You deploy a new service and the connection hangs
You spin up a fresh Fedora instance. You install a database or a web framework. The application starts without errors. The socket binds to the expected port. You run a quick test from localhost and the response is instant. You attempt the same request from a different machine and the connection times out. You check the service status. It is active. You check the listening ports. They are open. The packets are simply not arriving. Something is eating them between the network interface and your application. You need to see exactly what firewalld is discarding.
What is actually happening
firewalld acts as a dynamic manager for the Linux kernel firewall. It translates your zone definitions into nftables rules. By default, firewalld follows a strict deny-all posture for any traffic that does not explicitly match an allowed rule. When a packet hits that default drop policy, the kernel silently discards it. No ICMP message is sent back to the sender. No log entry is written to disk. This default behavior protects your system from noisy network scans and keeps your disk I/O low. It also makes debugging connectivity issues feel like staring into a black hole.
Enabling dropped packet logging changes that default behavior. It tells the kernel to attach a LOG target to the chain before the DROP target. Every packet that fails to match an allow rule gets tagged with metadata and forwarded to the audit subsystem. You trade a small amount of CPU and disk space for visibility. That trade is worth it when you are troubleshooting, but it requires careful handling so your logs do not fill up overnight. The logging happens at the kernel level, which means the performance impact is minimal compared to userspace packet capture tools. You are not running tcpdump or wireshark. You are asking the kernel to write a structured line to the audit ring buffer whenever a packet hits the dead end.
Reboot before you debug. Half the time the symptom is gone.
How to enable drop logging
You need to adjust two settings. First, you raise the firewalld log level so it actually passes the kernel log messages to userspace. Second, you enable the log-dropped flag in your active zone. The flag must be applied permanently so it survives a reboot, but you also need to reload the runtime configuration to see the effect immediately.
Here is how to check your current zone and log level before making changes.
sudo firewall-cmd --get-default-zone # Shows which zone is active by default
sudo firewall-cmd --get-log-level # Shows the current verbosity setting
The default zone is usually public. The default log level is info. You will bump the level to debug temporarily to catch every drop event, then enable the permanent flag.
sudo firewall-cmd --set-log-level=debug # Raises runtime verbosity to capture kernel drop messages
sudo firewall-cmd --permanent --set-log-dropped=yes # Persists the drop-logging flag across reboots
sudo firewall-cmd --reload # Applies the permanent configuration to the running firewall
The --permanent flag edits the XML configuration files in /etc/firewalld/. Files in /usr/lib/firewalld/ ship with the package and should never be edited. The --reload command bridges the two directories. It flushes the live nftables rules and rebuilds them from the permanent configuration. Always reload after permanent changes. Otherwise your runtime and persistent configs diverge.
Run journalctl first. Read the actual error before guessing.
Verify the logs
Once the firewall reloads, generate some traffic that should be blocked. Try connecting to a closed port or reaching a service you have not opened in the zone. The kernel will now log the drop event. You can watch the logs in real time using journalctl.
sudo journalctl -xeu firewalld | grep -i "drop" # Shows recent firewalld logs with explanatory context
sudo grep -i "DROPPED" /var/log/audit/audit.log # Checks the audit subsystem for kernel-level drop records
The log line will contain interface names, source and destination IPs, protocol, and port numbers. A typical entry looks like this:
firewalld: DROP IN=eth0 OUT= MAC=00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff SRC=192.168.1.50 DST=10.0.0.5 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=54321 DF PROTO=TCP SPT=49152 DPT=8080 WINDOW=64240 RES=0x00 SYN URGP=0
Parse the fields methodically. SRC tells you who is trying to reach you. DST confirms the packet hit the correct interface. PROTO, SPT, and DPT show the transport layer details. If DPT matches your service port, the firewall is correctly blocking traffic that should be allowed. You then need to add a port rule or move the service to a more permissive zone. If DPT is random, you are looking at background noise or a scan. Trust the package manager. Manual file edits drift, snapshots stay.
Common pitfalls and production safety
Leaving the log level at debug in production will fill your disk. The debug level logs every single packet inspection, not just drops. You will see thousands of lines per minute on a busy server. Switch back to info once you have identified the blocked traffic.
sudo firewall-cmd --set-log-level=info # Returns verbosity to the standard production setting
Another common issue is log rotation. The audit log and journal files grow quickly when logging drops. Ensure logrotate is configured for /var/log/audit/audit.log and that journalctl --vacuum-size=500M is scheduled if you run this on a low-storage machine. Fedora's release cadence is 6 months. The N-2 release goes EOL when N+1 ships. Plan upgrades on that cycle. Do not let unrotated logs become the reason you cannot upgrade.
You might also encounter SELinux denials if you try to write custom log parsers or move log files to a custom directory. SELinux enforces strict file contexts. Do not move audit logs without setting the correct context with semanage fcontext. SELinux denials show up in journalctl -t setroubleshoot with a one-line summary. Read those before disabling SELinux. Disabling SELinux to fix a logging problem introduces a larger security problem.
If the boot menu is gone, GRUB rescue is your friend, not your enemy.
When to use logging vs alternatives
Use log-dropped when you are debugging why a specific client or service cannot reach your host. Use log-rejected when you want to log traffic that triggers an explicit reject rule and sends an ICMP unreachable message back to the sender. Use log-all when you need a complete audit trail of every packet touching the firewall, regardless of whether it is allowed or denied. Stick to info log level for production systems. Keep debug reserved for active troubleshooting sessions. Stay on the upstream Workstation if you only deviate from the defaults occasionally.