Firewalld is the default firewall management tool in Rocky Linux, providing a dynamic managed firewall with support for network zones and a D-Bus interface for easy management. This comprehensive guide will teach you how to configure and manage firewalld effectively, from basic concepts to advanced configurations, ensuring your Rocky Linux system is properly protected.
Understanding firewalld
What is firewalld?
firewalld is a firewall service daemon that provides a dynamic customizable host-based firewall with a D-Bus interface. Unlike static firewall solutions, firewalld allows changes to be made without restarting the entire firewall service, preventing existing connections from being lost.
Key Features
- Dynamic Configuration: Changes without service restart
- Zone-Based Management: Different trust levels for network connections
- D-Bus Interface: Allows applications to request firewall changes
- Runtime and Permanent Configuration: Test changes before making permanent
- Service and Port Definitions: Pre-configured service definitions
- Rich Language: Complex firewall rules with rich rule syntax
- IPv4 and IPv6 Support: Dual-stack firewall configuration
- Masquerading and Port Forwarding: NAT support
firewalld vs iptables
While firewalld uses iptables/nftables as its backend, it provides several advantages:
# Traditional iptables approach
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
service iptables save
service iptables restart # Disrupts connections
# firewalld approach
firewall-cmd --add-service=http
firewall-cmd --runtime-to-permanent # No restart needed
firewalld Architecture and Concepts
Core Components
- firewalld Service: The main daemon
- firewall-cmd: Command-line tool
- firewall-config: GUI configuration tool
- firewall-offline-cmd: Offline configuration tool
Configuration Hierarchy
/usr/lib/firewalld/ # Default configurations
├── services/ # Service definitions
├── zones/ # Zone definitions
└── icmptypes/ # ICMP type definitions
/etc/firewalld/ # Custom configurations
├── firewalld.conf # Main configuration
├── services/ # Custom services
├── zones/ # Custom zones
└── direct.xml # Direct rules
Runtime vs Permanent Configuration
firewalld maintains two configurations:
- Runtime: Active configuration (lost on reload/restart)
- Permanent: Saved configuration (loaded on start)
Basic firewalld Commands
Service Management
# Check firewalld status
sudo systemctl status firewalld
# Start firewalld
sudo systemctl start firewalld
# Enable firewalld at boot
sudo systemctl enable firewalld
# Stop firewalld (not recommended)
sudo systemctl stop firewalld
# Check if firewalld is running
sudo firewall-cmd --state
Basic Operations
# List all active zones
sudo firewall-cmd --get-active-zones
# List all available services
sudo firewall-cmd --get-services
# List all available zones
sudo firewall-cmd --get-zones
# Get default zone
sudo firewall-cmd --get-default-zone
# List everything added to a zone
sudo firewall-cmd --zone=public --list-all
# Reload firewall without losing state
sudo firewall-cmd --reload
# Complete reload (loses state information)
sudo firewall-cmd --complete-reload
Configuration Modes
# Make runtime changes (immediate effect)
sudo firewall-cmd --add-service=http
# Make permanent changes (requires reload)
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --reload
# Make runtime changes permanent
sudo firewall-cmd --runtime-to-permanent
# Check configuration
sudo firewall-cmd --check-config
Working with Zones
Understanding Zones
Zones define the trust level of network connections. Rocky Linux includes several predefined zones:
- drop: Lowest trust level, all incoming connections dropped
- block: All incoming connections rejected with icmp-host-prohibited
- public: Default zone for public networks
- external: For external networks with masquerading enabled
- dmz: For computers in DMZ with limited access
- work: For work networks
- home: For home networks
- internal: For internal networks
- trusted: All network connections accepted
Zone Management
# Set default zone
sudo firewall-cmd --set-default-zone=home
# Create custom zone
sudo firewall-cmd --permanent --new-zone=customzone
sudo firewall-cmd --reload
# Delete zone
sudo firewall-cmd --permanent --delete-zone=customzone
sudo firewall-cmd --reload
# Assign interface to zone
sudo firewall-cmd --zone=internal --add-interface=eth1
# Change interface zone
sudo firewall-cmd --zone=internal --change-interface=eth1
# Remove interface from zone
sudo firewall-cmd --zone=internal --remove-interface=eth1
Zone Configuration
# List zone configuration
sudo firewall-cmd --zone=public --list-all
# Add source to zone
sudo firewall-cmd --zone=trusted --add-source=192.168.1.0/24
# Remove source from zone
sudo firewall-cmd --zone=trusted --remove-source=192.168.1.0/24
# List sources in zone
sudo firewall-cmd --zone=trusted --list-sources
Custom Zone Example
# Create web server zone
sudo firewall-cmd --permanent --new-zone=webserver
sudo firewall-cmd --reload
# Configure zone
sudo firewall-cmd --permanent --zone=webserver --add-service=http
sudo firewall-cmd --permanent --zone=webserver --add-service=https
sudo firewall-cmd --permanent --zone=webserver --add-service=ssh
sudo firewall-cmd --permanent --zone=webserver --add-source=10.0.0.0/8
# Assign interface
sudo firewall-cmd --permanent --zone=webserver --add-interface=eth0
sudo firewall-cmd --reload
Managing Services
Predefined Services
# List available services
sudo firewall-cmd --get-services
# Show service details
sudo firewall-cmd --info-service=http
# Add service to zone
sudo firewall-cmd --zone=public --add-service=http
sudo firewall-cmd --zone=public --add-service=https
# Remove service from zone
sudo firewall-cmd --zone=public --remove-service=telnet
# Query if service is enabled
sudo firewall-cmd --zone=public --query-service=http
Creating Custom Services
# Create service file
sudo nano /etc/firewalld/services/myapp.xml
<?xml version="1.0" encoding="utf-8"?>
<service>
<short>MyApp</short>
<description>My Application Service</description>
<port protocol="tcp" port="8080"/>
<port protocol="tcp" port="8443"/>
<port protocol="udp" port="9000"/>
</service>
# Reload to recognize new service
sudo firewall-cmd --reload
# Use custom service
sudo firewall-cmd --zone=public --add-service=myapp
Service Management Examples
# Web server configuration
sudo firewall-cmd --permanent --zone=public --add-service=http
sudo firewall-cmd --permanent --zone=public --add-service=https
# Mail server configuration
sudo firewall-cmd --permanent --zone=public --add-service=smtp
sudo firewall-cmd --permanent --zone=public --add-service=smtps
sudo firewall-cmd --permanent --zone=public --add-service=imap
sudo firewall-cmd --permanent --zone=public --add-service=imaps
# Database server (specific sources)
sudo firewall-cmd --permanent --zone=internal --add-service=mysql
sudo firewall-cmd --permanent --zone=internal --add-source=192.168.1.0/24
# Apply changes
sudo firewall-cmd --reload
Port Management
Opening Ports
# Open single port
sudo firewall-cmd --zone=public --add-port=8080/tcp
# Open port range
sudo firewall-cmd --zone=public --add-port=5000-5010/tcp
# Open UDP port
sudo firewall-cmd --zone=public --add-port=123/udp
# Make permanent
sudo firewall-cmd --permanent --zone=public --add-port=8080/tcp
sudo firewall-cmd --reload
Closing Ports
# Remove port
sudo firewall-cmd --zone=public --remove-port=8080/tcp
# Remove port range
sudo firewall-cmd --zone=public --remove-port=5000-5010/tcp
# Query port status
sudo firewall-cmd --zone=public --query-port=8080/tcp
Port Forwarding
# Enable masquerading (required for port forwarding)
sudo firewall-cmd --zone=public --add-masquerade
# Forward port 80 to 8080
sudo firewall-cmd --zone=public --add-forward-port=port=80:proto=tcp:toport=8080
# Forward to different IP
sudo firewall-cmd --zone=public --add-forward-port=port=80:proto=tcp:toport=8080:toaddr=192.168.1.100
# Remove port forwarding
sudo firewall-cmd --zone=public --remove-forward-port=port=80:proto=tcp:toport=8080
# List port forwards
sudo firewall-cmd --zone=public --list-forward-ports
Rich Rules
Rich rules provide more complex firewall rule capabilities:
Rich Rule Syntax
# Basic syntax
rule family="ipv4|ipv6"
source address="address[/mask]"
destination address="address[/mask]"
service name="service"
port port="port" protocol="tcp|udp"
protocol value="protocol"
icmp-type name="icmptype"
masquerade
forward-port port="port" protocol="tcp|udp" to-port="port" to-addr="address"
log [prefix="prefix"] [level="level"] [limit value="rate/duration"]
audit [limit value="rate/duration"]
accept|reject|drop
Rich Rule Examples
# Allow specific IP to access SSH
sudo firewall-cmd --zone=public --add-rich-rule='
rule family="ipv4"
source address="192.168.1.100"
service name="ssh"
accept'
# Rate limit connections
sudo firewall-cmd --zone=public --add-rich-rule='
rule family="ipv4"
source address="192.168.1.0/24"
service name="http"
limit value="10/m"
accept'
# Log and drop specific traffic
sudo firewall-cmd --zone=public --add-rich-rule='
rule family="ipv4"
source address="10.0.0.0/8"
port port="22" protocol="tcp"
log prefix="SSH_ATTACK" level="warning"
drop'
# Time-based rule (requires firewalld >= 0.6.0)
sudo firewall-cmd --zone=public --add-rich-rule='
rule family="ipv4"
source address="192.168.1.0/24"
service name="ssh"
accept
limit value="5/h"'
# Port forwarding with rich rule
sudo firewall-cmd --zone=public --add-rich-rule='
rule family="ipv4"
forward-port port="443" protocol="tcp"
to-port="8443" to-addr="192.168.1.100"'
Managing Rich Rules
# List rich rules
sudo firewall-cmd --zone=public --list-rich-rules
# Remove rich rule
sudo firewall-cmd --zone=public --remove-rich-rule='
rule family="ipv4"
source address="192.168.1.100"
service name="ssh"
accept'
# Query rich rule
sudo firewall-cmd --zone=public --query-rich-rule='
rule family="ipv4"
source address="192.168.1.100"
service name="ssh"
accept'
Direct Rules and Custom Chains
For advanced users who need iptables-like functionality:
Direct Rules
# Add direct rule
sudo firewall-cmd --direct --add-rule ipv4 filter INPUT 0 -p tcp --dport 9000 -j ACCEPT
# Remove direct rule
sudo firewall-cmd --direct --remove-rule ipv4 filter INPUT 0 -p tcp --dport 9000 -j ACCEPT
# List direct rules
sudo firewall-cmd --direct --get-all-rules
# Add custom chain
sudo firewall-cmd --direct --add-chain ipv4 filter CUSTOM_CHAIN
# Add rule to custom chain
sudo firewall-cmd --direct --add-rule ipv4 filter CUSTOM_CHAIN 0 -s 192.168.1.0/24 -j ACCEPT
Direct Configuration File
# Edit direct rules
sudo nano /etc/firewalld/direct.xml
<?xml version="1.0" encoding="utf-8"?>
<direct>
<chain table="filter" ipv="ipv4" chain="CUSTOM_INPUT"/>
<rule priority="0" table="filter" ipv="ipv4" chain="INPUT">-j CUSTOM_INPUT</rule>
<rule priority="0" table="filter" ipv="ipv4" chain="CUSTOM_INPUT">-s 192.168.1.0/24 -j ACCEPT</rule>
</direct>
Network Address Translation (NAT)
Masquerading
# Enable masquerading on zone
sudo firewall-cmd --zone=external --add-masquerade
# Query masquerading status
sudo firewall-cmd --zone=external --query-masquerade
# Remove masquerading
sudo firewall-cmd --zone=external --remove-masquerade
SNAT Configuration
# Source NAT with rich rules
sudo firewall-cmd --zone=external --add-rich-rule='
rule family="ipv4"
source address="192.168.1.0/24"
masquerade'
DNAT Configuration
# Destination NAT (port forwarding)
sudo firewall-cmd --zone=external --add-rich-rule='
rule family="ipv4"
destination address="203.0.113.1"
forward-port port="80" protocol="tcp"
to-port="8080" to-addr="192.168.1.100"'
Complete NAT Example
# Router/Gateway configuration
# External interface: eth0 (public zone)
# Internal interface: eth1 (internal zone)
# Enable IP forwarding
echo "net.ipv4.ip_forward=1" | sudo tee /etc/sysctl.d/99-ip-forward.conf
sudo sysctl -p /etc/sysctl.d/99-ip-forward.conf
# Configure zones
sudo firewall-cmd --permanent --zone=external --add-interface=eth0
sudo firewall-cmd --permanent --zone=internal --add-interface=eth1
# Enable masquerading on external
sudo firewall-cmd --permanent --zone=external --add-masquerade
# Allow internal network services
sudo firewall-cmd --permanent --zone=internal --add-service=dhcp
sudo firewall-cmd --permanent --zone=internal --add-service=dns
# Port forwarding example
sudo firewall-cmd --permanent --zone=external --add-forward-port=port=80:proto=tcp:toport=80:toaddr=192.168.1.100
# Apply configuration
sudo firewall-cmd --reload
Logging and Monitoring
Enable Logging
# Set log denied packets
sudo firewall-cmd --set-log-denied=all
# Options: all, unicast, broadcast, multicast, off
sudo firewall-cmd --get-log-denied
# Enable logging for specific rules
sudo firewall-cmd --zone=public --add-rich-rule='
rule family="ipv4"
source address="10.0.0.0/8"
log prefix="DENIED_10NET" level="info"
drop'
Configure Logging
# Edit firewalld configuration
sudo nano /etc/firewalld/firewalld.conf
# Set logging options
# LogDenied=all
# IndividualCalls=yes
# LogFile=/var/log/firewalld
Monitoring Commands
# Watch firewall logs
sudo journalctl -u firewalld -f
# View denied packets
sudo journalctl -u firewalld | grep DENIED
# Monitor in real-time
sudo tail -f /var/log/firewalld
# Check packet counts
sudo iptables -L -n -v
# Monitor connections
sudo ss -tuln
sudo netstat -tuln
Logging Script
#!/bin/bash
# /usr/local/bin/firewall-monitor.sh
LOG_FILE="/var/log/firewall-monitor.log"
ALERT_EMAIL="[email protected]"
# Function to log messages
log_message() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
}
# Check for denied packets
DENIED_COUNT=$(journalctl -u firewalld --since "5 minutes ago" | grep -c "DENIED")
if [ $DENIED_COUNT -gt 100 ]; then
log_message "WARNING: High number of denied packets: $DENIED_COUNT"
echo "Firewall Alert: $DENIED_COUNT denied packets in last 5 minutes" | mail -s "Firewall Alert" $ALERT_EMAIL
fi
# Check for specific attacks
SSH_ATTACKS=$(journalctl -u firewalld --since "5 minutes ago" | grep -c "DPT=22")
if [ $SSH_ATTACKS -gt 50 ]; then
log_message "WARNING: Possible SSH brute force attack: $SSH_ATTACKS attempts"
fi
# Check firewall service status
if ! systemctl is-active --quiet firewalld; then
log_message "CRITICAL: firewalld service is not running!"
fi
Security Best Practices
1. Default Deny Policy
# Use restrictive default zone
sudo firewall-cmd --set-default-zone=drop
# Only allow specific services
sudo firewall-cmd --permanent --zone=drop --add-service=ssh
sudo firewall-cmd --permanent --zone=drop --add-source=192.168.1.0/24
2. Minimize Open Ports
# Audit open ports
for zone in $(firewall-cmd --get-zones); do
echo "Zone: $zone"
sudo firewall-cmd --zone=$zone --list-ports
sudo firewall-cmd --zone=$zone --list-services
done
# Remove unnecessary services
sudo firewall-cmd --permanent --zone=public --remove-service=cockpit
sudo firewall-cmd --permanent --zone=public --remove-service=dhcpv6-client
3. Use Specific Sources
# Instead of opening SSH to all
# sudo firewall-cmd --zone=public --add-service=ssh
# Restrict to specific networks
sudo firewall-cmd --zone=public --add-rich-rule='
rule family="ipv4"
source address="192.168.1.0/24"
service name="ssh"
accept'
4. Rate Limiting
# Limit SSH connections
sudo firewall-cmd --permanent --zone=public --add-rich-rule='
rule family="ipv4"
service name="ssh"
limit value="3/m"
accept'
# Limit HTTP connections
sudo firewall-cmd --permanent --zone=public --add-rich-rule='
rule family="ipv4"
service name="http"
limit value="100/s"
accept'
5. Implement Fail2ban
# Install fail2ban
sudo dnf install -y fail2ban
# Configure for firewalld
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo nano /etc/fail2ban/jail.local
# Set banaction to firewalld
# banaction = firewallcmd-ipset
# Start fail2ban
sudo systemctl enable --now fail2ban
6. Regular Auditing
#!/bin/bash
# /usr/local/bin/firewall-audit.sh
echo "=== Firewall Audit Report ==="
echo "Date: $(date)"
echo
echo "=== Active Zones ==="
firewall-cmd --get-active-zones
echo -e "\n=== Zone Configurations ==="
for zone in $(firewall-cmd --get-zones); do
echo -e "\nZone: $zone"
firewall-cmd --zone=$zone --list-all
done
echo -e "\n=== Direct Rules ==="
firewall-cmd --direct --get-all-rules
echo -e "\n=== Rich Rules ==="
for zone in $(firewall-cmd --get-zones); do
rules=$(firewall-cmd --zone=$zone --list-rich-rules)
if [ -n "$rules" ]; then
echo "Zone $zone:"
echo "$rules"
fi
done
echo -e "\n=== Potential Issues ==="
# Check for permissive zones
if firewall-cmd --get-default-zone | grep -q "trusted"; then
echo "WARNING: Default zone is set to 'trusted'"
fi
# Check for any allow-all rules
if firewall-cmd --direct --get-all-rules | grep -q "ACCEPT"; then
echo "WARNING: Direct ACCEPT rules found"
fi
Troubleshooting Common Issues
Service Not Accessible
# Verify firewall is running
sudo firewall-cmd --state
# Check if service/port is open
sudo firewall-cmd --list-all
# Check specific zone
sudo firewall-cmd --zone=public --list-all
# Verify runtime vs permanent
sudo firewall-cmd --list-all
sudo firewall-cmd --permanent --list-all
# Test from outside
telnet server_ip port
nc -zv server_ip port
Configuration Not Persisting
# Ensure permanent flag is used
sudo firewall-cmd --permanent --add-service=http
# Or save runtime to permanent
sudo firewall-cmd --runtime-to-permanent
# Verify permanent configuration
sudo firewall-cmd --permanent --list-all
# Check configuration files
ls -la /etc/firewalld/zones/
Zone Assignment Issues
# Check interface zone assignment
sudo firewall-cmd --get-zone-of-interface=eth0
# Force zone assignment
sudo firewall-cmd --permanent --zone=public --change-interface=eth0
sudo firewall-cmd --reload
# Check NetworkManager interference
nmcli connection show
nmcli connection modify "System eth0" connection.zone public
Debugging Steps
# Enable debug logging
sudo firewall-cmd --set-log-denied=all
# Check logs
sudo journalctl -u firewalld -f
# Test with verbose output
sudo firewall-cmd --reload --debug
# Check iptables rules directly
sudo iptables -L -n -v
sudo ip6tables -L -n -v
# Verify nftables (if backend)
sudo nft list ruleset
Recovery Procedures
# If locked out, boot in emergency mode
# Add to kernel parameters: systemd.unit=emergency.target
# Disable firewalld temporarily
systemctl stop firewalld
systemctl disable firewalld
# Reset to defaults
sudo rm -rf /etc/firewalld/zones/*
sudo rm -rf /etc/firewalld/services/*
sudo firewall-cmd --reload
# Restore from backup
sudo cp -r /root/firewalld-backup/* /etc/firewalld/
sudo firewall-cmd --reload
Advanced Configurations
High Availability Firewall
# Configure connection tracking sync
sudo dnf install -y conntrack-tools
# Master node configuration
cat > /etc/conntrackd/conntrackd.conf << EOF
Sync {
Mode FTFW {
ResendQueueSize 131072
PurgeTimeout 60
}
Multicast {
IPv4_address 225.0.0.50
Group 3780
IPv4_interface 192.168.1.1
Interface eth1
SndSocketBuffer 1249280
RcvSocketBuffer 1249280
Checksum on
}
}
EOF
GeoIP Blocking
# Install GeoIP database
sudo dnf install -y geoipupdate
# Create update script
cat > /usr/local/bin/geoip-block.sh << 'EOF'
#!/bin/bash
# Block specific countries
COUNTRIES="CN RU KP" # China, Russia, North Korea
for country in $COUNTRIES; do
for ip in $(geoiplookup -f /usr/share/GeoIP/GeoIP.dat -i $country | awk '{print $2}'); do
firewall-cmd --permanent --zone=drop --add-source=$ip
done
done
firewall-cmd --reload
EOF
chmod +x /usr/local/bin/geoip-block.sh
DDoS Protection
# Rate limiting rules
# Limit new connections
sudo firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 \
-p tcp -m conntrack --ctstate NEW -m limit --limit 60/second --limit-burst 20 -j ACCEPT
# Drop excessive connections
sudo firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 1 \
-p tcp -m conntrack --ctstate NEW -j DROP
# SYN flood protection
sudo sysctl -w net.ipv4.tcp_syncookies=1
echo "net.ipv4.tcp_syncookies=1" >> /etc/sysctl.conf
Conclusion
firewalld provides a powerful and flexible firewall solution for Rocky Linux systems. Key takeaways:
- Use zones to manage different trust levels
- Leverage predefined services when possible
- Implement rich rules for complex requirements
- Always test runtime before making permanent
- Regular audit firewall configurations
- Monitor logs for security events
- Follow the principle of least privilege
- Document your firewall rules
Remember that a properly configured firewall is essential for system security, but it’s just one layer of defense. Combine firewalld with other security measures like SELinux, intrusion detection systems, and regular security updates for comprehensive protection.