Create and Manage Podman Networks with `podman network`

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; macvlan and ipvlan require root
Scope Creating and managing persistent Podman network objects — podman network create, ls, inspect, connect, disconnect, rm, prune, subnet and gateway options, internal and IPv6 bridges, routes, DNS flags, macvlan, ipvlan, and podman network reload. Does not cover port publishing, DNS troubleshooting, pasta tuning, or firewall administration.
Related guides Podman pod networking
Run containers with podman run

podman network create builds a reusable network object that containers attach to at run time or later with podman network connect. This guide walks through listing, inspecting, customizing, and cleaning up those networks on Podman 5.8 with Netavark. If you need the big picture on bridge versus pasta versus host mode, read Podman networking modes first — here the focus stays on managing network resources themselves.

The lab image is docker.io/library/alpine:3.20. Most examples reuse one bridge network named podman-network-demo.


Create a Podman network

Start with a default bridge network. Podman picks the driver, subnet, and host-side interface name for you:

bash
podman network create podman-network-demo

Sample output:

output
podman-network-demo

Podman prints the network name on success. Confirm it exists:

bash
podman network ls

Sample output:

output
NETWORK ID    NAME                 DRIVER
ece90e607d27  podman-network-demo  bridge

On Podman 5.8 with Netavark, a user-defined bridge network behaves like this:

  • Driver defaults to bridge
  • Podman allocates a free subnet from the Netavark pool (for example 10.89.5.0/24)
  • The object is persistent until you remove it with podman network rm

Inspect the full definition:

bash
podman network inspect podman-network-demo

Sample output (trimmed):

output
[
     {
          "name": "podman-network-demo",
          "id": "ece90e607d271ea0810c2f4daa2543d9f11161b96580602cc7771b6f207693eb",
          "driver": "bridge",
          "network_interface": "podman6",
          "subnets": [
               {
                    "subnet": "10.89.5.0/24",
                    "gateway": "10.89.5.1"
               }
          ],
          "ipv6_enabled": false,
          "internal": false,
          "dns_enabled": true,
          "ipam_options": {
               "driver": "host-local"
          },
          "containers": {}
     }
]

network_interface is the bridge device on the host (podman6 here). containers lists endpoints currently attached — empty until you run a container on this network.


List Podman networks

podman network ls is the quick inventory of custom networks plus the built-in podman bridge:

bash
podman network ls

Use filters when the list grows. Driver filter:

bash
podman network ls --filter driver=bridge

Name substring filter:

bash
podman network ls --filter name=demo

Label filter (create labeled networks with --label key=value):

bash
podman network create --label environment=test podman-label-demo

List only networks that carry the label:

bash
podman network ls --filter label=environment=test

Sample output:

output
NETWORK ID    NAME               DRIVER
651838b55148  podman-label-demo  bridge

For a compact table without learning every Go template field, --format accepts a few useful columns:

bash
podman network ls --format 'table {{.Name}}\t{{.Driver}}\t{{.NetworkInterface}}'

Sample output:

output
NAME                 DRIVER      NETWORK INTERFACE
podman-network-demo  bridge      podman6
podman-label-demo    bridge      podman7

That is enough for day-to-day checks. Reserve deeper template work for one-off scripting, not as a tutorial goal.


Inspect a Podman network

Full JSON from podman network inspect is the source of truth when something misbehaves. The fields you reach for most often:

  • name and id — human name and stable ID
  • driverbridge, macvlan, or ipvlan
  • network_interface — host bridge or parent NIC
  • subnets — CIDR, gateway, and optional lease_range
  • ipv6_enabled and internal — dual-stack and isolation flags
  • dns_enabled — whether Aardvark serves names on this network
  • ipam_options — IPAM driver (host-local, dhcp, …)
  • routes — static routes pushed into attached containers
  • containers — connected endpoints

Pull single fields with --format when you are scripting checks:

bash
podman network inspect --format '{{.DNSEnabled}}' podman-network-demo

