Setting Up FreeBSD 14 VNET Jails with IPv6-Only Networking
I've been running FreeBSD jails for years, but when I discovered VNET jails with proper network isolation, my infrastructure game changed completely. The ability to give each service its own network stack with full firewall control is a game-changer for security and flexibility. Let me walk you through how I set up modern VNET jails with IPv6-only networking on FreeBSD 14.
What You'll Learn
This guide covers setting up FreeBSD 14 VNET jails with:
- Robust network isolation using
epairinterfaces andbridgenetworking - IPv6-only architecture for modern networking
- PF firewall integration at both host and jail levels
- Practical troubleshooting techniques
FreeBSD Jails offer lightweight virtualization with process and filesystem isolation. While traditional jails share the host's network stack, VNET jails get their own independent network environment. This setup gives you complete control over each jail's networking, including IP addresses, routing tables, and firewalls.
1. Preparing Your Host System
Before creating VNET jails, you need to configure your FreeBSD host properly.
1.1 Kernel Modules and rc.conf Configuration
First, let's load the necessary kernel modules and configure them to load automatically:
# Load modules immediately
kldload if_epair
kldload if_bridge
kldload pf
kldload pflog
# Add to /etc/rc.conf for persistent loading
echo 'if_epair_load="YES"' >> /etc/rc.conf
echo 'if_bridge_load="YES"' >> /etc/rc.conf
echo 'pf_enable="YES"' >> /etc/rc.conf
echo 'pflog_enable="YES"' >> /etc/rc.conf
Next, configure the bridge interface in /etc/rc.conf:
# /etc/rc.conf additions
cloned_interfaces="bridge0"
ifconfig_bridge0="inet6 -ifdisabled up" # IPv6-only bridge
ipv6_enable="YES"
ipv6_gateway_enable="YES"
rtsold_enable="YES" # If host needs to get IPv6 from upstream
rtadvd_enable="YES" # If host acts as a router for jails
1.2 sysctl Tunings
We need to adjust some sysctl parameters for proper networking:
# Enable IP forwarding for IPv4 and IPv6
sysctl net.inet.ip.forwarding=1
sysctl net.inet6.ip6.forwarding=1
# Configure bridge filtering
sysctl net.link.bridge.pfil_member=0
sysctl net.link.bridge.pfil_bridge=1
# Add to /etc/sysctl.conf for persistence
echo 'net.inet.ip.forwarding=1' >> /etc/sysctl.conf
echo 'net.inet6.ip6.forwarding=1' >> /etc/sysctl.conf
echo 'net.link.bridge.pfil_member=0' >> /etc/sysctl.conf
echo 'net.link.bridge.pfil_bridge=1' >> /etc/sysctl.conf
1.3 Basic Host pf.conf
Here's a basic PF configuration for the host:
# /etc/pf.conf on the host
ext_if = "vtnet0"
bridge_if = "bridge0"
jail_net = "2001:db8:jails::/64"
set skip on lo0
set skip on $bridge_if
scrub in on $ext_if all fragment reassemble
scrub out on $ext_if all fragment reassemble
# Default deny everything
block all
# Allow all outbound traffic from jails
pass out on $ext_if from $jail_net to any keep state
# Allow specific inbound traffic to jails
pass in on $ext_if proto tcp from any to $jail_net port { ssh, http, https } keep state
# Allow host to communicate with jails
pass in quick on $bridge_if from $jail_net to any keep state
pass out quick on $bridge_if from any to $jail_net keep state
# Basic host protection
pass in on $ext_if proto icmp6 from any to any icmp6-type { echoreq, routeradvert, routersol } keep state
pass out on $ext_if proto icmp6 from any to any icmp6-type { echoreq, routeradvert, routersol } keep state
pass in on $ext_if proto tcp from any to ($ext_if) port ssh keep state
After configuring, enable PF:
pfctl -e -f /etc/pf.conf
2. Creating VNET Jails with epair and bridge
Now let's create our first VNET jail with proper network isolation.
2.1 Understanding epair and bridge Interaction
An epair interface is a virtual network device that comes in pairs (epairXa and epairXb). Here's how it works with VNET jails:
-
epairXagoes into the jail's network stack -
epairXbstays on the host and connects to the bridge - The bridge acts as a virtual switch connecting all jail interfaces
2.2 jail.conf Structure for VNET Jails
Here's an example jail.conf entry for an IPv6-only VNET jail:
# /etc/jail.conf
vnet_base {
path = "/jails/basejail";
mount.devfs;
allow.raw_sockets;
exec.start = "/bin/sh /etc/rc";
exec.stop = "/bin/sh /etc/rc.shutdown";
}
vnet-jail-01 {
host.hostname = "vnet-jail-01";
path = "/jails/vnet-jail-01";
vnet;
vnet.interface = "epair0a";
# Commands executed on the host before jail starts
exec.prestart += "ifconfig epair0 create";
exec.prestart += "ifconfig bridge0 addm epair0b";
# Commands executed inside the jail after it starts
exec.start += "ifconfig epair0a up";
exec.start += "ifconfig epair0a inet6 accept_rtadv";
exec.start += "route add -inet6 default fe80::1%epair0a";
# Commands executed on the host after jail stops
exec.poststop += "ifconfig bridge0 deletem epair0b";
exec.poststop += "ifconfig epair0b destroy";
mount.devfs;
allow.raw_sockets;
exec.clean;
exec.consolelog = "/var/log/jail_vnet-jail-01_console.log";
exec.start = "/bin/sh /etc/rc";
exec.stop = "/bin/sh /etc/rc.shutdown";
}
To start the jail:
jail -c vnet-jail-01
To enter the jail's console:
jexec vnet-jail-01 /bin/csh
3. Configuring IPv6-Only Networking
An IPv6-only architecture simplifies network management and prepares your infrastructure for the future.
3.1 Host rtadvd Configuration
Configure the host to act as a router for the jails:
# /etc/rc.conf (ensure these are present)
ipv6_enable="YES"
ipv6_gateway_enable="YES"
rtadvd_enable="YES"
# /etc/rtadvd.conf
bridge0:\
:addrs#1:prefix:2001:db8:jails::/64:
Start the rtadvd service:
service rtadvd start
3.2 Jail rc.conf and DNS Configuration
Inside the jail, ensure IPv6 is enabled:
# /jails/vnet-jail-01/etc/rc.conf
ipv6_enable="YES"
rtsol_enable="YES"
Configure DNS in the jail:
# /jails/vnet-jail-01/etc/resolv.conf
nameserver 2001:4860:4860::8888
nameserver 2001:4860:4860::8844
3.3 Static IPv6 Addressing (Alternative)
For services needing stable addresses:
# In /etc/jail.conf for vnet-jail-01
# ...
exec.start += "ifconfig epair0a inet6 2001:db8:jails::10/64 up";
exec.start += "route add -inet6 default 2001:db8:jails::1";
# ...
4. Implementing PF Firewall for Enhanced Security
PF provides powerful firewall capabilities at both host and jail levels.
4.1 Host PF for VNET Jails
The host's PF controls traffic between external networks and the jail bridge:
# /etc/pf.conf (host)
# ...
# Define tags for specific jail services
pass in on $ext_if proto tcp from any to $jail_net port ssh tag SSH_JAIL
pass in on $ext_if proto tcp from any to $jail_net port http tag HTTP_JAIL
# Example: allow SSH to specific jail IP
pass in on $ext_if proto tcp from any to 2001:db8:jails::10 port ssh keep state tag SSH_JAIL_01
4.2 Jail-Specific PF Configuration
Each jail can run its own PF instance:
# /jails/vnet-jail-01/etc/pf.conf
int_if = "epair0a"
set skip on lo0
# Default deny all
block all
# Allow outbound connections
pass out on $int_if all keep state
# Allow inbound SSH
pass in on $int_if proto tcp from any to any port ssh keep state
# Allow ICMP6 for network diagnostics
pass in on $int_if proto icmp6 from any to any icmp6-type { echoreq, echorep, routersol, routeradvert, neighbrsol, neighbradvert } keep state
Enable PF in the jail's /etc/rc.conf:
pf_enable="YES"
pf_rules="/etc/pf.conf"
5. Advanced VNET Features and Troubleshooting
5.1 Multiple Bridges and VLANs
For more complex setups:
# /etc/rc.conf
cloned_interfaces="bridge0 bridge1"
ifconfig_bridge0="inet6 -ifdisabled up"
ifconfig_bridge1="inet6 -ifdisabled up"
5.2 Jail Management Tools
Consider using tools like:
- CBSD: Powerful framework for managing jails, bhyve, and other virtual environments
- Pot: Lightweight ZFS-based jail manager focused on immutable infrastructure
5.3 Monitoring and Troubleshooting
Key commands for debugging:
-
ifconfig -a(host and jail) -
netstat -rn(host and jail) -
pfctl -sr,pfctl -sa(host and jail) tcpdump -i <interface>-
dmesg,/var/log/messages, jail console logs
Final Thoughts
Setting up VNET jails with proper network isolation gives you incredible flexibility and security for your FreeBSD infrastructure. The IPv6-only approach simplifies configuration while preparing your systems for the future.
Have you tried setting up VNET jails before? What challenges did you face? I'd love to hear about your experiences in the comments below!
Originally published on synthetic-context.net
Top comments (0)