Skip to content

Networking

FreeBSD Podman containers support several networking modes. Understanding which one to use is critical for connectivity and performance.

Bridge Networking (Default)

The container gets its own IP address on a virtual network (usually 10.88.0.0/16).

Port Forwarding

podman run -d -p 7878:7878 --name radarr ghcr.io/daemonless/radarr:latest

Maps container port to host port. Requires pf configuration.

Multiple Ports

1
2
3
4
5
podman run -d \
  -p 80:80 \
  -p 443:443 \
  -p 8080:8080 \
  --name traefik ghcr.io/daemonless/traefik:latest

pf.conf Setup

Add to /etc/pf.conf:

1
2
3
4
5
6
# Podman container networking
rdr-anchor "cni-rdr/*"
nat-anchor "cni-rdr/*"
table <cni-nat>
nat on $ext_if inet from <cni-nat> to any -> ($ext_if)
nat on $ext_if inet from 10.88.0.0/16 to any -> ($ext_if)

Enable local filtering:

1
2
3
4
5
echo 'pf_load="YES"' >> /boot/loader.conf
sysctl net.pf.filter_local=1
echo 'net.pf.filter_local=1' >> /etc/sysctl.conf
sysrc pf_enable=YES
service pf restart

pf only reads net.pf.filter_local when it is enabled, and /etc/sysctl.conf is applied before kld_list loads modules. Load pf from /boot/loader.conf so the setting takes effect at boot; otherwise the host cannot reach its own containers on localhost after a reboot.

sysctl net.pf.filter_local can read 1 while pf is still ignoring it. It is active when pfilctl heads lists pf:default-out under inet-local.

Containers already running

service pf restart empties the <cni-nat> table, so containers on Compose networks lose outbound access until they are restarted. To apply net.pf.filter_local=1 without that, run pfctl -d; pfctl -e.

Host Networking

The container shares the host's network stack directly. No separate IP address.

podman run -d --network=host --name unifi ghcr.io/daemonless/unifi:latest

Use Cases

  • Applications needing L2 network discovery (UniFi adopting APs, SmokePing)
  • Avoiding NAT overhead
  • Simpler setup without pf configuration

Note

Port mapping (-p) has no effect in host mode; the application listens on the host IP directly.

Pros Cons
Simpler setup Less isolation
No pf config needed Port conflicts possible
Better performance Container sees all host interfaces

VNET (Virtual Network Stack)

VNET provides a private, isolated network stack for the jail.

1
2
3
podman run -d --name gitea \
  --annotation 'org.freebsd.jail.vnet=new' \
  ghcr.io/daemonless/gitea:latest

Use Cases

  • Applications managing their own network interfaces or routing (WireGuard, Gitea)
  • Higher isolation than bridge mode

Limitations

  • Port Forwarding: Standard -p mapping not supported by stock ocijail with VNET. Access via container's internal IP.
  • Kernel Support: Requires VNET support (default in FreeBSD 13+).

Container-to-Container Communication

Multi-container apps (like Immich) need services to find each other. FreeBSD has some limitations here compared to Linux.

Option 1: Host Networking

All containers share the host network and communicate via localhost. Simple, but every service binds host ports; with cni-dnsname packaged (Option 2), names on a bridge are the better default:

1
2
3
4
5
6
services:
  app:
    network_mode: host
    environment:
      - DB_HOSTNAME=localhost
      - REDIS_HOSTNAME=localhost
Pros Cons
No extra setup Port conflicts possible
Works out of the box Less isolation
Matches Linux behavior Services bind to host ports

The cni-dnsname plugin enables containers to resolve each other by name (e.g., postgres, redis). This is required for multi-container apps like Immich and Mealie when using podman-compose.

Installation

cni-dnsname is in the official FreeBSD ports tree as sysutils/cni-dnsname:

pkg install cni-dnsname

Verify Installation

ls /usr/local/libexec/cni/dnsname
# Should exist

With cni-dnsname installed, containers can resolve each other by name:

1
2
3
# From inside one container, reach another by name
ping immich_postgres
fetch -o - http://immich_server:2283

Option 3: Static IPs

Look up or assign container IPs and use them directly:

podman inspect -f '{{.NetworkSettings.IPAddress}}' radarr

Or create a network with static IPs in your compose file. More complex but avoids both host networking and dnsname.

An Address on Your LAN

For apps that need to be seen on the LAN directly (UniFi adopting devices, Home Assistant discovery, mDNS), a container can get its own address on your network, by DHCP or a fixed one, through the cni-epair plugin (pkg install cni-epair). The image must include dhclient for DHCP. fjord's networking guide walks through it, and fjord sets it up for you.

Comparison Summary

Feature Bridge (Default) Host VNET
IP Address Private (10.88.x.x) Shared with Host Private (10.88.x.x)
Port Mapping Supported (-p) Not needed Not supported
Isolation High Low Very High
Best For Most Apps Network Discovery VPNs / High Isolation
pf Required Yes No Yes