Sample output:

output
true

Subnet and gateway use the Subnets slice (capital S in the Go template):

bash
podman network inspect --format '{{(index .Subnets 0).Subnet}}' podman-network-demo

Sample output:

output
10.89.5.0/24

The gateway is the bridge address containers use as their default next hop on that subnet:

bash
podman network inspect --format '{{(index .Subnets 0).Gateway}}' podman-network-demo

Sample output:

output
10.89.5.1

Those three commands are handy in troubleshooting scripts: DNS on or off, subnet in use, gateway Podman assigned.


Create a network with a custom subnet

Pass --subnet when the automatic pool does not fit your address plan:

bash
podman network create --subnet 10.20.0.0/24 podman-custom-subnet

Sample output:

output
podman-custom-subnet

Verify the CIDR stuck:

bash
podman network inspect --format '{{(index .Subnets 0).Subnet}} {{(index .Subnets 0).Gateway}}' podman-custom-subnet

Sample output:

output
10.20.0.0/24 10.20.0.1

Pick a subnet that does not overlap the host LAN or another Podman network. When you omit --subnet, Podman keeps choosing unused ranges from its pool.


Set a custom gateway

A custom gateway must sit inside the subnet you declare:

bash
podman network create --subnet 10.21.0.0/24 --gateway 10.21.0.1 podman-custom-gateway

Sample output:

output
podman-custom-gateway

If you pass multiple --subnet and --gateway pairs (for example dual-stack later), match them in order — first gateway belongs to the first subnet. Podman rejects a gateway outside its subnet.


Restrict container IP allocation with --ip-range

--ip-range limits automatic assignments while the network keeps the wider subnet:

bash
podman network create --subnet 10.22.0.0/24 --ip-range 10.22.0.128/25 podman-ip-range

Inspect shows the lease window under lease_range:

output
'subnet': '10.22.0.0/24', 'gateway': '10.22.0.1', 'lease_range': {'start_ip': '10.22.0.129', 'end_ip': '10.22.0.254'}

Containers still route within 10.22.0.0/24, but automatic allocation uses 10.22.0.129 through 10.22.0.254. Reserve the lower half for static assignments or external gear.


Connect a container to a user-defined network

Attach at create time with --network:

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

Sample output:

output
1bd7f5a227652561e623bb343b0fc0dfbc5e2015cda8d0d56e5e662768bbba8c

Check the address inside the container namespace:

bash
podman exec network-demo ip addr show eth0

Sample output:

output
inet 10.89.5.3/24 brd 10.89.5.255 scope global eth0

Podman-side attachment metadata lives under NetworkSettings.Networks:

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

Sample output (trimmed):

output
{"podman-network-demo":{"Gateway":"10.89.5.1","IPAddress":"10.89.5.3","IPPrefixLen":24,"MacAddress":"52:b4:1c:40:4c:7b",...}}

You can also attach an existing container later — covered in the next section.


Connect an existing container to another network

Create a second network, then plug the running container into it:

bash
podman network create second-network

Attach the running container without stopping it:

bash
podman network connect second-network network-demo

podman network connect exits silently on success. List both attachments:

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

Sample output (trimmed):

output
{
    "podman-network-demo": {
        "Gateway": "10.89.0.1",
        "IPAddress": "10.89.0.2",
        ...
    },
    "second-network": {
        "Gateway": "10.89.1.1",
        "IPAddress": "10.89.1.2",
        ...
    }
}

Each network adds its own interface (eth0, eth1, …) and IP. The container never restarted.

Network-scoped DNS aliases are useful when a service should answer to a stable name on one network only:

bash
podman run -d --name database-container --network podman-network-demo docker.io/library/alpine:3.20 sleep 600

Add a DNS alias on the second network only:

bash
podman network connect --alias database second-network database-container

Other containers on second-network can resolve database through Aardvark. Full resolution behavior belongs in Podman DNS and name resolution.


