You installed a service and the connection times out
You just finished installing a database or a web server on your Fedora machine. The service is running. systemctl status shows green. You try to connect from your laptop, and the connection times out. The network is silent. You haven't misconfigured the application. The firewall is doing its job. Fedora ships with firewalld enabled by default, and it blocks everything except what you explicitly allow. This is good for security, but it can feel like a brick wall when you are trying to get a new service online.
Run firewall-cmd --list-all before you guess. The output tells you exactly what is allowed.
What's actually happening
firewalld sits between your network interfaces and the services listening on your system. It uses a concept called zones to group interfaces by trust level. The default zone is public, which assumes the network is untrusted and blocks incoming connections. When you add a rule, you are telling the firewall to open a specific door for a specific type of traffic.
There are two layers of configuration. The runtime configuration is active right now. The permanent configuration lives on disk and survives reboots. When you make a change with --permanent, it goes to disk but does not affect the active firewall until you reload. When you make a change without --permanent, it applies immediately but disappears on reboot.
Think of the runtime as the bouncer at the door and the permanent config as the guest list. If you update the guest list, the bouncer doesn't know until you hand him the new list. That is what firewall-cmd --reload does. Always reload after permanent changes. The runtime and permanent configs diverge until you sync them.
Config files live in /etc/firewalld/. The package ships defaults in /usr/lib/firewalld/. Never edit files in /usr/lib/. Your edits in /etc/ override the defaults. If you edit a file directly, run firewall-cmd --reload to pick up the changes. The firewall-cmd command is the safe way to modify rules. Direct file edits can lead to syntax errors that break the firewall on reload.
Check the current status
Here's how to see if the firewall is running and what rules are active.
sudo firewall-cmd --state
# Check if the daemon is running.
# Returns 'running' if active, or an error if stopped.
sudo firewall-cmd --get-active-zones
# Show which interfaces are assigned to which zones.
# This helps you target rules to the right network.
sudo firewall-cmd --list-all
# Display the full runtime configuration for the default zone.
# Includes allowed services, ports, masquerade status, and rich rules.
Run journalctl -xe if the firewall service fails to start. The logs show dependency errors or configuration syntax problems.
Allow a service or port
Firewalld knows about common services like http, https, ssh, and samba. These service definitions map to standard ports and protocols. Using service names is better than hardcoding ports because the definition can update if the standard port changes.
Here's how to add a service permanently and apply it.
sudo firewall-cmd --get-services
# List all available service definitions.
# Use this to find the correct name for your service.
sudo firewall-cmd --permanent --add-service=http
# Add http to the permanent configuration.
# This survives reboots but does not take effect immediately.
sudo firewall-cmd --reload
# Apply the permanent configuration to the runtime.
# Without this, the rule is inactive until the next boot.
If you are running a custom application on a non-standard port, add the port directly. Specify the protocol as tcp or udp.
sudo firewall-cmd --permanent --add-port=8080/tcp
# Open port 8080 for TCP traffic in the permanent config.
sudo firewall-cmd --reload
# Reload to activate the port immediately.
You can batch permanent changes and reload once. This is useful when setting up multiple services. Add all the --permanent rules first, then run --reload at the end. The firewall applies the entire batch atomically.
Reload after every permanent change. The runtime and permanent configs diverge until you sync them.
Use rich rules for granular control
Simple service and port rules open access to the world. Rich rules let you restrict access by source IP, forward ports, or masquerade. Use rich rules when you need more control than a blanket allow.
Here's how to allow a port only from a specific subnet.
sudo firewall-cmd --permanent --add-rich-rule='rule family=ipv4 source address=192.168.1.0/24 port protocol=tcp port=5432 accept'
# Allow PostgreSQL access only from the local subnet.
# This is more secure than opening the port to the world.
sudo firewall-cmd --reload
# Apply the rich rule to the active firewall.
The rich rule syntax follows a pattern: rule family=<family> source address=<ip> port protocol=<proto> port=<port> accept. You can also use reject or drop instead of accept. Use reject to send an error back to the client. Use drop to silently discard the packet.
Check rich rules with sudo firewall-cmd --list-rich-rules. They appear in the output with the full syntax.
Match the tool to the complexity. Simple ports get simple commands. Complex restrictions get rich rules.
Manage zones and interfaces
Zones let you apply different trust levels to different network interfaces. A laptop might have a public Wi-Fi adapter and a trusted wired connection. You can assign each interface to a zone that matches its risk level.
Here's how to list zones and assign an interface.
sudo firewall-cmd --get-zones
# List all available zone definitions.
# Includes public, trusted, block, drop, and custom zones.
sudo firewall-cmd --permanent --zone=trusted --add-interface=eth1
# Assign eth1 to the trusted zone permanently.
# The trusted zone allows all traffic by default.
sudo firewall-cmd --reload
# Reload to move the interface to the new zone.
The public zone blocks incoming traffic except for allowed services. The trusted zone allows all traffic. The block zone rejects all incoming traffic with a host-prohibited message. The drop zone silently drops all incoming traffic. Choose the zone that matches your security posture.
Run firewall-cmd --list-all-zones to see the rules for every zone. This helps you audit your configuration.
Verify and debug
After adding rules, verify that the firewall is working and the service is reachable. Check the firewall output, then test the connection.
Here's how to verify the rule and test the port.
sudo firewall-cmd --list-all
# Confirm the service or port appears in the output.
# If it is missing, the rule was not applied correctly.
ss -tlnp | grep 8080
# Check if the service is listening on the expected port.
# Ensure it is bound to 0.0.0.0 or the correct interface.
nc -zv localhost 8080
# Test the connection from the local machine.
# This rules out network issues and confirms the service is up.
If the firewall allows the port but the connection still fails, check the service binding. Many services bind to 127.0.0.1 by default. They will only accept connections from localhost. Edit the service configuration to bind to 0.0.0.0 or the specific interface address. Restart the service after the change.
Check the binding address. An open firewall port means nothing if the service is listening only on localhost.
Common pitfalls
You will run into a few standard errors. Knowing what they look like saves time.
You will see Error: COMMAND_FAILED if you try to add a rule that conflicts with an existing one, or if the syntax is wrong. Check the rule syntax and ensure you are not duplicating a rule that is already present.
A common mistake is adding a rule to the runtime but forgetting --permanent. The rule works until you reboot, then it disappears. Another mistake is adding --permanent and forgetting --reload. The rule is saved but inactive. Always pair --permanent with --reload unless you are batching changes.
Zone mismatches cause silent failures. If you add a rule to the public zone but your interface is assigned to work, the rule does not apply. Check the active zones with --get-active-zones and target the correct zone in your commands.
Service definitions can change between Fedora releases. A service that worked on Fedora 40 might have a different port on Fedora 42. Use --get-services to verify the definition exists and check the XML file in /usr/lib/firewalld/services/ if you need to inspect the details.
If the boot menu is gone, GRUB rescue is your friend, not your enemy. Firewall errors rarely prevent booting, but a misconfigured network service can block remote access. Test changes in a session you can recover from.
Decision matrix
Use --add-service when the port is standard and defined in /usr/lib/firewalld/services/. This keeps your config readable and updates automatically if the port changes.
Use --add-port when you are running a custom application on a non-standard port that has no service definition.
Use rich rules when you need to restrict access by source IP, forward ports, or masquerade.
Use zones when you have multiple interfaces with different trust levels, such as a public Wi-Fi adapter and a trusted wired connection.
Use firewall-config or the GNOME Settings GUI when you prefer a visual interface and are making simple changes to services or ports.
Use the command line when you are scripting, managing servers without a desktop, or need precise control over rich rules.