Skip to content

🛡️ firewalld (CentOS/RHEL Firewall)

What is firewalld?

firewalld introduces the concept of "Zones" — imagine your server has different "faces" depending on the setting: at home (trusted zone) everything is allowed, at a coffee shop (public zone) only essential ports are open, at the office (work zone) work-related services are available.

Zones

ZoneDefault BehaviorUse Case
dropDrop all inboundHighest security level
blockReject all inbound (returns ICMP reject)Similar to drop, but notifies the sender
publicDefault zone, only allows selected servicesPublic-facing servers
externalEnables masquerading (MASQUERADE)Routers/gateways
workAllows common office servicesOffice networks
homeTrusts most inboundHome networks
trustedAllows all inboundFully trusted networks

Basic Management

bash
# Start and enable on boot
sudo systemctl start firewalld
sudo systemctl enable firewalld

# Check status
sudo firewall-cmd --state
running

# View default zone
sudo firewall-cmd --get-default-zone
public

# View all zones
sudo firewall-cmd --get-zones
block dmz drop external home internal public trusted work

# View current zone rules
sudo firewall-cmd --list-all
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: eth0
  sources:
  services: dhcpv6-client ssh
  ports:
  protocols:
  masquerade: no
  forward-ports:
  rich rules:

# View rules for all zones
sudo firewall-cmd --list-all-zones

Service and Port Management

bash
# View available services list
sudo firewall-cmd --get-services
RH-Satellite-6 amanda-client amanda-k5-client bacula
bacula-client bitcoin bitcoin-rpc ... ssh dhcpv6-client
http https mysql postgresql redis ...

# Add service (runtime, not persistent)
sudo firewall-cmd --add-service=http
sudo firewall-cmd --add-service=https

# Add port
sudo firewall-cmd --add-port=8080/tcp
sudo firewall-cmd --add-port=3000-4000/tcp    # Port range

# Add permanently (persists after reboot)
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --permanent --add-port=8080/tcp

# Reload to apply permanent rules
sudo firewall-cmd --reload

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

# View currently active rules (runtime)
sudo firewall-cmd --list-services
dhcpv6-client http https ssh

sudo firewall-cmd --list-ports
8080/tcp

⚠️ Warning: ⚠️ Runtime vs Permanent: --add-service only applies to the current session (lost after reboot). Adding --permanent makes it persist. After adding --permanent, you need --reload to take effect.

Rich Rules

Rich Rules are firewalld's advanced syntax that enable more granular control.

bash
# Allow only a specific IP to access SSH
sudo firewall-cmd --permanent --add-rich-rule='
  rule family="ipv4"
  source address="192.168.1.100"
  port protocol="tcp" port="22"
  accept'

# Rate limiting (max 10 new SSH connections per minute)
sudo firewall-cmd --permanent --add-rich-rule='
  rule family="ipv4"
  port protocol="tcp" port="22"
  accept
  limit value="10/m"'

# Deny a specific IP
sudo firewall-cmd --permanent --add-rich-rule='
  rule family="ipv4"
  source address="10.0.0.50"
  drop'

# Allow a specific subnet to access MySQL
sudo firewall-cmd --permanent --add-rich-rule='
  rule family="ipv4"
  source address="192.168.1.0/24"
  port protocol="tcp" port="3306"
  accept'

# View all rich rules
sudo firewall-cmd --list-rich-rules

# Delete a rich rule
sudo firewall-cmd --permanent --remove-rich-rule='
  rule family="ipv4"
  source address="10.0.0.50"
  drop'

sudo firewall-cmd --reload

Direct Rules

bash
# Directly insert iptables rules (firewalld's backdoor)
sudo firewall-cmd --direct --add-rule ipv4 filter INPUT 0 \
  -p tcp --dport 9090 -j ACCEPT

# View direct rules
sudo firewall-cmd --direct --get-all-rules

# Make permanent
sudo firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 0 \
  -p tcp --dport 9090 -j ACCEPT
sudo firewall-cmd --reload

📝 Note: 📝 When to use Direct Rules? When firewalld's rich rules can't meet your needs (e.g., complex iptables rules), you can use direct rules to operate the underlying iptables directly.

Zone Binding

bash
# Bind a network interface to a zone
sudo firewall-cmd --permanent --zone=public --change-interface=eth0

# Bind an IP to a zone
sudo firewall-cmd --permanent --zone=trusted --add-source=192.168.1.100

# View which zone each interface is in
sudo firewall-cmd --get-active-zones
public
  interfaces: eth0 eth1