Podman Networking: Netavark, DNS and Network Modes Explained

Tested on Red Hat Enterprise Linux 10.2 (Coughlan)
Package podman-5.8.2-5.el10_2.x86_64
netavark-1.17.2-1.el10.x86_64
aardvark-dns-1.17.1-1.el10_2.x86_64
Applies to Any Linux host with Podman installed
Privilege Rootful examples as root; rootless examples as an unprivileged user
Scope Podman networking architecture — Netavark, Aardvark DNS, rootful vs rootless defaults, and --network modes (bridge, host, none, pasta, private, container:, ns:). Does not cover podman network create options, port publishing syntax, DNS troubleshooting, pasta tuning, or host-access debugging.
Related guides Run containers with podman run

Podman containers do not share one generic network stack. Rootful workloads usually ride a Linux bridge managed by Netavark; rootless workloads default to pasta. The --network flag picks which path a specific container uses. This guide maps the architecture, shows what each mode looks like on the lab host, and helps you choose the right default before you open the network-management or port-mapping articles.


How Podman networking works

For normal rootful bridge networking, traffic flows like this:

text
Container
   │ veth
Linux bridge (podman0)
Netavark
   ├── addresses and routes
   ├── firewall and NAT
   └── port forwarding
Host network

When DNS is enabled on a user-defined bridge network, name queries go through Aardvark DNS:

text
Container
Aardvark DNS
   ├── container names and aliases
   └── forwards external queries upstream

Rootless Podman defaults to pasta instead of a kernel bridge:

text
Rootless container
    pasta
Host network connectivity

Netavark still owns network configuration even when pasta carries the data path. Aardvark DNS answers names only on networks where DNS is enabled — not on every attachment by default.


What is Netavark?

Netavark is Podman's modern network configuration backend. It creates container interfaces, assigns addresses and routes, configures firewall and NAT rules for bridge networks, and integrates with Aardvark DNS for local name resolution. It replaces the older CNI-based networking path on current installations.

Confirm the active backend:

bash
podman info --format 'NetworkBackend={{.Host.NetworkBackend}}'
output
NetworkBackend=netavark

The full podman info output on the lab host also reports package versions — filter the network block:

bash
podman info 2>&1 | sed -n '/networkBackendInfo:/,/version: netavark/p'
output
networkBackendInfo:
    backend: netavark
    defaultNetwork: podman
    dns:
      package: aardvark-dns-1.17.1-1.el10_2.x86_64
      path: /usr/libexec/podman/aardvark-dns
      version: aardvark-dns 1.17.1
    package: netavark-1.17.2-1.el10.x86_64
    path: /usr/libexec/podman/netavark
    version: netavark 1.17.2

Netavark configures networking; it is not something you tune in day-to-day container runs unless you are changing networks or firewall integration.


What happened to CNI networking?

Podman 5.x

Podman 5.x still contains legacy CNI compatibility in code and documentation, but modern installations normally use Netavark. Do not write that CNI does not exist in Podman 5 — instead verify your host:

bash
podman info --format 'NetworkBackend={{.Host.NetworkBackend}}'

If the output is netavark, you are on the current path. Legacy CNI configuration may still appear on older or heavily customized hosts.

Podman 6 and later

Podman 6 removes CNI support completely. The split looks like this:

text
Podman 5.x
    → Netavark normally
    → legacy CNI may still exist

Podman 6+
    → Netavark only

This article focuses on Netavark-era networking. CNI migration belongs in the Podman 5 to 6 migration guide, not here.


Rootful vs rootless Podman networking

Rootful Podman Rootless Podman
bridge is the default pasta is the default
kernel bridge and veth user-mode pasta by default
Netavark configures bridge networking pasta handles default rootless connectivity
normal firewall and NAT integration no root privileges required
can use macvlan and ipvlan macvlan and ipvlan cannot use host interfaces rootless
can bind privileged ports directly ports below 1024 need separate handling

