How to Allow a Service Through the Firewall on Fedora

To allow a service through the firewall on Fedora, use `firewall-cmd` to add the predefined service name to the active zone and make the change permanent.

You installed a service and the connection timed out

You installed a web server, a database, or a custom application on Fedora. You started the service. You checked that it is listening on the correct port. You opened your browser on another machine and the connection timed out. The service is running. The port is open. The firewall is standing in the way.

Fedora ships with firewalld enabled by default. It blocks all incoming traffic except what you explicitly allow. This is good security. It is also the first wall you hit when exposing a new service. The error is usually a timeout or a connection refused message from the client. The server logs show nothing because the packet never reached the application.

How firewalld manages traffic

firewalld manages the netfilter rules in the kernel. It does not just open ports. It manages zones. A zone is a named set of rules applied to a network interface. The default zone is usually public. When you add a service, you are telling the firewall to trust traffic matching that service's definition for that zone.

There are two configurations. The runtime configuration lives in memory and applies immediately. The permanent configuration lives on disk and applies after a reload or reboot. If you change the permanent config, the runtime config does not update automatically. You must reload. If you change the runtime config, it vanishes on reboot unless you make it permanent. This separation lets you test changes without breaking your current session.

Run firewall-cmd --state to confirm the daemon is active. If it returns not running, start the service with systemctl start firewalld. A stopped firewall means no filtering, which is rarely what you want on a production system.

Check your zones before you change rules

You must know which zone your interface is in. If you add a rule to public but your interface is in internal, the rule does nothing. This is the most common mistake. Users modify the wrong zone and wonder why the traffic is still blocked.

# Check if firewalld is running. If it says not running, start it with systemctl.
sudo firewall-cmd --state
# List active zones and the interfaces attached to them.
# This tells you which zone your traffic is hitting.
# If your interface is missing, it defaults to the zone set in firewalld.conf.
sudo firewall-cmd --get-active-zones

The output shows zones like public or home and lists interfaces like eth0 or wlan0. Traffic arriving on eth0 is evaluated against the rules in the zone assigned to eth0. If you have multiple interfaces, they can belong to different zones. A server might have public on the external interface and trusted on the internal management interface.

Check the active zones first. Modify the zone that matches your interface.

Allow a standard service

Most common services have predefined definitions. These definitions include the port number, the protocol, and sometimes helper applications. Using the service name is safer than opening a raw port because the definition handles the details. If the port changes in a future package update, the firewall rule updates automatically.

Find the service name by listing available definitions. The list is long. Pipe it to grep to search.

# List all available service definitions.
# This output is long. Pipe it to grep to find what you need.
# Service names are lowercase and match the XML files in /usr/lib/firewalld/services/.
sudo firewall-cmd --get-services | grep -i http

Once you have the name, add it to the permanent configuration. The --permanent flag writes the rule to disk. It does not apply the rule to the running firewall. You must reload to activate it.

# Add the http service to the permanent configuration.
# This writes the rule to disk but does not apply it yet.
# The rule survives a reboot but is inactive until you reload.
sudo firewall-cmd --permanent --add-service=http
# Reload the firewall to merge permanent changes into the runtime configuration.
# Without this step, the rule sits on disk and does nothing until reboot.
# This is the standard workflow: change permanent, then reload.
sudo firewall-cmd --reload

Reload the firewall after every permanent change. The runtime and persistent configs diverge instantly if you skip this step.

Verify the rule is active

After reloading, check the runtime configuration. The permanent config is what you saved. The runtime config is what is actually filtering packets. You need to verify the runtime config.

# List services allowed in the current runtime configuration.
# The output shows what is active right now, not what is saved for reboot.
# If your service is missing here, the reload failed or you checked the wrong zone.
sudo firewall-cmd --list-services

If the service appears in the list, the firewall allows the traffic. Test the connection from a client. If it still fails, the issue is not the firewall. Check the application logs, the listening port, or SELinux.

Verify the runtime list. If the service is not there, the reload failed or you checked the wrong zone.

Open a custom port

Some applications do not have a service definition. You must open the port manually. You must specify the protocol. firewall-cmd rejects port numbers without a protocol.

# Add a custom TCP port to the permanent configuration.
# Use this when no service definition exists for your application.
# You must specify /tcp or /udp. Omitting the protocol causes an error.
sudo firewall-cmd --permanent --add-port=8080/tcp
# Reload to apply the change immediately.
sudo firewall-cmd --reload

If you omit the protocol, firewall-cmd prints Error: INVALID_PORT: 8080. The command requires the format port/protocol. You can add multiple ports in one command by separating them with commas, but reloading is still required.

Specify the protocol. 8080 is not a valid argument. 8080/tcp is.

Restrict access with rich rules

Services and ports open access to everyone. If you only want to allow traffic from a specific IP or subnet, use a rich rule. Rich rules let you add conditions like source addresses, destination ports, and logging.

# Add a rich rule to allow HTTP only from a specific IP range.
# This is more secure than opening the service to everyone.
# The rule applies to the permanent configuration.
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" service name="http" accept'
# Reload to activate the rich rule.
sudo firewall-cmd --reload

Rich rules are evaluated before standard service rules. A rich rule can block traffic even if the service is allowed. Use rich rules for granular control. Use standard services for simple allow lists.

Reload after adding rich rules. The syntax is strict. A typo in the XML-like string causes Error: COMMAND_FAILED.

Common pitfalls and errors

You added the service but the connection still fails. Check these issues.

  • Wrong zone: You modified public but the interface is in internal. Run --get-active-zones to confirm.
  • Runtime vs Permanent: You added the rule without --permanent. It works now but vanishes on reboot. Or you added it with --permanent but forgot --reload. It is saved but inactive.
  • SELinux: The firewall allows the packet, but SELinux blocks the application from binding to the port or accessing resources. Check journalctl -t setroubleshoot for denials. The firewall is layer 3/4. SELinux is layer 7/process. Both must allow the traffic.
  • Service definition mismatch: The service name you used does not match the application's port. Check the definition file. Service files live in /usr/lib/firewalld/services/. You can view the XML to see the port and protocol. Never edit files in /usr/lib/. Copy to /etc/firewalld/services/ and modify there if you need a custom definition.
  • Error messages:
    • Error: INVALID_PORT: 8080: Missing protocol. Add /tcp or /udp.
    • Error: COMMAND_FAILED: Syntax error in a rich rule or invalid argument.
    • Error: ZONE_NOT_FOUND: You specified a zone that does not exist. Check --get-zones.

Check the zone before you blame the port. SELinux is the second wall.

Decision matrix

Use --add-service when the application has a standard definition in /usr/lib/firewalld/services/. Use --add-port when you need to open a single port for a custom application without a service file. Use --add-rich-rule when you need to restrict access by source IP or forward traffic to another port. Use --zone=internal when the service should only be accessible on your local network, not from the internet. Use --permanent when the rule must survive a reboot. Use --reload after every permanent change to activate the rule immediately. Use firewall-cmd --list-all when you need to see all rules, ports, and rich rules for a zone in one view.

Reload or the rule is dead. Trust the package manager for service definitions. Edit /etc/ for customizations.

Where to go next