Disconnect a container from a network

Remove one attachment while the container keeps running:

bash
podman network disconnect second-network network-demo

The command prints nothing when it succeeds. Only second-network is removed; podman-network-demo stays connected.

If Podman reports the container is not attached, double-check the network name. For stuck endpoints during cleanup, podman network disconnect --force exists, but treat force as troubleshooting — disconnect normally first.


Create an internal Podman network

Internal bridges isolate workloads from the wider network while keeping east-west traffic inside the bridge:

bash
podman network create --internal podman-internal

Run two containers and confirm they reach each other:

bash
podman run -d --name int-a --network podman-internal docker.io/library/alpine:3.20 sleep 600

From a second container on the same bridge, ping by name:

bash
podman run --rm --network podman-internal docker.io/library/alpine:3.20 ping -c 1 int-a

Sample output:

output
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.266/0.266/0.266 ms

Inside an internal network container, routing tells the story:

bash
podman exec int-a ip route

Sample output:

output
10.89.8.0/24 dev eth0 scope link  src 10.89.8.2

There is no default route. Outbound traffic beyond the bridge fails:

bash
podman exec int-a ping -c 1 -W 2 8.8.8.8

Sample output:

output
ping: sendto: Network unreachable

On Netavark internal bridges:

  • No default route is injected
  • External forwarding is disabled for that bridge
  • Aardvark still resolves container names on the same network
  • General Internet DNS names are not the goal here — external lookup is blocked with the route, not merely “no Internet” in a vague sense

Container-to-container traffic and name resolution on the internal bridge still work.


Create an IPv6 Podman network

Enable IPv6 on a new bridge:

bash
podman network create --ipv6 podman-ipv6

Inspect shows both address families when Podman allocates them:

output
10.89.9.0/24 fd41:428:bc84:c9c3::/64

For explicit dual-stack CIDRs, pass subnets and gateways in matching order:

bash
podman network create --subnet 10.23.0.0/24 --subnet fd00:23::/64 --gateway 10.23.0.1 --gateway fd00:23::1 podman-dual-stack

Verify IPv6 inside a container:

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

Sample output:

output
inet6 fd00:23::2/64 scope global
    inet6 fe80::18d5:8cff:fe35:7d54/64 scope link

That is enough to confirm Podman handed out the ULA range you declared. Full IPv6 administration is out of scope.


Add static routes to a Podman network

Push routes into every container attached to the network with --route destination,gateway:

bash
podman network create --subnet 10.24.0.0/24 --route 172.20.0.0/16,10.24.0.254 podman-routed

Inspect the routes field:

output
[{"destination":"172.20.0.0/16","gateway":"10.24.0.254"}]

Containers inherit that route in their network namespace. The lab does not reach a real 172.20.0.0/16 target, so treat this as syntax you verify in inspect — prove reachability only when your topology has a gateway that forwards there.


Disable the default route

On Netavark 1.x with Podman 5.8, disable the default route with the bridge option no_default_route=true:

bash
podman network create --subnet 10.25.0.0/24 --opt no_default_route=true podman-no-default-route

Older docs sometimes show no_default_route=1; the tested binary accepts true. Check inside a container:

bash
podman run --rm --network podman-no-default-route docker.io/library/alpine:3.20 ip route

Sample output:

output
10.25.0.0/24 dev eth0 scope link  src 10.25.0.2

Only the connected subnet appears — no default via line. Combine with explicit --route entries when containers need selective upstream paths instead of a full default route.


Enable or disable network DNS

New user-defined bridge networks enable Aardvark DNS by default. Confirm:

bash
podman network inspect --format '{{.DNSEnabled}}' podman-network-demo

Sample output:

output
true

Turn off container-name DNS for a network:

bash
podman network create --disable-dns podman-no-dns

Confirm DNS is off for that object:

bash
podman network inspect --format '{{.DNSEnabled}}' podman-no-dns

Sample output:

output
false