Rootless users are not limited to pasta only. On Podman 5.x you can create and attach rootless Netavark bridge networks — the lab user podnet received eth0 at 10.89.0.2/24 on a user-defined bridge. The distinction is default behavior: pasta is the rootless default; explicit bridge networks are also available. See Rootless Podman networking for pasta options and port forwarding.


Podman --network modes at a glance

Mode What it does
bridge connects through Podman's default bridge network
network name attaches to a user-created Podman network
pasta rootless user-mode networking
host shares the host network namespace
none isolated namespace without external connectivity
container:ID shares another container's network namespace
ns:PATH joins an existing Linux network namespace
private explicitly create a new namespace using bridge rootful or pasta rootless

The sections below demonstrate the modes that matter for everyday decisions.


Bridge networking

Rootful Podman attaches containers to the default podman bridge unless you specify another network:

bash
podman run --rm --network bridge docker.io/library/alpine:3.20 ip addr show eth0
output
2: eth0@if856: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP qlen 1000
    link/ether 3e:bb:88:63:5c:85 brd ff:ff:ff:ff:ff:ff
    inet 10.88.2.107/16 brd 10.88.255.255 scope global eth0

The container gets its own network namespace, an address on the 10.88.0.0/16 subnet, and a default route through the bridge gateway:

bash
podman run --rm --network bridge docker.io/library/alpine:3.20 ip route
output
default via 10.88.0.1 dev eth0  metric 100
10.88.0.0/16 dev eth0 scope link  src 10.88.2.108

Inspect the bridge Netavark manages:

bash
podman network inspect podman

The lab host shows network_interface: podman0, subnet 10.88.0.0/16, and dns_enabled: false on the built-in network. Outbound traffic is NATed through Netavark's firewall integration; published ports use Netavark forwarding rules. Creating custom bridges is covered in Create and manage Podman networks.


User-defined Podman networks

Application stacks often need a dedicated network scope:

bash
podman network create app-network

Run a container on that network to confirm it receives an address:

bash
podman run --rm --network app-network docker.io/library/alpine:3.20 ip addr show eth0

User-defined bridge networks give you:

  • separate subnet and gateway per network
  • predictable grouping of related containers
  • DNS and aliases when DNSEnabled is true
  • multiple network attachments per container

Check DNS state rather than assuming it is on:

bash
podman network inspect app-network --format 'DNSEnabled={{.DNSEnabled}}'
output
DNSEnabled=true

Compare with the built-in podman network:

bash
podman network inspect podman --format 'DNSEnabled={{.DNSEnabled}}'
output
DNSEnabled=false

Network create options, macvlan, and ipvlan belong in the network-management article.


--network=host

Host mode drops network isolation — the container uses the host's network namespace:

bash
podman run --rm --network host docker.io/library/alpine:3.20 ip addr show lo
output
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
    inet 127.0.0.1/8 scope host lo

Services bound to 127.0.0.1 on the host are reachable from the container at the same address. Port mapping with -p is unnecessary because there is no separate namespace to forward into — and on host networking it has no effect. Host mode trades isolation for simplicity when a container must behave like a host process.


--network=none

none creates a network namespace with loopback only:

bash
podman run --rm --network none docker.io/library/alpine:3.20 ip addr
output
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
    inet 127.0.0.1/8 scope host lo

No external interface or default route exists. Outbound access fails:

bash
podman run --rm --network none docker.io/library/alpine:3.20 wget -q -O- --timeout=2 http://example.com
output
wget: bad address 'example.com'

Use none for intentionally offline workloads, isolation testing, or jobs that never need network access. This is not the same as private, which still provides connectivity through a fresh namespace.


--network=container:ID

Two containers can share one network namespace. Start a long-running container:

bash
podman run -d --name net-demo-primary docker.io/library/alpine:3.20 sleep 600

Attach a second container to the first container's namespace:

bash
podman run --rm --network container:net-demo-primary docker.io/library/alpine:3.20 ip -4 addr show eth0 | grep inet
output
inet 10.88.2.112/16 brd 10.88.255.255 scope global eth0

The primary container reports the same address — both see one eth0 and can reach services on localhost in the shared namespace. This resembles one aspect of pod networking; see Podman pod networking for pod-level ports and DNS.

