How to Configure a Firewall for Apache

How to configure a firewall for Apache

The first time I put a fresh Apache server on the public internet without touching the firewall, I watched the access logs fill up with scanner traffic within minutes. Bots were probing for open ports, poking at admin paths, and trying default credentials before I’d even finished installing my first virtual host. That experience taught me something I now treat as non-negotiable: a firewall isn’t an optional extra for an Apache deployment, it’s step one.

In this post I’m walking through how I configure a firewall for Apache, covering firewalld, ufw, and raw iptables/nftables, so you can pick whichever fits your distribution and comfort level.

What a Firewall Actually Does for a Web Server

A firewall filters packets based on rules I define — deciding what’s allowed to reach the machine and what gets dropped before it ever touches Apache. For a web server, I keep the job narrow on purpose:

  • Allow inbound traffic on the ports Apache is actually listening on (usually 80 for HTTP and 443 for HTTPS).
  • Allow the administrative access I need to manage the box (SSH on port 22, ideally locked to known IPs).
  • Block everything else, including any service running on the machine that shouldn’t be internet-facing.

Without this filtering, every service on the box — even ones I forgot I installed — is potentially reachable from anywhere.

Prerequisites

Before I touch any firewall rules, I make sure I have:

  • A Linux server with Apache installed (or about to be)
  • Root or sudo access
  • A clear idea of which ports my applications actually need

I always confirm Apache’s listening ports first:

sudo apachectl -S
sudo ss -tulnp | grep apache2

Real-World Use Cases I’ve Run Into

  • A public production web server where I only want 80/443/22 reachable, nothing else.
  • An internal staging box I restrict to my office or VPN IP range.
  • A multi-service host where Apache shares the machine with a database that should never be internet-facing.
  • Compliance work, where PCI-DSS and similar standards explicitly require a host-based firewall.

Configuring firewalld (RHEL, CentOS, Fedora, AlmaLinux, Rocky Linux)

firewalld uses “zones” and predefined “services” mapped to specific ports, which I find easier to reason about than raw port numbers once I got used to it.

Checking status

sudo systemctl status firewalld
sudo firewall-cmd --state

Allowing HTTP and HTTPS

sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload

Verifying

sudo firewall-cmd --list-services
sudo firewall-cmd --list-all

Restricting SSH to a specific IP range

sudo firewall-cmd --permanent --remove-service=ssh
sudo firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="203.0.113.0/24" service name="ssh" accept'
sudo firewall-cmd --reload

Allowing a custom port

If I’ve got an app server sitting behind a reverse proxy:

sudo firewall-cmd --permanent --add-port=8080/tcp
sudo firewall-cmd --reload

Configuring UFW (Ubuntu, Debian)

UFW is the front end I reach for on Debian-based boxes — “Uncomplicated Firewall” really does live up to the name.

Setting sensible defaults

sudo ufw default deny incoming
sudo ufw default allow outgoing

Allowing SSH before enabling UFW — I never skip this

sudo ufw allow OpenSSH
# or explicitly:
sudo ufw allow 22/tcp

I’ve locked myself out of a remote box exactly once by forgetting this step, and once was enough to make it a permanent habit.

Allowing Apache traffic

UFW auto-detects Apache’s application profile once Apache is installed:

sudo ufw app list
sudo ufw allow 'Apache Full'   # allows both 80 and 443

If I only want HTTP for the moment:

sudo ufw allow 'Apache'        # port 80 only

Enabling the firewall

sudo ufw enable
sudo ufw status verbose

Restricting by IP

sudo ufw allow from 203.0.113.10 to any port 22 proto tcp

Configuring iptables / nftables Directly

When I want full manual control, or I’m teaching someone the fundamentals, I drop down to raw iptables:

# Flush existing rules (be careful on a live server)
sudo iptables -F

# Allow loopback
sudo iptables -A INPUT -i lo -j ACCEPT

# Allow established/related connections
sudo iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# Allow SSH
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT

# Allow HTTP/HTTPS
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# Drop everything else
sudo iptables -A INPUT -j DROP

I persist the rules on Debian/Ubuntu like this:

sudo apt install iptables-persistent
sudo netfilter-persistent save

Newer systems are shifting to nftables as the default backend — same logic, different syntax (nft add rule inet filter input tcp dport {80,443} accept), and I expect to lean on it more going forward.