--disable-dns stops Podman’s name plugin on that bridge. Containers may still use upstream resolvers from /etc/resolv.conf for external names. Debugging resolution belongs in Podman DNS and name resolution.


Configure network-scoped DNS forwarders

When your Podman build supports network-level forwarders, pass --dns:

bash
podman network create --dns 10.0.0.53 podman-custom-dns

Inspect shows the upstream list:

output
dns_enabled= True
network_dns_servers= ['10.0.0.53']

Aardvark answers container-name queries locally and forwards other queries to network_dns_servers. Container-level --dns flags are a separate topic.


Create a macvlan network

Macvlan attaches containers directly to a host interface. Find the real parent name first — do not assume eth0:

bash
ip route show default

On the lab VM the default route uses enp0s3. Create the network as root:

bash
sudo podman network create --driver macvlan --opt parent=enp0s3 podman-macvlan

Inspect ties the parent to network_interface:

output
"driver": "macvlan",
"network_interface": "enp0s3",
"ipam_options": { "driver": "dhcp" }

Keep these constraints in mind:

  • Each container gets its own MAC on the LAN segment
  • A real host interface is required — rootless Podman networking cannot create macvlan parents
  • Podman port forwarding (-p) is not supported on macvlan networks
  • Host-to-container traffic on the same parent has Linux macvlan quirks; do not assume the host can always ping a macvlan child without extra setup

Create an ipvlan network

IPvlan shares the parent MAC differently. The same parent discovery applies:

bash
ip link show enp0s3

A plain create often fails because dhcp IPAM is incompatible:

bash
sudo podman network create --driver ipvlan --opt parent=enp0s3 podman-ipvlan

Sample output:

output
Error: ipam driver dhcp is not supported with ipvlan

Fix it with host-local IPAM and an explicit subnet. Use a CIDR that fits your LAN — the lab uses the host-only segment:

bash
sudo podman network create --driver ipvlan --opt parent=enp0s3 --ipam-driver=host-local --subnet 192.168.56.0/24 podman-ipvlan

Do not use -o ipam_driver=host-local; the CLI flag is --ipam-driver.

IPvlan modes (l2, l3, l3s) map to --opt mode=… when you need them. Like macvlan, ipvlan requires root and does not support Podman port publishing.


Macvlan vs ipvlan

Topic Macvlan IPvlan
L2 identity Separate MAC per container Shares parent MAC behavior
Modes Layer-2 oriented l2, l3, l3s
Privilege Root required for parent NIC Root required
Port publishing Not supported Not supported
Typical use Containers visible as distinct LAN hosts Better when MAC tables are tight or policies limit MAC count

Pick macvlan when each container should look like its own NIC on the wire. Pick ipvlan when MAC scaling or switch policy makes shared-MAC modes attractive.


Podman 6 and Netavark 2 network isolation

IMPORTANT
The behavior below applies to Podman 6 with Netavark 2. The lab runs Podman 5.8.2 / Netavark 1.17.2, where bridge isolation is not strict by default.

On Podman 5.x, the isolate bridge option exists, but traffic between separate user-defined bridge networks is not automatically blocked. Do not assume strict isolation on Podman 5 without checking your rules and routes.

Podman 6 / Netavark 2 changes the default for new bridge networks to isolate=strict, which blocks traffic to and from other Podman bridge networks unless you opt out:

bash
podman network create --opt isolate=false mynetwork

Supported isolate values on Podman 6:

  • strict — default; block traffic to and from all other Podman bridge networks
  • true — isolate from other networks that also have isolation enabled (true or strict)
  • false — allow traffic to other bridge networks, restoring the pre-Podman-6 behavior

Plan upgrades carefully if workloads relied on cross-bridge chatter on the same host.


Reload Podman network configuration

Rootful bridge connectivity depends on Netavark-managed firewall rules. After sudo firewall-cmd --reload, those rules can disappear while containers keep running. Symptom: outbound traffic dies until you refresh networking.

