॥ श्री ॥

Firewall (firewalld)

Networking 2026-04-20

firewalld is active by default on Shani OS with a restrictive inbound policy. It manages nftables under the hood using a zone-based model — every interface belongs to a zone, and each zone has its own allow/deny rules. Do not mix direct nft commands with firewalld rules as they will conflict.

Pre-configured zones for KDE Connect, GSConnect, Waydroid, and Tailscale are included out of the box.

| Zone | Default assignment | Policy | |------|--------------------|--------| | public | All physical NICs | Deny inbound, allow outbound | | trusted | waydroid0 | Accept all |

---

Status & Inspection

# Confirm firewall is running
sudo firewall-cmd --state

# Show all rules for the active zone
sudo firewall-cmd --list-all

# Show all zones with their rules
sudo firewall-cmd --list-all-zones

# Show active zones and their interfaces
sudo firewall-cmd --get-active-zones

# Show which zone an interface belongs to
sudo firewall-cmd --get-zone-of-interface=eth0

# Show the default zone
sudo firewall-cmd --get-default-zone

---

Opening Services & Ports

The --permanent flag writes the rule to disk so it survives reboots. Always follow with --reload to apply immediately to the running firewall.

# Allow a named service (uses built-in service definitions)
sudo firewall-cmd --add-service=http --permanent
sudo firewall-cmd --add-service=https --permanent
sudo firewall-cmd --add-service=ssh --permanent
sudo firewall-cmd --reload

# Allow a specific TCP/UDP port
sudo firewall-cmd --add-port=8080/tcp --permanent
sudo firewall-cmd --add-port=51820/udp --permanent   # WireGuard
sudo firewall-cmd --add-port=41641/udp --permanent   # Tailscale
sudo firewall-cmd --reload

# Remove a rule
sudo firewall-cmd --remove-service=http --permanent
sudo firewall-cmd --remove-port=8080/tcp --permanent
sudo firewall-cmd --reload

# List all available pre-defined service names
sudo firewall-cmd --get-services

---

Zones

Zones let you apply different rules to different network interfaces or source IP ranges — useful when a LAN interface and a VPN interface should have different trust levels.

# Move an interface to a different zone
sudo firewall-cmd --zone=trusted --change-interface=tailscale0 --permanent
sudo firewall-cmd --reload

# Add a source IP range to a zone (all traffic from that range uses that zone's rules)
sudo firewall-cmd --zone=trusted --add-source=192.168.1.0/24 --permanent
sudo firewall-cmd --reload

# Create a custom zone
sudo firewall-cmd --new-zone=homelab --permanent
sudo firewall-cmd --reload
sudo firewall-cmd --zone=homelab --add-service=http --permanent
sudo firewall-cmd --reload

---

Rich Rules

Rich rules allow more granular conditions — source IP, destination port, logging, and rate limiting.

# Allow SSH only from your LAN
sudo firewall-cmd --add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" service name="ssh" accept' --permanent

# Block a specific IP entirely
sudo firewall-cmd --add-rich-rule='rule family="ipv4" source address="1.2.3.4" reject' --permanent

# Rate-limit new connections to port 443
sudo firewall-cmd --add-rich-rule='rule service name="https" limit value="50/m" accept' --permanent

# Log and drop traffic from a subnet
sudo firewall-cmd --add-rich-rule='rule family="ipv4" source address="10.0.0.0/8" log prefix="BLOCKED: " level="warning" drop' --permanent

sudo firewall-cmd --reload

---

Port Forwarding

# Forward incoming port 80 to localhost:8080
sudo firewall-cmd --add-forward-port=port=80:proto=tcp:toport=8080:toaddr=127.0.0.1 --permanent
sudo firewall-cmd --reload

---

Logging

# Enable logging of dropped packets
sudo firewall-cmd --set-log-denied=all --permanent
sudo firewall-cmd --reload

# View firewall-related kernel messages
sudo journalctl -k | grep -i "nft\|firewall\|REJECT\|DROP"

---

Runtime vs Permanent

# Show rules currently active (runtime)
sudo firewall-cmd --list-all

# Show what will be active after the next reload (permanent config on disk)
sudo firewall-cmd --list-all --permanent

# Sync runtime to match permanent config
sudo firewall-cmd --reload

# Make the current runtime config permanent without re-running each command
sudo firewall-cmd --runtime-to-permanent

Omit --permanent to test a rule without committing it — it disappears on the next --reload or reboot.

---

GUI

# Launch the graphical firewall manager (pre-installed)
sudo firewall-config

---

Common Port Reference

| Service | Port | Protocol | |---------|------|----------| | SSH | 22 | TCP | | HTTP | 80 | TCP | | HTTPS | 443 | TCP | | DNS | 53 | TCP/UDP | | WireGuard | 51820 | UDP | | Tailscale | 41641 | UDP | | Syncthing | 22000 | TCP/UDP | | KDE Connect | 1714–1764 | TCP/UDP | | Minecraft | 25565 | TCP |

---

Troubleshooting

| Issue | Solution | |-------|----------| | Service reachable locally but not from LAN | Check --list-all to confirm the port/service is open; verify the interface is in the correct zone | | Rule added but not working | Did you forget --reload? Runtime and permanent configs can diverge | | ALREADY_ENABLED error | The rule already exists permanently; inspect with --list-all --permanent | | Port open but connection refused | The service itself may not be running; check systemctl status <service> | | Rules disappear after reboot | Rule was added without --permanent | | fail2ban bans not appearing in firewall | Confirm fail2ban's backend is firewalld; check sudo firewall-cmd --direct --get-all-rules | | Waydroid has no network | Check waydroid0 is in the trusted zone: sudo firewall-cmd --get-zone-of-interface=waydroid0 | | Podman/container networking broken | Add the container bridge to trusted: sudo firewall-cmd --zone=trusted --add-interface=podman0 --permanent |

---

See Also