Remove the primary container when finished:

bash
podman rm -f net-demo-primary

--network=ns:PATH

Join an existing Linux network namespace by path:

bash
podman run --network ns:/run/netns/example docker.io/library/alpine:3.20 ip addr

Replace /run/netns/example with a namespace your platform already created — for example one set up by ip netns or another orchestrator. This is advanced usage for integrating Podman with existing network namespaces; it is not the normal application deployment path.


--network=private

private creates a new network namespace using the default mechanism for your privilege mode:

text
rootful private  → bridge-based private networking
rootless private → pasta-based private networking

Rootful private on the lab host still receives a bridge eth0 and can reach the internet:

bash
podman run --rm --network private docker.io/library/alpine:3.20 ip addr show eth0
output
2: eth0@if861: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP qlen 1000
    inet 10.88.2.110/16 brd 10.88.255.255 scope global eth0

private explicitly requests a new network namespace using Podman's privilege-specific default networking implementation: bridge for rootful containers and pasta for rootless containers. It still provides network connectivity; use none when you want only loopback.


Rootless --network=pasta

Pasta is the default rootless network stack from Podman 5.0 onward. It copies host interface addressing and routes into the container namespace without root privileges:

bash
podman run --rm docker.io/library/alpine:3.20 ip addr show enp0s3

As rootless user podnet, the container sees the host's enp0s3 interface and address:

output
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 65520 qdisc fq_codel state UNKNOWN qlen 1000
    inet 10.0.2.15/24 brd 10.0.2.255 scope global noprefixroute enp0s3

Explicit pasta mode behaves the same way on this host. Pasta handles published-port forwarding and can preserve source IP compared with older slirp stacks. Option tuning and port-forward behavior belong in Rootless Podman networking.

Rootless bridge networks remain available when you need a traditional eth0 on an isolated subnet:

bash
podman network create rl-bridge

Attach a container to the rootless bridge:

bash
podman run --rm --network rl-bridge docker.io/library/alpine:3.20 ip addr show eth0
output
2: eth0@if4: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 65520 qdisc noqueue state UP qlen 1000
    inet 10.89.0.2/24 brd 10.89.0.255 scope global eth0

Connect a container to multiple networks

A container can attach to more than one network:

bash
podman network create app-frontend

Create a second network for backend services:

bash
podman network create app-backend

Start one container attached to both:

bash
podman run -d --name multi-net-demo --network app-frontend --network app-backend docker.io/library/alpine:3.20 sleep 600

Inspect the attachments:

bash
podman inspect multi-net-demo --format '{{json .NetworkSettings.Networks}}'

The lab container received separate interfaces and addresses on each network — 10.89.5.2 on app-frontend and 10.89.6.2 on app-backend. Each attachment can carry its own aliases and routing implications. Static addresses and alias syntax belong in the network-management guide.

Clean up when done:

bash
podman rm -f multi-net-demo

Remove the networks when they are no longer needed:

bash
podman network rm app-frontend app-backend

How Podman DNS fits into networking

On DNS-enabled bridge networks, resolution flows through Aardvark DNS:

text
container query
Aardvark DNS
     ├── container name or alias → local answer
     └── external name         → upstream resolver

Not every network enables DNS. The built-in podman network on Podman 5.8 has dns_enabled: false, while user-created bridges default to DNS on unless you pass --disable-dns. Always check:

bash
podman network inspect NETWORK --format 'DNSEnabled={{.DNSEnabled}}'

Container name resolution, search domains, and --dns overrides are covered in Podman DNS and name resolution.


How Podman firewall and NAT integration works

For managed rootful bridge networks, Netavark configures:

  • bridge interfaces and veth pairs
  • forwarding and masquerading for outbound traffic
  • port-forwarding rules for published ports

The exact firewall backend depends on host configuration — nftables, iptables on Podman 5-era installs, or firewalld integration. Netavark 2, required with Podman 6, removes Netavark's iptables firewall-driver support.

Do not hard-code one firewall tool in your runbooks. Confirm connectivity after host firewall changes.


What happens after firewall-cmd --reload?