Reload one container’s firewall integration:

bash
podman network reload network-demo

Refresh every running container at once:

bash
podman network reload --all

On success, Podman prints the IDs of the containers whose network configuration was reloaded. If reload does not help, walk through Podman container has no Internet for broader diagnosis.


Remove a Podman network

Delete an unused network by name:

bash
podman network rm podman-custom-subnet

If containers remain attached, Podman blocks the delete:

output
Error: "podman-network-demo" has associated containers with it. Use -f to forcibly delete containers and pods: network is being used

Clean up in order:

  1. podman network disconnect NETWORK CONTAINER (or podman rm the container)
  2. podman network rm NETWORK

podman network rm -f force-removes attached containers and pods along with the network. Reserve -f for deliberate teardown, not routine maintenance.


Prune unused Podman networks

Remove every custom network with no endpoints:

bash
podman network prune

Sample output:

output
podman-custom-gateway
podman-custom-subnet
second-network

Podman lists each deleted name. Add -f to skip the confirmation prompt in scripts.

When your build supports time filters, prune old unused networks:

bash
podman network prune --filter until=24h -f

Only unused user-defined networks are candidates. The built-in podman network and networks still referenced by containers remain. This is narrower than podman system prune.


Troubleshooting

Symptom Likely cause Fix
network is being used on podman network rm Containers still connected Disconnect or remove containers, then retry rm
ipam driver dhcp is not supported with ipvlan Default IPAM on ipvlan create Add --ipam-driver=host-local and --subnet
Container has no outbound traffic after firewall reload Netavark rules dropped podman network reload CONTAINER or --all
Macvlan/ipvlan create permission error rootless Parent NIC requires root Run create with sudo or stay on bridge/pasta rootless
--format template error on subnets Field name is Subnets in Go templates Use {{(index .Subnets 0).Subnet}}

References


Summary

You created persistent Podman network objects with podman network create, listed and filtered them with podman network ls, and pulled subnet, gateway, and DNS flags from podman network inspect. Custom --subnet, --gateway, and --ip-range values shape automatic addressing without renumbering the whole host.

Containers joined networks at podman run time and later with podman network connect, gaining extra interfaces without a restart. Internal bridges dropped the default route while keeping container-to-container traffic; IPv6 and dual-stack subnets extended the same model. Macvlan and ipvlan tied networks to a real parent interface — with ipvlan needing --ipam-driver=host-local when dhcp IPAM fails.

Remember the Podman 5 versus 6 isolation default before you assume bridges are isolated from each other. When firewall reload breaks NAT, podman network reload is the first recovery step. For name resolution and outbound connectivity debugging, continue with the DNS and no-Internet guides linked above.


Frequently Asked Questions

1. What is the default driver for podman network create?

Bridge is the default driver. Podman allocates a free subnet and creates a persistent network object backed by Netavark. You can override the driver with --driver for macvlan or ipvlan when you need containers on a host interface.

2. Can a running container join another Podman network?

Yes. Attach a network at create time with --network NAME, or add another network later with podman network connect. The container keeps running; it gains an additional interface and IP on the new network. Use podman network disconnect to remove one attachment without stopping the container.

3. What does --internal do on a Podman bridge network?

Internal bridge networks still allow container-to-container traffic and Aardvark DNS for container names on that network. Podman does not add a default route and disables external forwarding for the bridge, so outbound traffic to the wider network is blocked. It is not the same as --network=none.

4. Why does ipvlan network create fail with ipam driver dhcp?

IPvlan networks do not support the default dhcp IPAM driver on Podman 5.8. Create the network with --ipam-driver=host-local and an explicit --subnet instead. Macvlan may use dhcp IPAM depending on your topology.

5. What happens if I run podman network rm while containers are attached?

Podman refuses the delete and reports that the network has associated containers. Disconnect or remove those containers first, or use podman network rm -f only when you intend to force-remove attached workloads along with the network.
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)