
Purpose:
Quick-reference guide to configure host firewalls on Rocky Linux (firewalld) and Ubuntu (ufw) with practical troubleshooting commands for homelab use.
Applies To:
- Rocky Linux 8/9 (RHEL-family,
firewalld)
- Ubuntu 20.04/22.04+ (
ufw, Uncomplicated Firewall)
Last Updated:
Difficulty:
- Intermediate (assumes Linux, TCP/IP, and basic security knowledge)
Overview
For Rocky, the native firewall service is firewalld (zones, services, rich rules).
For Ubuntu, the typical host firewall is ufw, a front end to iptables/nftables that exposes simple “allow/deny” syntax.
This guide focuses on:
- Enabling and hardening the system firewall
- Allowing common services (SSH, HTTP, etc.)
- Inspecting rules and live connections
- Using standard troubleshooting commands (ping, nc, curl, ss, tcpdump) to debug connectivity
Prerequisites
- Root or sudo access on the target host.
- SSH or console access (ideally via out-of-band if you are modifying SSH rules).
- Package updates applied (
dnf update / apt upgrade) to ensure current firewall components.
⚠️ WARNING: When changing firewall rules on remote systems, always ensure you have a persistent session and that SSH is explicitly allowed before applying restrictive policies, or you risk locking yourself out.
Step-by-Step Instructions
1. Confirm which firewall you are using
On Rocky Linux:
sudo firewall-cmd --state
sudo systemctl status firewalld
On Ubuntu:
sudo ufw status verbose
sudo systemctl status ufw
If firewalld or ufw are inactive, you will see them reported as not running or inactive.
2. Enable and secure the firewall
Rocky Linux: firewalld basics
- Enable and start
firewalld:
sudo systemctl enable --now firewalld
sudo firewall-cmd --state
- Check default zone and active interfaces:
sudo firewall-cmd --get-default-zone
sudo firewall-cmd --get-active-zones
sudo firewall-cmd --zone=public --list-all
Zones group interfaces/services by trust level (e.g., public, internal, dmz).
💡 TIP: In a homelab, map management networks to a more trusted zone (e.g., internal) and WAN-facing or guest networks to restrictive zones like public.
Ubuntu: ufw basics
- Enable
ufw:
- Lock in a default deny inbound posture:
sudo ufw default deny incoming
sudo ufw default allow outgoing
- Check status:
ufw outputs the default policy plus per-rule state.
3. Allow essential services (SSH, HTTP, HTTPS)
Rocky Linux (firewalld)
Allow SSH, HTTP, HTTPS in the default zone:
sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
sudo firewall-cmd --list-services
To allow a specific TCP port (e.g., 8080):
sudo firewall-cmd --permanent --add-port=8080/tcp
sudo firewall-cmd --reload
Services correspond to XML definitions under /usr/lib/firewalld/services/ and include standard port/protocol mapping.
Ubuntu (ufw)
Allow SSH, HTTP, HTTPS:
sudo ufw allow ssh # typically port 22/tcp
sudo ufw allow http # port 80/tcp
sudo ufw allow https # port 443/tcp
sudo ufw status numbered
To allow a specific TCP port (e.g., 8080):
To restrict a rule to a source network:
sudo ufw allow from 192.168.10.0/24 to any port 22 proto tcp
This is handy for homelab management networks.
4. Add more advanced/firewall-specific rules
firewalld: zones and rich rules
Assign an interface to a specific zone (e.g., eth1 to internal):
sudo firewall-cmd --permanent --zone=internal --change-interface=eth1
sudo firewall-cmd --reload
sudo firewall-cmd --zone=internal --list-all
Add a rich rule (e.g., allow SSH only from 10.0.0.0/24):
sudo firewall-cmd --permanent --zone=public \
--add-rich-rule='rule family="ipv4" source address="10.0.0.0/24" service name="ssh" accept'
sudo firewall-cmd --reload
Rich rules allow more granular matching (source, destination, logging, etc.).
ufw: application profiles and rules
List known application profiles:
Allow a profile (e.g., OpenSSH):
Delete a misconfigured rule by its number:
sudo ufw status numbered
sudo ufw delete <rule-number>
This prevents rule sprawl and keeps the rule set manageable.
5. Logging and visibility
firewalld logging
Enable logging of denied packets (RHEL-family):
sudo firewall-cmd --set-log-denied=all
Logs typically appear in:
sudo journalctl -u firewalld
sudo journalctl -k | grep -i "REJECT"
This is useful when you suspect the firewall is dropping traffic.
ufw logging
Enable ufw logging:
Inspect logs:
sudo grep UFW /var/log/syslog
# or on some systems:
sudo grep UFW /var/log/kern.log
Log entries show whether packets were allowed or denied, and from which source/destination.
Verification
1. Basic connectivity checks
From a remote host towards your Linux box:
ping <target-ip>
traceroute <target-ip> # or tracepath <target-ip>
On the target itself, verify listening services and bound ports:
ss shows listening ports, associated processes, and which address families are enabled.
💡 TIP: When debugging “service down” vs “firewall blocking,” start with ss or netstat to confirm the service is actually listening, then test connectivity (ping, nc, curl), then inspect firewall logs.
2. Port testing with netcat and curl
From a remote client:
nc -vz <target-ip> 22
nc -vz <target-ip> 80
For HTTP/S:
curl -v http://<target-ip>/
curl -vk https://<target-ip>/
If nc/curl time out or are refused, check firewall rules and host-based service status.
3. Packet-level verification (tcpdump)
On the firewall host:
sudo tcpdump -ni eth0 port 22
If packets arrive on the interface but the session never establishes, the firewall or local service is likely the culprit.
Troubleshooting
1. Standard triage steps
Work through these in order:
- Confirm interface IPs and routes:
ip addr show
ip route show
- Check firewall status and rules:
```bash
Rocky
sudo firewall-cmd –state
sudo firewall-cmd –list-all
Ubuntu
sudo ufw status verbose
3. Confirm service is listening:
```bash
sudo systemctl status sshd
sudo ss -tulpen | grep :22
- Review logs for denies:
```bash
firewalld/Kernel
sudo journalctl -u firewalld
sudo journalctl -k | grep -i “REJECT”
ufw
sudo grep UFW /var/log/syslog
These steps align with typical firewall troubleshooting guidance: log inspection, debugging tools, SNMP/CPU checks, and connectivity tests.[^8][^5]
### 2. Temporarily relax rules (with caution)
If you strongly suspect the firewall is the issue, and you have out-of-band access:
On firewalld:
```bash
sudo firewall-cmd --set-default-zone=trusted
# test connectivity, then revert:
sudo firewall-cmd --set-default-zone=public
On ufw:
sudo ufw disable
# test, then re-enable and fix rules:
sudo ufw enable
⚠️ WARNING: Never leave a host with a fully disabled firewall on untrusted networks. Use temporary relaxations only for controlled tests and revert immediately after.
3. SELinux considerations (Rocky)
If a service is listening and allowed in firewalld but traffic is still blocked, check SELinux:
getenforce
sudo ausearch -m AVC,USER_AVC -ts recent
Relabel or adjust SELinux policy using semanage and restorecon rather than disabling SELinux, to retain proper security posture.
Security Considerations
- Principle of least privilege: Only open ports/services that are strictly needed, and restrict by source networks where possible.
- Default deny: Keep default inbound policy as deny and add explicit allow rules (typical best practice on both network and host firewalls).
- Logging and review: Enable firewall logging for drops and periodically review logs to detect misconfigurations and suspicious activity.
- Change control: Back up configurations and document rule changes so you can roll back after testing.
💡 TIP: For a homelab, treat “lab-only” networks as lower trust than management networks, and still adhere to strict rules; it keeps habits aligned with production-grade practices.
Notes/Tips
- Pair host firewalls with upstream controls (Fortigate, etc.) to catch misconfigurations earlier in the path.
- For complex multi-hop issues, capture on both ends and in the middle (e.g., hypervisor bridge, router) to see exactly where traffic stops.
- Periodically audit firewall rules and prune unused entries to avoid rule bloat and unintended access.
To download this as a .md file, copy the raw Markdown above into a file or use the copy button.
What environment do you want to start with for hands-on examples in your homelab—Rocky (firewalld) hosts, Ubuntu (ufw) hosts, or both?
⁂