Rootful Podman depends on Netavark-managed firewall rules. If firewall-cmd --reload removes those rules, running containers may lose outbound connectivity even though their interfaces still look healthy.

Recovery:

bash
podman network reload CONTAINER

Or reload every attachment:

bash
podman network reload --all

The full DNS-versus-routing-versus-firewall workflow belongs in a dedicated no-internet troubleshooting article.


Podman 5 vs Podman 6 networking changes

Podman 5.x Podman 6+
Netavark is modern default backend Netavark required
legacy CNI may still exist CNI removed
pasta default rootless from 5.0 pasta only supported rootless stack
slirp4netns still available slirp4netns removed
older Netavark network isolation defaults Netavark 2 strict bridge isolation by default
Netavark 1.x may use its older iptables firewall backend Netavark 2 removes its iptables firewall backend

These Podman 6 rows describe the major upgrade — do not assume Netavark 2 isolation defaults apply to the Podman 5.8.2 lab host in this article.


Which Podman network mode should you use?

Requirement Start with
normal rootful container bridge
normal rootless container pasta (default)
multi-container app with names and DNS user-defined bridge network
no network at all none
share another container's namespace container:ID
use host networking directly host
join a pre-existing Linux namespace ns:PATH
explicit fresh private namespace private

When in doubt, run podman info to confirm the backend and default network, then inspect the specific network's DNS and subnet settings before relying on name resolution or fixed addresses.


References


Summary

Modern Podman networking runs through Netavark with Aardvark DNS for name resolution on DNS-enabled networks. On the lab host, podman info reports NetworkBackend=netavark with netavark 1.17.2 and aardvark-dns 1.17.1. Rootful containers default to bridge mode on the podman0 network at 10.88.0.0/16; rootless containers default to pasta and see host interfaces such as enp0s3 at the host address, though rootless bridge networks remain available when you need a separate eth0 subnet.

The --network flag selects among bridge, host, none, pasta, private, shared container namespaces, and external namespace paths. none isolates completely; private creates a fresh connected namespace; host removes isolation entirely. DNS is not universal — the built-in podman network ships with DNS disabled while user-created bridges enable it by default on Podman 5.8.

For creating networks, publishing ports, pasta tuning, and connectivity troubleshooting, follow the dedicated guides linked above. Start with the mode table in this article, confirm settings with podman info and podman network inspect, and only then dive into network create or port-mapping syntax.


Frequently Asked Questions

1. What is the default Podman network mode?

Rootful Podman defaults to bridge networking through the podman bridge network. Rootless Podman defaults to pasta, which by default copies addressing and routes from the host's selected network interface into the container namespace without root privileges. Both paths use Netavark as the network backend on current Podman 5.x releases.

2. Does Podman still use CNI for networking?

Netavark is the modern default on Podman 5.x, but legacy CNI configuration may still exist on older installations. Podman 6 removes CNI support entirely and requires Netavark. Run podman info and check NetworkBackend rather than assuming either backend.

3. What is the difference between --network=none and --network=private?

none creates an isolated network namespace with only loopback and no external connectivity. private creates a fresh network namespace using the default mechanism for your privilege mode — bridge-based for rootful Podman and pasta-based for rootless. private still provides outbound connectivity; none does not.

4. Does every Podman network have DNS enabled?

No. On Podman 5.8 the built-in podman bridge network has DNS disabled. User-created bridge networks enable DNS by default unless you pass --disable-dns. Check podman network inspect and the DNSEnabled field instead of assuming name resolution works.

5. What happens to Podman networking after firewall-cmd --reload?

A firewall reload can remove Netavark-managed NAT and forwarding rules. Containers may lose outbound connectivity until you run podman network reload on affected containers or podman network reload --all. Full troubleshooting belongs in a dedicated no-internet guide.
Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive experience, he excels across development, DevOps, networking, and security, delivering robust and efficient solutions for diverse projects.

  • Go (programming language)
  • Python (programming language)
  • DevOps
  • Computer Security
  • Cloud Computing
  • Kubernetes
  • Linux
  • Ansible (software)