Rate Limiting and Brute-Force Protection

I also use the firewall to throttle abusive traffic before it ever reaches Apache:

# iptables: limit new connections to port 80 to 25/minute per IP
sudo iptables -A INPUT -p tcp --dport 80 -m state --state NEW -m recent --set
sudo iptables -A INPUT -p tcp --dport 80 -m state --state NEW -m recent --update --seconds 60 --hitcount 25 -j DROP

For SSH specifically, I pair firewall rules with fail2ban, which reads logs and dynamically bans IPs showing malicious patterns.

Mistakes I’ve Made (So You Don’t Have To)

  • Enabling the firewall without allowing SSH first — locks you out fast.
  • Forgetting to open 443 after adding an SSL certificate, so HTTPS silently fails while HTTP keeps working.
  • Leaving default database ports open to the public internet when the database only ever needs local access.
  • Not persisting iptables rules, so a reboot wipes out protection I thought was permanent.
  • Confusing firewall rules with SELinux/AppArmor — a firewall controls network access; SELinux/AppArmor controls what a process can do once traffic gets through. I need both.

Security Best Practices I Follow

  • Least privilege: only open the ports I actually need.
  • Default deny on inbound traffic, with explicit exceptions.
  • Pair firewall rules with fail2ban for dynamic banning.
  • If Apache sits behind a load balancer, I restrict direct access to Apache’s port and only allow the proxy’s IP.
  • Regular port audits with ss -tulnp or nmap from an external host.
  • Log dropped packets for forensic visibility, without going overboard and filling the disk.

Performance Considerations

Every packet gets evaluated against the rule set, so I:

  • Keep rules as short and specific as possible.
  • Put the most frequently matched rules (like established connections) near the top of the chain.
  • Watch connection tracking memory usage — overly aggressive state tracking can exhaust kernel memory under DDoS conditions.
  • For very high-traffic sites, I offload filtering to a cloud provider’s network firewall or a CDN/WAF in front of Apache, taking pressure off the origin’s own firewall.

Troubleshooting

Website unreachable after enabling the firewall

sudo firewall-cmd --list-all      # or
sudo ufw status verbose

I check that 80/443 are explicitly allowed.

SSH connection refused after firewall changes If I still have an active session, I don’t close it until I’ve verified SSH access with a fresh connection in a separate terminal.

Firewall rules disappear after reboot I make sure firewalld or ufw are enabled at boot:

sudo systemctl enable firewalld
sudo systemctl enable ufw

FAQs

Do I need a firewall if my server is already behind a cloud provider’s security group? Yes. Cloud security groups filter traffic at the network edge, but a host-based firewall gives me defense in depth in case the security group gets misconfigured or the server moves.

Will a firewall slow down my website? Properly configured rules add negligible latency in my experience. Performance issues usually come from overly complex rule chains, not firewalls in general.

Can a firewall stop DDoS attacks? A host-based firewall mitigates small-scale abuse but can’t stop large volumetric DDoS — that requires upstream protection from an ISP, cloud provider, or dedicated mitigation service.

Should I block all countries except my own? Geo-blocking can cut down noise, but I never treat it as a substitute for proper firewall and application security, since attackers can route through allowed regions.

Summary and Key Takeaways

  • A firewall is the first layer of defense I set up on any Apache deployment.
  • firewalld and ufw give me accessible, service-aware management on RHEL-based and Debian-based systems; iptables/nftables give me full manual control.
  • I always allow SSH before enabling a restrictive firewall.
  • I combine firewall rules with fail2ban, SELinux/AppArmor, and application-level hardening.
  • I audit open ports regularly and persist rules across reboots.

References

  • Apache HTTP Server Documentation: https://httpd.apache.org/docs/
  • firewalld Documentation: https://firewalld.org/documentation/
  • UFW Documentation (Ubuntu): https://help.ubuntu.com/community/UFW
  • Netfilter/iptables Project: https://www.netfilter.org/documentation/
  • fail2ban Documentation: https://www.fail2ban.org/
Total
0
Shares

Leave a Reply

Previous Post
How to secure your Apache Web Server

How to Secure Your Apache Web Server

Next Post
How to prevent directory listing in Apache

How to Prevent Directory Listing in Apache

Related Posts