How to Set Up a Firewall on Your Web Server: Complete Guide
Your server is scanned by bots within minutes of going online. A properly configured firewall is the first (and most critical ) line of defense. This guide covers UFW, firewalld, iptables, Fail2Ban, and WAF configuration with production-ready commands.

Web hosting enthusiast who tests providers and breaks down features, pricing, and real world speed

Quick Setup Summary
Ubuntu/Debian Servers
Use UFW: simplest setup, 3 commands to secure your server. Best for single-server deployments.
CentOS/RHEL Servers
Use firewalld: zone-based architecture with runtime/permanent rule separation. Enterprise-ready.
Advanced Users
Use iptables/nftables directly for granular control. Required for complex multi-service architectures.
Cloud Servers
Layer cloud firewalls (Security Groups, VPC rules) with host-based firewalls for defense-in-depth.
What Is a Server Firewall?
A firewall is a network security system that monitors and controls incoming and outgoing traffic based on predefined rules. On a web server, it acts as a gatekeeper, deciding which connections are allowed and which are blocked.
Without a firewall, every service running on your server is exposed to the internet. A single unpatched service on an open port is all an attacker needs. In 2025, the average unprotected server was compromised within 39 minutes of going online.
| Threat Type | Without Firewall | With Firewall |
|---|---|---|
| SSH Brute Force | Thousands of attempts/day | Blocked after 3 failures |
| Port Scanning | All ports visible | Only 80/443 exposed |
| DDoS Floods | Server overwhelmed | Rate-limited and filtered |
| Service Exploits | All services reachable | Only web traffic allowed |
| Data Exfiltration | Unrestricted outbound | Outbound rules limit egress |
Types of Firewalls
Server security uses multiple firewall layers. Understanding each type helps you build a complete defense strategy.
Packet Filter (iptables/nftables)
Inspects individual packets at the network layer. Fastest but least context-aware. The foundation of Linux firewalling.
Stateful Firewall (UFW/firewalld)
Tracks connection state, knows if a packet is part of an established session. Smarter than packet filtering alone.
Application Firewall (WAF)
Inspects HTTP requests for SQL injection, XSS, and application-layer attacks. Essential for web servers.
Cloud Firewall (Security Groups)
Provider-level filtering before traffic reaches your server. Zero server CPU overhead. First line of defense.
UFW Setup (Ubuntu/Debian)
UFW (Uncomplicated Firewall) is the recommended firewall for Ubuntu and Debian servers. It wraps iptables in a human-friendly interface without sacrificing power.
Step 1: Install and configure UFW
# Install UFW (usually pre-installed on Ubuntu) sudo apt update && sudo apt install ufw -y # Set default policies, deny incoming, allow outgoing sudo ufw default deny incoming sudo ufw default allow outgoing # Allow SSH BEFORE enabling (critical, don't lock yourself out!) sudo ufw allow 22/tcp comment 'SSH access' # Allow web traffic sudo ufw allow 80/tcp comment 'HTTP' sudo ufw allow 443/tcp comment 'HTTPS' # Enable the firewall sudo ufw enable # Verify rules sudo ufw status verbose
Step 2: Advanced UFW rules
# Allow SSH only from your IP (replace with your IP) sudo ufw allow from 203.0.113.50 to any port 22 proto tcp # Rate-limit SSH to prevent brute force (6 connections/30s) sudo ufw limit 22/tcp # Allow a specific subnet (office network) sudo ufw allow from 10.0.0.0/24 to any port 3306 comment 'MySQL from office' # Deny a specific IP sudo ufw deny from 192.168.1.100 # Delete a rule by number sudo ufw status numbered sudo ufw delete 3 # Enable logging sudo ufw logging on
Warning: Always allow SSH before enabling UFW. If you enable the firewall without an SSH rule, you will be locked out of your server. Recovery requires console access from your hosting provider.
Firewalld Setup (CentOS/RHEL/AlmaLinux)
Firewalld uses a zone-based model that separates runtime rules (lost on reboot) from permanent rules. It's the default on RHEL-based distributions.
# Install firewalld (usually pre-installed) sudo dnf install firewalld -y # Start and enable sudo systemctl start firewalld sudo systemctl enable firewalld # Check default zone sudo firewall-cmd --get-default-zone # Allow web services (permanent) sudo firewall-cmd --permanent --add-service=http sudo firewall-cmd --permanent --add-service=https sudo firewall-cmd --permanent --add-service=ssh # Remove unnecessary services sudo firewall-cmd --permanent --remove-service=dhcpv6-client sudo firewall-cmd --permanent --remove-service=cockpit # Allow custom port sudo firewall-cmd --permanent --add-port=8443/tcp # Restrict SSH to specific IP sudo firewall-cmd --permanent --add-rich-rule=' rule family="ipv4" source address="203.0.113.50/32" service name="ssh" accept' # Apply changes sudo firewall-cmd --reload # Verify active rules sudo firewall-cmd --list-all
| Feature | UFW | firewalld |
|---|---|---|
| Distribution | Ubuntu/Debian | CentOS/RHEL/Alma |
| Architecture | Flat rule list | Zone-based |
| Runtime vs Permanent | All rules persist | Separate concepts |
| Learning Curve | Very low | Moderate |
| Rich Rules | Limited | Full support |
| Best For | Single-server setups | Enterprise environments |
iptables Deep Dive
iptables is the underlying packet filtering framework in Linux. While UFW and firewalld are easier, understanding iptables gives you complete control and is essential for debugging.
Production-ready iptables ruleset
#!/bin/bash # Flush existing rules iptables -F iptables -X # Default policies: drop incoming, allow outgoing iptables -P INPUT DROP iptables -P FORWARD DROP iptables -P OUTPUT ACCEPT # Allow loopback iptables -A INPUT -i lo -j ACCEPT iptables -A OUTPUT -o lo -j ACCEPT # Allow established connections iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT # Allow SSH (rate-limited) iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW \ -m recent --set --name SSH iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW \ -m recent --update --seconds 60 --hitcount 4 --name SSH -j DROP iptables -A INPUT -p tcp --dport 22 -j ACCEPT # Allow HTTP and HTTPS iptables -A INPUT -p tcp --dport 80 -j ACCEPT iptables -A INPUT -p tcp --dport 443 -j ACCEPT # Allow ICMP (ping), rate-limited iptables -A INPUT -p icmp --icmp-type echo-request \ -m limit --limit 1/s --limit-burst 4 -j ACCEPT # Drop invalid packets iptables -A INPUT -m conntrack --ctstate INVALID -j DROP # Log dropped packets (last 5/min to avoid log flooding) iptables -A INPUT -m limit --limit 5/min -j LOG \ --log-prefix "iptables-dropped: " --log-level 4 # Save rules (Debian/Ubuntu) iptables-save > /etc/iptables/rules.v4
Note: Modern Linux distributions are migrating from iptables to nftables. The syntax differs, but concepts are identical. Ubuntu 22.04+ uses nftables as the default backend, even when you use UFW.
Fail2Ban: Automatically Block Attackers
Fail2Ban monitors log files for signs of brute-force attacks and automatically creates firewall rules to block offending IPs. It's essential for any internet-facing server.
Install and configure Fail2Ban
# Install Fail2Ban sudo apt install fail2ban -y # Debian/Ubuntu sudo dnf install fail2ban -y # CentOS/RHEL # Create local config (never edit jail.conf directly) sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local # Edit jail.local sudo nano /etc/fail2ban/jail.local
/etc/fail2ban/jail.local, recommended settings
[DEFAULT] bantime = 3600 # Ban for 1 hour findtime = 600 # Within 10-minute window maxretry = 3 # After 3 failures banaction = ufw # Use UFW for banning (or iptables-multiport) # Whitelist your own IP ignoreip = 127.0.0.1/8 ::1 203.0.113.50 [sshd] enabled = true port = ssh logpath = /var/log/auth.log # Debian/Ubuntu # logpath = /var/log/secure # CentOS/RHEL maxretry = 3 [nginx-http-auth] enabled = true port = http,https logpath = /var/log/nginx/error.log [nginx-botsearch] enabled = true port = http,https logpath = /var/log/nginx/access.log maxretry = 2 [nginx-limit-req] enabled = true port = http,https logpath = /var/log/nginx/error.log
Managing Fail2Ban
# Start and enable sudo systemctl start fail2ban sudo systemctl enable fail2ban # Check status of all jails sudo fail2ban-client status # Check specific jail sudo fail2ban-client status sshd # Unban an IP sudo fail2ban-client set sshd unbanip 192.168.1.100 # Test regex against log file sudo fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf
Web Application Firewall (WAF)
Network firewalls control which ports are open. A WAF controls what passes through those ports, inspecting HTTP requests for SQL injection, cross-site scripting, and other application attacks.
| WAF Solution | Type | Price | Best For |
|---|---|---|---|
| ModSecurity + OWASP CRS | Self-hosted | Free | Nginx/Apache servers |
| Cloudflare WAF | Cloud proxy | Free: $200/mo | Any website |
| AWS WAF | Cloud-native | $5/mo + rules | AWS-hosted apps |
| Sucuri | Cloud proxy | $199/yr | WordPress sites |
| Imperva (Incapsula) | Enterprise | $59+/mo | High-traffic sites |
Install ModSecurity with Nginx
# Install ModSecurity for Nginx (Ubuntu 22.04+) sudo apt install libmodsecurity3 libmodsecurity-dev \ libnginx-mod-http-modsecurity -y # Download OWASP Core Rule Set cd /etc/nginx/modsec sudo git clone https://github.com/coreruleset/coreruleset.git sudo cp coreruleset/crs-setup.conf.example crs-setup.conf # Enable in nginx.conf # Add inside server block: modsecurity on; modsecurity_rules_file /etc/nginx/modsec/main.conf; # Test and reload sudo nginx -t && sudo systemctl reload nginx
Cloud Provider Firewalls
Cloud firewalls filter traffic at the network edge before it reaches your server, consuming zero server resources. Always use them alongside host-based firewalls.
| Provider | Feature Name | Stateful? | Cost |
|---|---|---|---|
| AWS | Security Groups + NACLs | SG: Yes, NACL: No | Free |
| DigitalOcean | Cloud Firewalls | Yes | Free |
| Vultr | Firewall Groups | Yes | Free |
| Linode/Akamai | Cloud Firewalls | Yes | Free |
| Hetzner | Firewalls | Yes | Free |
| Google Cloud | VPC Firewall Rules | Yes | Free |
Pro tip: Configure your cloud firewall to only allow ports 80, 443, and SSH (from your IP). Then use UFW/firewalld on the server as a second layer. If either fails, the other still protects you.
Port Management Best Practices
The fewer ports you expose, the smaller your attack surface. Here's a reference for common services and whether they should face the internet.
| Port | Service | Public? | Recommendation |
|---|---|---|---|
| 22 | SSH | Limited | Restrict to your IP or VPN only |
| 80 | HTTP | Yes | Open, redirects to HTTPS |
| 443 | HTTPS | Yes | Open, primary web traffic |
| 3306 | MySQL | No | Bind to 127.0.0.1 or private network |
| 5432 | PostgreSQL | No | Bind to 127.0.0.1 or private network |
| 6379 | Redis | No | Bind to 127.0.0.1, never expose |
| 27017 | MongoDB | No | Bind to 127.0.0.1, critical risk |
| 8080 | Dev/Admin | No | Close or restrict to VPN |
| 9090 | Monitoring | No | Access via SSH tunnel only |
Scan your server for open ports
# From another machine, scan your server nmap -sV your-server-ip # Check listening ports from the server itself sudo ss -tlnp # or sudo netstat -tlnp
Outbound Filtering
Most guides focus on inbound rules, but outbound filtering prevents compromised servers from connecting to attacker-controlled infrastructure, blocking data exfiltration and reverse shells.
Restrict outbound traffic (iptables)
# Allow DNS lookups iptables -A OUTPUT -p udp --dport 53 -j ACCEPT iptables -A OUTPUT -p tcp --dport 53 -j ACCEPT # Allow HTTP/HTTPS (for package updates, API calls) iptables -A OUTPUT -p tcp --dport 80 -j ACCEPT iptables -A OUTPUT -p tcp --dport 443 -j ACCEPT # Allow SMTP (if server sends email) iptables -A OUTPUT -p tcp --dport 587 -j ACCEPT # Allow NTP (time synchronization) iptables -A OUTPUT -p udp --dport 123 -j ACCEPT # Allow established connections iptables -A OUTPUT -m conntrack --ctstate ESTABLISHED -j ACCEPT # Drop everything else iptables -P OUTPUT DROP
Caution: Strict outbound filtering can break legitimate services. Test thoroughly in a staging environment before applying to production. Start with logging mode to identify what your server normally connects to.
Logging & Monitoring
A firewall without logging is flying blind. You need visibility into blocked traffic to detect attack patterns and tune your rules.
# UFW logging levels
sudo ufw logging low # Log blocked packets only
sudo ufw logging medium # Log blocked + rate-limited
sudo ufw logging high # Log everything (generates large logs)
# View UFW logs
sudo tail -f /var/log/ufw.log
sudo grep "UFW BLOCK" /var/log/ufw.log | tail -20
# firewalld logging
sudo firewall-cmd --set-log-denied=all # Log all denied traffic
# View firewalld logs
sudo journalctl -u firewalld -f
# Count blocked IPs (top offenders)
grep "UFW BLOCK" /var/log/ufw.log | \
awk '{for(i=1;i<=NF;i++) if($i ~ /SRC=/) print $i}' | \
sort | uniq -c | sort -rn | head -20Grafana + Loki
Visualize firewall logs with dashboards and alerts
CrowdSec
Community-driven threat intelligence with auto-banning
OSSEC / Wazuh
Full HIDS with log analysis and real-time alerting
Common Mistakes to Avoid
❌ Enabling the firewall before allowing SSH
✅ Always run 'ufw allow 22/tcp' before 'ufw enable'. Test SSH in a second terminal before closing your current session.
❌ Leaving database ports open to the internet
✅ Bind MySQL/PostgreSQL/Redis to 127.0.0.1 in their configs. Use SSH tunnels or private networks for remote access.
❌ Using only a cloud firewall without host-based firewall
✅ Cloud firewalls can be misconfigured through the API. Host-based firewalls provide a second layer that requires server access to change.
❌ Never reviewing or auditing rules
✅ Schedule monthly rule audits. Run 'nmap' against your server quarterly. Remove rules for decommissioned services.
❌ Not rate-limiting SSH connections
✅ Use 'ufw limit 22/tcp' or Fail2Ban. Without rate-limiting, bots will try thousands of passwords per hour.
❌ Forgetting IPv6
✅ Ensure your firewall rules apply to both IPv4 and IPv6. UFW handles this automatically; iptables requires separate ip6tables rules.
❌ Blocking ICMP entirely
✅ Allow ICMP echo-request (ping) with rate-limiting. Blocking all ICMP breaks path MTU discovery and network diagnostics.
Firewall Security Checklist
| Action | Priority | Tool |
|---|---|---|
| Set default deny incoming policy | Critical | UFW / firewalld |
| Allow only ports 22, 80, 443 | Critical | UFW / firewalld |
| Restrict SSH to known IPs | Critical | UFW / cloud firewall |
| Install and configure Fail2Ban | Critical | Fail2Ban |
| Enable cloud provider firewall | High | AWS / DO / Vultr |
| Bind databases to localhost | High | MySQL / PostgreSQL config |
| Enable firewall logging | High | UFW / iptables |
| Install WAF (ModSecurity or Cloudflare) | High | ModSecurity / Cloudflare |
| Scan for open ports (nmap) | High | nmap |
| Configure outbound rules | Medium | iptables |
| Set up log monitoring / alerts | Medium | Grafana / CrowdSec |
| Disable IPv6 if not used | Medium | sysctl / UFW |
| Review and audit rules monthly | Medium | Manual |
| Document all firewall rules | Medium | Wiki / README |
| Test firewall after changes | Low | nmap / curl |
Frequently Asked Questions
What ports should I keep open on a web server?
What's the difference between UFW and iptables?
Should I use a host-based or cloud firewall?
How do I protect against brute-force SSH attacks?
Can a firewall slow down my website?
What is a WAF and do I need one?
How often should I review firewall rules?
Does Fail2Ban work with UFW?
Need Hosting With Built-In Firewall Protection?
Many managed hosting providers include pre-configured firewalls, DDoS protection, and WAF rules. Find the right one for your needs.
Find Secure Hosting