| Tested on | Red Hat Enterprise Linux 10.2 (Coughlan) |
|---|---|
| Package | podman-5.8.2-5.el10_2.x86_64netavark-1.17.2-1.el10.x86_64aardvark-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:
podman network create podman-network-demoSample output:
podman-network-demoPodman prints the network name on success. Confirm it exists:
podman network lsSample output:
NETWORK ID NAME DRIVER
ece90e607d27 podman-network-demo bridgeOn 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:
podman network inspect podman-network-demoSample output (trimmed):
[
{
"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:
podman network lsUse filters when the list grows. Driver filter:
podman network ls --filter driver=bridgeName substring filter:
podman network ls --filter name=demoLabel filter (create labeled networks with --label key=value):
podman network create --label environment=test podman-label-demoList only networks that carry the label:
podman network ls --filter label=environment=testSample output:
NETWORK ID NAME DRIVER
651838b55148 podman-label-demo bridgeFor a compact table without learning every Go template field, --format accepts a few useful columns:
podman network ls --format 'table {{.Name}}\t{{.Driver}}\t{{.NetworkInterface}}'Sample output:
NAME DRIVER NETWORK INTERFACE
podman-network-demo bridge podman6
podman-label-demo bridge podman7That 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:
nameandid— human name and stable IDdriver—bridge,macvlan, oripvlannetwork_interface— host bridge or parent NICsubnets— CIDR, gateway, and optionallease_rangeipv6_enabledandinternal— dual-stack and isolation flagsdns_enabled— whether Aardvark serves names on this networkipam_options— IPAM driver (host-local,dhcp, …)routes— static routes pushed into attached containerscontainers— connected endpoints
Pull single fields with --format when you are scripting checks:
podman network inspect --format '{{.DNSEnabled}}' podman-network-demoSample output:
trueSubnet and gateway use the Subnets slice (capital S in the Go template):
podman network inspect --format '{{(index .Subnets 0).Subnet}}' podman-network-demoSample output:
10.89.5.0/24The gateway is the bridge address containers use as their default next hop on that subnet:
podman network inspect --format '{{(index .Subnets 0).Gateway}}' podman-network-demoSample output:
10.89.5.1Those 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:
podman network create --subnet 10.20.0.0/24 podman-custom-subnetSample output:
podman-custom-subnetVerify the CIDR stuck:
podman network inspect --format '{{(index .Subnets 0).Subnet}} {{(index .Subnets 0).Gateway}}' podman-custom-subnetSample output:
10.20.0.0/24 10.20.0.1Pick 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:
podman network create --subnet 10.21.0.0/24 --gateway 10.21.0.1 podman-custom-gatewaySample output:
podman-custom-gatewayIf 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:
podman network create --subnet 10.22.0.0/24 --ip-range 10.22.0.128/25 podman-ip-rangeInspect shows the lease window under lease_range:
'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:
podman run -d --name network-demo --network podman-network-demo docker.io/library/alpine:3.20 sleep 600Sample output:
1bd7f5a227652561e623bb343b0fc0dfbc5e2015cda8d0d56e5e662768bbba8cCheck the address inside the container namespace:
podman exec network-demo ip addr show eth0Sample output:
inet 10.89.5.3/24 brd 10.89.5.255 scope global eth0Podman-side attachment metadata lives under NetworkSettings.Networks:
podman inspect network-demo --format '{{json .NetworkSettings.Networks}}'Sample output (trimmed):
{"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:
podman network create second-networkAttach the running container without stopping it:
podman network connect second-network network-demopodman network connect exits silently on success. List both attachments:
podman inspect network-demo --format '{{json .NetworkSettings.Networks}}'Sample output (trimmed):
{
"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:
podman run -d --name database-container --network podman-network-demo docker.io/library/alpine:3.20 sleep 600Add a DNS alias on the second network only:
podman network connect --alias database second-network database-containerOther 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:
podman network disconnect second-network network-demoThe 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:
podman network create --internal podman-internalRun two containers and confirm they reach each other:
podman run -d --name int-a --network podman-internal docker.io/library/alpine:3.20 sleep 600From a second container on the same bridge, ping by name:
podman run --rm --network podman-internal docker.io/library/alpine:3.20 ping -c 1 int-aSample output:
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.266/0.266/0.266 msInside an internal network container, routing tells the story:
podman exec int-a ip routeSample output:
10.89.8.0/24 dev eth0 scope link src 10.89.8.2There is no default route. Outbound traffic beyond the bridge fails:
podman exec int-a ping -c 1 -W 2 8.8.8.8Sample output:
ping: sendto: Network unreachableOn 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:
podman network create --ipv6 podman-ipv6Inspect shows both address families when Podman allocates them:
10.89.9.0/24 fd41:428:bc84:c9c3::/64For explicit dual-stack CIDRs, pass subnets and gateways in matching order:
podman network create --subnet 10.23.0.0/24 --subnet fd00:23::/64 --gateway 10.23.0.1 --gateway fd00:23::1 podman-dual-stackVerify IPv6 inside a container:
podman run --rm --network podman-dual-stack docker.io/library/alpine:3.20 ip -6 addr show eth0Sample output:
inet6 fd00:23::2/64 scope global
inet6 fe80::18d5:8cff:fe35:7d54/64 scope linkThat 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:
podman network create --subnet 10.24.0.0/24 --route 172.20.0.0/16,10.24.0.254 podman-routedInspect the routes field:
[{"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:
podman network create --subnet 10.25.0.0/24 --opt no_default_route=true podman-no-default-routeOlder docs sometimes show no_default_route=1; the tested binary accepts true. Check inside a container:
podman run --rm --network podman-no-default-route docker.io/library/alpine:3.20 ip routeSample output:
10.25.0.0/24 dev eth0 scope link src 10.25.0.2Only 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:
podman network inspect --format '{{.DNSEnabled}}' podman-network-demoSample output:
trueTurn off container-name DNS for a network:
podman network create --disable-dns podman-no-dnsConfirm DNS is off for that object:
podman network inspect --format '{{.DNSEnabled}}' podman-no-dnsSample 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:
podman network create --dns 10.0.0.53 podman-custom-dnsInspect shows the upstream list:
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:
ip route show defaultOn the lab VM the default route uses enp0s3. Create the network as root:
sudo podman network create --driver macvlan --opt parent=enp0s3 podman-macvlanInspect ties the parent to network_interface:
"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:
ip link show enp0s3A plain create often fails because dhcp IPAM is incompatible:
sudo podman network create --driver ipvlan --opt parent=enp0s3 podman-ipvlanSample output:
Error: ipam driver dhcp is not supported with ipvlanFix it with host-local IPAM and an explicit subnet. Use a CIDR that fits your LAN — the lab uses the host-only segment:
sudo podman network create --driver ipvlan --opt parent=enp0s3 --ipam-driver=host-local --subnet 192.168.56.0/24 podman-ipvlanDo 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
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:
podman network create --opt isolate=false mynetworkSupported isolate values on Podman 6:
strict— default; block traffic to and from all other Podman bridge networkstrue— isolate from other networks that also have isolation enabled (trueorstrict)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:
podman network reload network-demoRefresh every running container at once:
podman network reload --allOn 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:
podman network rm podman-custom-subnetIf containers remain attached, Podman blocks the delete:
Error: "podman-network-demo" has associated containers with it. Use -f to forcibly delete containers and pods: network is being usedClean up in order:
podman network disconnect NETWORK CONTAINER(orpodman rmthe container)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:
podman network pruneSample output:
podman-custom-gateway
podman-custom-subnet
second-networkPodman lists each deleted name. Add -f to skip the confirmation prompt in scripts.
When your build supports time filters, prune old unused networks:
podman network prune --filter until=24h -fOnly 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.

