UFW Firewall on Ubuntu/Debian: Easy Setup, Instant Security
UFW (Uncomplicated Firewall) is a front-end to iptables that comes ready to use on Ubuntu and Debian without needing to memorize complex iptables syntax. With just a few simple commands, you can lock down your VPS by preventing unnecessary ports from staying open and block brute-force attacks at the Firewall level before traffic even reaches your applications.
How Do UFW and iptables Differ?
iptables is powerful kernel-level packet filtering with fairly complex syntax. UFW is a wrapper that makes commands simpler, but still uses iptables under the hood. UFW rules are automatically converted to iptables rules. You can still view the actual iptables rules with ufw show added and edit /etc/ufw/before.rules for advanced cases.
Installation and Enabling UFW
Ubuntu 20.04+ and Debian 11+ come with UFW already installed. If not, install it with:
apt update && apt install ufw -y
Step 1 — Set Default Policy
The best firewall practice is "deny everything first, then allow only what you need":
# Deny all incoming traffic by default
ufw default deny incoming
# Allow all outgoing traffic (VPS must reach the internet)
ufw default allow outgoing
Step 2 — Allow SSH Before Enabling UFW
# If using default port 22
ufw allow ssh
# Or specify port directly (if SSH port changed)
ufw allow 2222/tcp
# To limit SSH to a single trusted IP (more secure)
ufw allow from 203.0.113.10 to any port 22
Step 3 — Allow Required Services
# Web Server
ufw allow http # Port 80
ufw allow https # Port 443
# Use Application Profiles (UFW includes ready-made profiles)
ufw allow 'Nginx Full' # Port 80 + 443
ufw allow 'Apache Full' # Port 80 + 443
# Database (open only from trusted IPs)
ufw allow from 10.0.0.0/8 to any port 3306 # MySQL from private network
ufw allow from 10.0.0.0/8 to any port 5432 # PostgreSQL from private network
# Mail Server
ufw allow 25/tcp # SMTP
ufw allow 587/tcp # SMTP Submission
ufw allow 993/tcp # IMAPS
ufw allow 995/tcp # POP3S
ufw app list shows installed profiles with the ports each one covers.
Step 4 — Enable UFW
# Enable UFW
ufw enable
# Check status and all rules
ufw status verbose
Expected output:
Status: active
To Action From
-- ------ ----
22/tcp ALLOW IN Anywhere
80/tcp ALLOW IN Anywhere
443/tcp ALLOW IN Anywhere
Rate Limiting — Auto Block Brute Force
UFW has built-in rate limiting that blocks IPs attempting more than 6 connections in 30 seconds:
# Enable rate limiting on SSH (instead of regular allow ssh)
ufw limit ssh
# Or specify port directly
ufw limit 22/tcp
ufw limit ssh instead of ufw allow ssh to get instant brute-force protection without needing fail2ban installed separately.
Deleting and Modifying Rules
# View rules with line numbers
ufw status numbered
# Delete rule by line number
ufw delete 3
# Delete rule by specification
ufw delete allow http
ufw delete allow from 203.0.113.10 to any port 22
# Temporarily disable UFW (rules are saved)
ufw disable
# Reset all rules and start fresh
ufw reset
Configure Logging
UFW can log blocked traffic to help analyze attacks:
# Enable logging at Low level (block events only)
ufw logging low
# Medium level (block + allow events)
ufw logging medium
# View logs in real-time
tail -f /var/log/ufw.log
# Show top blocked IPs
grep "BLOCK" /var/log/ufw.log | awk '{print $12}' | sort | uniq -c | sort -rn | head -20
Advanced: Open Port for Specific Time Range
UFW doesn't support time-based rules natively, but you can use cron to open/close rules by time:
# Open port 8080 only during 9am–6pm on weekdays via cron
# Add to crontab -e
0 9 * * 1-5 ufw allow 8080/tcp
0 18 * * 1-5 ufw delete allow 8080/tcp
UFW on VPS Using Docker
Docker manages iptables directly, which can bypass UFW blocking of exposed container ports. Fix this by:
# Edit /etc/ufw/after.rules
# Add before the *filter section
*nat
:PREROUTING ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
COMMIT
Alternatively, add --iptables=false to Docker daemon config and manage routing entirely through UFW. This approach is best for those who need complete firewall control.
Checklist Before Going Live
- SSH port is open and rate limiting is enabled (
ufw limit ssh) - Default policy deny incoming is set
- Only necessary ports are allowed
- Database ports (3306, 5432) are not exposed to the world
ufw status verbosehas been reviewed for open ports- Logging is enabled for audit trail
UFW is ideal for entry to mid-range VPS because it's simple to set up, easy to manage, and effective enough to block common attacks. For more complex requirements like geo-blocking or deep packet inspection, you can extend it with iptables directly or combine it with fail2ban.
Verify UFW is Working Correctly
# View status and all rules
ufw status verbose
# View rules with line numbers (for deletion)
ufw status numbered
# Verify ports you want open are actually open
ss -tlnp | grep -E ':22|:80|:443'
# View UFW log in real-time to see blocked connections
tail -f /var/log/ufw.log
Common Issues & Troubleshooting
Error: Locked myself out of SSH after ufw enable
This happens when UFW is enabled before SSH port is allowed. If you still have console access (KVM/VNC from your provider), do this:
# Connect via VPS console (not SSH)
ufw disable
ufw allow ssh
ufw enable
# Or if UFW is already active and you have another session
ufw allow 22/tcp
ufw reload
Error: Docker container reaches internet even though UFW blocks it
Docker manages iptables directly, bypassing UFW. Fix by binding container to 127.0.0.1 only:
# docker-compose.yml
ports:
- "127.0.0.1:8080:80" # Not "8080:80"
# Or add to /etc/docker/daemon.json
{
"iptables": false
}
# Then manage routing through UFW/iptables completely
Error: UFW rules disappeared after reboot
UFW requires the ufw.service to be enabled in systemd. If disabled, rules won't load at boot:
# Check if UFW service is enabled
systemctl is-enabled ufw
systemctl enable ufw
# Check if UFW is marked ENABLED in config
grep "ENABLED" /etc/ufw/ufw.conf
# Should be: ENABLED=yes
Error: ufw limit blocks my own IP when using it from one location
ufw limit blocks IPs with 6+ connections in 30 seconds. If you're locked out:
# View currently banned IPs in iptables
iptables -L ufw-user-limit-accept -n -v
# Clear rate limit rules temporarily
ufw delete limit ssh
ufw allow ssh
# Or wait 30 seconds (ban is temporary)
Error: "ufw: command not found" on AlmaLinux/Rocky Linux
UFW is Debian/Ubuntu only. RHEL-based systems use firewalld instead:
# On AlmaLinux/Rocky/CentOS use firewalld
systemctl start firewalld
systemctl enable firewalld
# Open ports
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https
firewall-cmd --permanent --add-service=ssh
firewall-cmd --reload
Frequently Asked Questions
How do UFW and firewalld differ? Which should I choose?
UFW is designed for Debian/Ubuntu with simple syntax, ideal for typical VPS use. firewalld runs on RHEL/CentOS/AlmaLinux and offers zone concepts with separate runtime and permanent rules—more complex but more flexible. Choose based on your operating system.
Where are UFW rules stored? Can I back them up?
UFW rules are stored in /etc/ufw/user.rules and /etc/ufw/user6.rules (IPv6). Back them up with cp -r /etc/ufw /backup/ufw-rules-$(date +%Y%m%d) and restore by copying them back, then running ufw reload.
Do I need UFW if I already have a Security Group / Cloud Firewall from my provider?
It's recommended to use both layers. Cloud Firewall protects at the network level before traffic reaches your VPS, while UFW protects at the OS level. If the cloud firewall fails or is misconfigured, UFW serves as a last line of defense. Additionally, UFW can rate-limit at the OS level, which most cloud firewalls cannot.