UFW Firewall VPS Protection

UFW Firewall on Ubuntu/Debian: Easy Setup, Instant Security

June 2026 · 6 min read

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
Important: Do not enable UFW before allowing SSH port access, otherwise you will immediately lock yourself out of the VPS.

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
View all Application Profiles: 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
Recommendation: Always use 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


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
Tip: Before changing SSH port or adding complex new rules, always keep a second SSH session open. If you misconfigure and lock yourself out, you still have the old session to fix it.

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.