Using firewalld Zones and Rich Rules to Secure a Web Server on CentOS 7
Learn how to use firewalld zones and rich rules on CentOS 7 to allow HTTP only from a trusted subnet, test with time‑out rules, and make the changes permanent.
08 Mar 2026, 21:38 UTC

Problem: Need granular HTTP access without disrupting existing firewall
You run a CentOS 7 web server that must accept HTTP requests only from a trusted subnet (e.g., 192.168.10.0/24). All other Internet traffic to port 80 should be blocked. The default public zone already allows the http service for everyone, so you need a more specific rule while keeping the rest of the firewall intact.
Thesis: firewalld’s zone model and rich‑rule language let you define precise, runtime‑testable policies that can be made permanent without a full firewall restart.
1. Zones give you a baseline trust level
firewalld organizes interfaces and sources into zones. Each zone has its own set of services and ports. The public zone is typically assigned to externally facing NICs and, by default, permits ssh, dhcpv6-client, and http.
To see what the zone currently allows:
# Run as root or with sudo
firewall-cmd --zone=public --list-all
You will see services: ssh dhcpv6-client http listed.
2. Test a temporary rich rule for the trusted subnet
A rich rule lets you match source addresses, ports, protocols, and actions in a single command. Add it with the --timeout flag so it disappears automatically after a set period—ideal for validation.
# Temporary rule: accept TCP 80 from 192.168.10.0/24 in the public zone
firewall-cmd --zone=public \
--add-rich-rule='rule family="ipv4" source address="192.168.10.0/24" \
port protocol="tcp" port="80" accept' \
--timeout=120
This command takes effect immediately. No service reload is needed.
Check that the rule is active:
firewall-cmd --zone=public --list-rich-rules
You should see the rule you just added.
Now verify connectivity:
- From a host inside 192.168.10.0/24:
curl http://<server_ip>should return the web page. - From a host outside that subnet: the request should time out or be refused.
After 120 seconds the rule vanishes automatically; you can confirm with --list-rich-rules again.
3. Make the rule permanent
Once testing succeeds, drop the --timeout flag and add --permanent. Then reload firewalld to apply the permanent XML.
# Make the same rule permanent
firewall-cmd --zone=public \
--add-rich-rule='rule family="ipv4" source address="192.168.10.0/24" \
port protocol="tcp" port="80" accept' \
--permanent
Reload to merge runtime and permanent settings:
firewall-cmd --reload
Verify persistence:
firewall-cmd --zone=public --list-rich-rules
The rule should remain listed even after a reboot.
4. Trade‑offs and limitations
- Learning curve: The zone‑centric syntax differs from legacy
iptablescommands; administrators must adapt to rich‑rule formatting. - Feature gaps: Some complex NAT helpers that existed in
iptablesextensions have no direct rich‑rule equivalent. In those cases you can fall back to firewalld’sdirectinterface or keep theiptablesservice alongside firewalld. - Runtime vs permanent confusion: Using only
--runtime(or omitting--permanent) means the rule disappears after a reload or reboot, which can cause unexpected connectivity loss. - Verification: Always check both runtime (
--list-all) and permanent (--permanent --list-all) sets, and confirm withsystemctl status firewalldthat the daemon is active.
Actionable closing
For CentOS 7 systems where firewalld is the default, start by defining the appropriate zone for your interface, test granular access with timed rich rules, and then commit them permanently. Keep the verification steps handy—firewall-cmd --list-rich-rules and systemctl status firewalld—to ensure your policies survive reloads and reboots. When a required feature isn’t expressible in rich rules, consider the direct interface as a controlled fallback rather than disabling firewalld entirely.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.