How to Configure firewalld for Docker or Podman on Fedora

Enable the container or docker service in firewalld to allow Podman or Docker traffic on Fedora.

The container runs but the port is unreachable

You spin up a web server in Podman. You map port 8080 to the host. You curl localhost and see the page. You try to access it from your phone on the same Wi-Fi and the connection times out. The container is running. The port is mapped. The firewall is eating the traffic.

This happens on Fedora because firewalld is enabled by default and configured to drop traffic that does not match an allowed service. Containers create virtual network interfaces. firewalld sees those interfaces and applies rules based on the zone. If the zone does not allow the container service, incoming connections to mapped ports are blocked.

How firewalld handles container traffic

Fedora uses firewalld as the firewall manager. firewalld manages rules using zones and services. A zone defines the trust level for a network interface. A service defines a set of ports and protocols that are allowed. When you enable a service in a zone, firewalld opens the necessary ports for traffic destined to that zone.

Containers add complexity. The container runtime creates virtual interfaces for each container or pod. These interfaces appear in the network namespace. firewalld needs to know that traffic arriving on these interfaces is safe. The container service in firewalld tells the firewall to allow traffic on interfaces that belong to container runtimes.

The service definition lives in /usr/lib/firewalld/services/container.xml. This file ships with the firewalld package. It contains rules that match the virtual interfaces created by Podman and Docker. You do not edit this file. You enable the service in your zone.

Fedora uses nftables as the backend for firewalld. nftables is the modern replacement for iptables. It handles rules more efficiently and supports sets and maps. Docker still relies on iptables for its internal networking. This creates a conflict when both tools try to manage the kernel's netfilter hooks. firewalld writes rules to nftables. Docker writes rules to iptables. The kernel translates between them, but the state can get corrupted. You see errors in the journal. The firewall reload fails. Docker stops working.

Check the active zone before adding services. Adding a service to the wrong zone has no effect.

# Show which interfaces are in which zones
# This tells you where to add the container service
firewall-cmd --get-active-zones

Enable the container service for Podman

Podman respects firewalld. It does not manipulate iptables directly. You enable the container service in the zone where your network interface lives. This adds the rules that allow traffic to container ports.

Enable the service in the permanent configuration. This ensures the rule survives a reboot. Reload the firewall to apply the changes to the running system.

# Add the container service to the permanent configuration
# This persists across reboots and firewall reloads
sudo firewall-cmd --permanent --add-service=container
# Apply the changes to the running firewall
# Rules do not take effect until you reload
sudo firewall-cmd --reload

Run firewall-cmd --reload after every permanent change. The runtime configuration and the persistent configuration diverge if you skip this step.

Enable the docker service for Docker

Docker requires different handling. Docker installs its own firewall rules. You can enable the docker service in firewalld, but Docker often conflicts with firewalld. The docker service allows traffic on the Docker bridge interface. It does not prevent Docker from rewriting iptables rules.

Enable the docker service if you are using Docker and want firewalld to allow traffic on the Docker bridge.

# Enable the docker service for firewalld
# This allows traffic on the docker0 bridge interface
sudo firewall-cmd --permanent --add-service=docker
# Reload to apply the service to the active zone
sudo firewall-cmd --reload

Docker may still break firewalld. Docker daemon restarts flush iptables rules. This can remove firewalld rules. You may need to disable Docker's iptables management.

Disable Docker's iptables management by editing the daemon configuration. Create or edit /etc/docker/daemon.json. Add the iptables key set to false. Restart the Docker daemon.

{
  "iptables": false
}

Restart the Docker service after editing the configuration. Docker will stop managing iptables. firewalld retains control. You must manage port forwarding manually or rely on firewalld rules.

# Restart Docker to apply the daemon configuration
# Docker will stop manipulating iptables rules
sudo systemctl restart docker

Edit configuration files in /etc/. Never edit files in /usr/lib/. Files in /usr/lib/ ship with packages and get overwritten on updates.

Verify the rules are active

Check that the service is enabled in the zone. List the services in the active zone. The output should include container or docker.

# List services enabled in the current zone
# Verify that container or docker appears in the list
firewall-cmd --list-services

Check that the port is open on the host. Use ss to see listening sockets. The output should show the port bound to 0.0.0.0 or the specific interface.

# Check listening sockets for the container port
# The grep filters for the specific port number
ss -tlnp | grep 8080

Test the connection from a remote machine. Use curl or a browser. If the connection succeeds, the firewall is allowing traffic.

Run journalctl -xeu firewalld if you suspect the firewall is failing. The -u flag filters by unit name. The -x flag adds explanatory text. The -e flag jumps to the end. This shows recent errors and context.

# Check firewalld logs for errors during reload
# The -xe flags add explanations and jump to the end
journalctl -xeu firewalld

Read the actual error before guessing. Half the time the symptom is a missing dependency or a syntax error in a config file.

Common failures and Docker conflicts

You may encounter errors when enabling services or reloading the firewall. These errors indicate specific problems.

The INVALID_ZONE error means you tried to add a service to a zone that does not exist. Check the active zones. Add the service to the correct zone.

Error: INVALID_ZONE: public

The COMMAND_FAILED error often indicates a conflict between firewalld and Docker. Docker manipulates iptables. firewalld uses nftables. The conflict causes the reload to fail. Disable Docker's iptables management. Restart Docker. Reload firewalld.

Error: COMMAND_FAILED: 'iptables-restore' failed

SELinux may block port binding if you use a non-standard port. SELinux enforces type enforcement on ports. If the port is not labeled correctly, the container cannot bind. Check SELinux denials.

# Check SELinux denials related to port binding
# setroubleshoot summarizes the denial in plain text
journalctl -t setroubleshoot

Add the port to the SELinux policy if needed. Use semanage port to add the port to the correct type. This allows the container to bind the port.

# Add the port to the http_port_t type
# This allows containers to bind to the port
sudo semanage port -a -t http_port_t -p tcp 8080

Zone mismatch is a silent failure. You add the service to public. The interface is in home. The service is not active for the interface. Traffic is blocked. Check the zone for the interface. Add the service to the correct zone.

# Check the zone for a specific interface
# Replace eth0 with your interface name
firewall-cmd --get-zone-of-interface=eth0

Snapshot the system before the upgrade. Future-you will thank you.

Choose the right firewall strategy

Use Podman when you want rootless containers and native firewalld integration without daemon conflicts.

Use Docker with the docker firewalld service when you are running legacy scripts that depend on the Docker daemon and you accept the risk of iptables interference.

Use dockerd --iptables=false when you need Docker to respect firewalld completely and you are willing to manage port forwarding manually.

Use firewall-cmd --add-port when you need to open a specific port for a container that does not match the standard container service definition.

Trust the package manager. Manual file edits drift, snapshots stay.

Where to go next