How to Close or Block a Port in the Firewall on Fedora

Block a port on Fedora by removing the service or port rule from the firewall and reloading the configuration.

You opened a port for testing and now need to lock it down

You spun up a development server on Fedora and opened port 8080 to test a web application. The test is complete. Now you want to close that door so external traffic cannot reach the service. Or perhaps a security scan flagged an open port you did not expect, and you need to shut it down immediately. You open the terminal and type iptables. You remember iptables from a tutorial years ago. Fedora does not use iptables directly. It uses firewalld. You need to tell firewalld to drop the traffic, and you need to do it correctly so the rule survives a reboot and does not conflict with other settings.

A botched firewall change can lock you out of SSH or break critical services. Always keep a second terminal session open when modifying firewall rules. If you are managing a remote server, consider using tmux or screen so you can recover access if the connection drops.

How firewalld manages access

firewalld is a dynamic firewall manager that controls the kernel's netfilter subsystem. On modern Fedora, the backend is nftables. firewalld translates your high-level commands into nftables rules. You do not need to know nftables syntax to use firewalld, but understanding the mental model prevents confusion.

The firewall sits between your network interfaces and the applications running on your machine. When a packet arrives, the kernel checks the firewall rules. If a rule allows the packet, it passes to the application. If no rule allows it, the default policy drops the packet. The application never sees the traffic.

firewalld organizes rules into zones. A zone is a named collection of rules that defines the trust level of a network. Fedora ships with zones like public, home, work, and trusted. Each network interface is assigned to a zone. Traffic entering an interface is evaluated against the rules of that zone. If you block a port in the public zone but your interface is assigned to home, the block has no effect.

There are two configurations: runtime and permanent. The runtime configuration lives in memory and is active immediately. The permanent configuration lives on disk and loads when the system boots. When you make a change with the --permanent flag, you are editing the file on disk. The change does not take effect until you reload the firewall. When you make a change without --permanent, you are editing the runtime configuration. The change takes effect immediately but is lost on reboot.

Think of the runtime config as the security guard's current instructions. Think of the permanent config as the rulebook in the drawer. You can shout a new rule to the guard, and he follows it until he goes home. If you want the rule to stay, you must write it in the rulebook and hand it to him.

Check the firewall state before you start. The daemon must be running.

sudo firewall-cmd --state
# WHY: Returns 'running' if the daemon is active.
# If it returns 'not running', the firewall is inactive and no rules are enforced.
# Start the service with 'sudo systemctl start firewalld' if needed.

Reload the firewall after every permanent change. The runtime config does not update itself.

The fix: Blocking ports and services

Identify the zone and current rules before making changes. You need to know which zone your interface uses and whether the port is open via a direct port rule or a service definition.

sudo firewall-cmd --get-active-zones
# WHY: Lists all active zones and the interfaces assigned to them.
# Use this to confirm which zone you need to modify.
# If you see 'public' with 'eth0', target the 'public' zone.
sudo firewall-cmd --list-all
# WHY: Shows the full configuration of the default zone.
# Look for 'services' and 'ports' sections.
# If 'http' is in services, port 80 is open via the service definition.
# If '8080/tcp' is in ports, it is open via a direct port rule.

Remove the port from the permanent configuration. Specify the protocol. Fedora requires tcp or udp. Omitting the protocol causes an error.

sudo firewall-cmd --permanent --remove-port=8080/tcp
# WHY: --permanent writes to the config file on disk.
# --remove-port takes the port number and protocol.
# This change does not take effect until you reload the firewall.

Reload the firewall to apply the permanent change to the runtime configuration.

sudo firewall-cmd --reload
# WHY: Reloads the permanent configuration into the runtime.
# Without this, the rule stays on disk but the active firewall ignores it.
# This command does not drop existing connections.

If the port is open because a service is allowed, removing the port alone does not work. Services are named groups of ports. The http service opens port 80/tcp. If you remove port 80/tcp but the http service is still allowed, the port remains open. Services override manual port blocks. Remove the service instead.

sudo firewall-cmd --permanent --remove-service=http
# WHY: Services are high-priority rules.
# Removing the service removes all associated port rules.
# This is cleaner than removing ports manually when a service is defined.

For an immediate block that does not persist, use runtime commands. This is useful for emergency mitigation or testing. The rule vanishes on reboot.

sudo firewall-cmd --remove-port=8080/tcp
# WHY: Omits --permanent. Changes the active firewall immediately.
# This rule is lost on reboot. Use this for emergency lockdowns.
# Follow up with --permanent commands if the block should persist.

Check the zone assignment before you block. A rule in the wrong zone is invisible to your traffic.

Verify the block

The firewall blocks incoming traffic. It does not stop the application from listening. The application may still be bound to the port. Use ss to check the listener state. Use firewall-cmd to check the firewall state.

sudo firewall-cmd --query-port=8080/tcp
# WHY: Returns 'yes' if the port is open, 'no' if blocked.
# This checks the runtime configuration.
# A 'no' result means the firewall will drop incoming packets.
ss -tlnp | grep 8080
# WHY: Shows if a process is listening on the port.
# The firewall blocks external access but the app can still listen.
# If you see a process, the app is running. The firewall just hides it.

Test from a remote machine. The firewall often allows loopback traffic. A connection from localhost may succeed even when the port is blocked for external traffic. Verify the block from a different host on the network.

Run journalctl -xeu firewalld if the command fails. Read the actual error before guessing.

Common pitfalls and error patterns

You run the command and get Error: INVALID_ZONE. You are targeting a zone that does not exist or is not active. Check the active zones with --get-active-zones. You might be on home or work instead of public. Specify the correct zone with --zone=home.

You removed the port but the connection still works. You forgot --reload. The permanent change is on disk but not active. Run sudo firewall-cmd --reload. Or you are testing from localhost. The loopback interface is often trusted. Test from a remote host.

You blocked 80/tcp but http service is still open. Services override ports. Remove the service with --remove-service=http. Or remove the service and the port. The service rule wins.

You get Error: COMMAND_FAILED. The syntax is wrong. Check the port format. It must be port/protocol. Use 8080/tcp, not 8080. Use udp, not up. Check the zone. Use --get-zones to list all available zones.

You need to block a port for a specific IP only. Use rich rules. Rich rules allow granular control.

sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.50" port port="8080" protocol="tcp" reject'
# WHY: Rich rules allow conditions beyond simple port blocks.
# This blocks port 8080 only for the specified IP.
# Other IPs can still connect.
# Reload the firewall after adding the rule.

You want to test a change safely. Use the timeout feature. This opens a port for a set duration then closes it automatically.

sudo firewall-cmd --add-port=8080/tcp --timeout=60
# WHY: Opens the port for 60 seconds then closes it.
# Useful for testing if a service is reachable without permanent changes.
# The timeout applies to the runtime config only.

Edit configuration files in /etc/firewalld/. Files in /usr/lib/firewalld/ ship with packages. Editing /usr/lib/ causes drift and breaks on updates. Use firewall-cmd commands to manage rules. Manual file edits are error-prone.

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

Decision matrix

Use --remove-port when you need to block a specific port number that is not part of a named service.

Use --remove-service when the port belongs to a standard service like http or ssh and you want to disable the whole service definition.

Use --permanent with --reload when the change must survive a system reboot.

Use runtime commands without --permanent when you need an immediate block for testing or emergency mitigation and plan to configure the permanent rules later.

Use --zone=... when your interface is assigned to a zone other than the default public zone.

Use rich rules when you need to block a port for a specific source IP or reject with a custom message.

Use the timeout feature when you need to open a port temporarily for a quick test.

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

Where to go next