UFW (Uncomplicated Firewall) is the default firewall front end on Ubuntu. It writes netfilter rules for you through short, readable commands, so you can control which ports and addresses can reach your server without writing raw iptables or nftables rules. In this tutorial you will configure UFW on Ubuntu 24.04 with a default deny policy, allow SSH and web traffic, restrict a service to a single IP, rate limit SSH and learn how to review and delete rules.

Prerequisites

To follow this tutorial, you need:

  • A server running Ubuntu 24.04 LTS (Debian 12 works the same way once UFW is installed), for example a CubePath VPS.
  • A non-root user with sudo privileges.
  • An open SSH session to the server. Keep it open until you have confirmed that a new SSH connection still works after enabling the firewall.

Step 1 - Installing UFW

UFW ships preinstalled on Ubuntu 24.04. On Debian 12 and minimal images it may be missing. Install it (the command does nothing if it is already present):

sudo apt update
sudo apt install ufw

Check the current state:

sudo ufw status verbose

On a fresh server the firewall is inactive:

Status: inactive

Step 2 - Setting the default policies

Default policies decide what happens to traffic that no rule matches. The safe baseline for a server is to block all incoming connections and allow all outgoing ones:

sudo ufw default deny incoming
sudo ufw default allow outgoing
Default incoming policy changed to 'deny'
(be sure to update your rules accordingly)
Default outgoing policy changed to 'allow'
(be sure to update your rules accordingly)

Nothing is enforced yet because UFW is still inactive. IPv6 is handled automatically: IPV6=yes is the default in /etc/default/ufw, so every rule you add applies to both IPv4 and IPv6.

Step 3 - Allowing SSH

Before enabling the firewall, allow SSH so you do not lock yourself out. Packages can register application profiles with UFW. List them:

sudo ufw app list
Available applications:
  OpenSSH

Allow the OpenSSH profile, which opens port 22/tcp:

sudo ufw allow OpenSSH

If SSH listens on a custom port, allow that port instead. For example, for port 2222:

sudo ufw allow 2222/tcp

To slow down brute force attempts, you can use limit instead of allow. UFW then denies an address that opens 6 or more connections within 30 seconds:

sudo ufw limit OpenSSH

If you already added an allow rule for the same port, limit updates it rather than creating a duplicate.

Step 4 - Allowing other services

Open only the ports your applications actually need. For a web server serving HTTP and HTTPS:

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

If Nginx or Apache is installed, you can use their profiles instead (sudo ufw allow 'Nginx Full' or sudo ufw allow 'Apache Full'). They only appear in ufw app list after the web server package is installed.

Open a range of ports by giving the protocol explicitly:

sudo ufw allow 6000:6007/tcp

Step 5 - Restricting access by IP address

Services such as databases or admin panels should not be reachable from the whole Internet. Allow them only from a trusted address. Replace your_trusted_ip with the public IP of your office, another server or your home connection:

sudo ufw allow from your_trusted_ip to any port 3306 proto tcp

You can also allow a whole subnet, for example a private network:

sudo ufw allow from 10.0.0.0/24

To block a specific address entirely, use deny. Because UFW evaluates rules in order and stops at the first match, insert the deny rule at the top so it takes effect before any allow rules:

sudo ufw insert 1 deny from 203.0.113.50

Step 6 - Enabling UFW

Review the rules you have added before activating them:

sudo ufw show added
Added user rules (see 'ufw status' for running firewall):
ufw limit OpenSSH
ufw allow 80/tcp
ufw allow 443/tcp

Make sure SSH is in the list, then enable the firewall:

sudo ufw enable
Command may disrupt existing ssh connections. Proceed with operation (y|n)? y
Firewall is active and enabled on system startup

Now open a second terminal and connect to the server with SSH. If the new connection works, your SSH rule is correct and you can close the old session.

Step 7 - Checking the active rules

Show the running rule set together with the default policies:

sudo ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), deny (routed)
New profiles: skip

To                         Action      From
--                         ------      ----
OpenSSH                    LIMIT IN    Anywhere
80/tcp                     ALLOW IN    Anywhere
443/tcp                    ALLOW IN    Anywhere
OpenSSH (v6)               LIMIT IN    Anywhere (v6)
80/tcp (v6)                ALLOW IN    Anywhere (v6)
443/tcp (v6)               ALLOW IN    Anywhere (v6)

You can also confirm from another machine that a port you did not open is now filtered, for example with nc -zv your_server_ip 8080, which should time out.

Step 8 - Deleting rules

List the rules with their numbers:

sudo ufw status numbered
     To                         Action      From
     --                         ------      ----
[ 1] OpenSSH                    LIMIT IN    Anywhere
[ 2] 80/tcp                     ALLOW IN    Anywhere
[ 3] 443/tcp                    ALLOW IN    Anywhere
[ 4] OpenSSH (v6)               LIMIT IN    Anywhere (v6)
[ 5] 80/tcp (v6)                ALLOW IN    Anywhere (v6)
[ 6] 443/tcp (v6)               ALLOW IN    Anywhere (v6)

Delete a rule by number. UFW asks for confirmation and renumbers the remaining rules afterwards, so list them again before deleting another one:

sudo ufw delete 2

Deleting by number removes only the IPv4 or the IPv6 entry. To remove both at once, delete the rule by its original syntax:

sudo ufw delete allow 80/tcp

Step 9 - Using the UFW log

With logging on (the default level is low), UFW logs blocked packets to the kernel log with the prefix [UFW BLOCK]. On Ubuntu 24.04 they are written to /var/log/ufw.log. Follow them while you test a connection:

sudo tail -f /var/log/ufw.log
Sep 25 10:12:03 server kernel: [UFW BLOCK] IN=eth0 OUT= SRC=198.51.100.23 DST=203.0.113.10 PROTO=TCP SPT=51544 DPT=3306 ...

DPT is the destination port that was blocked, which tells you which rule is missing if a legitimate service stops working.

Troubleshooting

  • Locked out of SSH. Log in through the VNC console in your provider's control panel, then run sudo ufw allow OpenSSH (or your custom port) or sudo ufw disable temporarily while you fix the rules.
  • Docker containers are reachable despite UFW. Docker writes its own netfilter rules for published ports, and they bypass UFW's input rules. Publish internal services only on localhost (for example -p 127.0.0.1:8080:80) instead of relying on UFW to hide them.
  • Starting over. sudo ufw reset disables the firewall and deletes all rules, keeping backups of the old rule files in /etc/ufw. Add your SSH rule again before re-enabling it.

Conclusion

Your server now drops all unsolicited incoming traffic except the services you explicitly allowed, for both IPv4 and IPv6, and SSH is protected by rate limiting. Keep the rule set small and review it with sudo ufw status numbered whenever you add or remove a service. As next steps, consider switching SSH to key-based authentication, installing Fail2ban for smarter brute force protection, and restricting admin ports to your own IP addresses.