How to Set Up a Firewall with UFW on Ubuntu and Debian

Kubana Cloud · September 29, 2026 · Updated September 29, 2026 · 10 min read

Devops
How to Set Up a Firewall with UFW on Ubuntu and Debian

Introduction

A working firewall is one of the first things any cloud server needs. Historically that meant learning iptables, which is powerful but verbose and easy to get wrong.

UFW (Uncomplicated Firewall) is a friendly front-end to the Linux kernel's netfilter framework. It translates short, readable commands like sudo ufw allow ssh into the low-level rules the kernel enforces. On current Ubuntu and Debian releases UFW uses the nftables backend under the hood, but the commands you type are the same regardless.

This guide walks you through installing UFW, setting sensible defaults, opening ports for SSH and web traffic, working with application profiles, enabling logging, deleting rules, and resetting the firewall if you need to start over.

Prerequisites

  • A server running Ubuntu 22.04 LTS (or later) or Debian 12 (or later)
  • A non-root user with sudo privileges. See our Initial Server Setup with Ubuntu guide if you haven't configured this yet.
  • An active SSH session to the server

Warning: Never run sudo ufw enable before allowing SSH. The default policy denies all incoming traffic, so enabling the firewall without an SSH rule will lock you out of a remote server.

Step 1: Installing UFW

On Ubuntu, UFW is installed by default but ships disabled. Confirm it's present by checking its status:

sudo ufw status

If UFW is installed but not yet enabled, you'll see:

Status: inactive

On Debian, UFW is in the standard repositories but not installed by default. Install it with apt:

sudo apt update
sudo apt install ufw -y

Installing the package does not enable the firewall. UFW stays inactive until you run sudo ufw enable, which gives you time to add an SSH rule first. Everything that follows applies identically to Ubuntu and Debian.

You can check which version is installed with:

sudo ufw version

Step 2: Enabling IPv6 Support

If your server has an IPv6 address, make sure UFW manages both IPv4 and IPv6 rules. Open the UFW configuration file:

sudo nano /etc/default/ufw

Confirm that IPV6 is set to yes (this is the default on modern systems):

IPV6=yes

Save and exit (CTRL + X, then Y, then ENTER). Changes to this file only take effect after the firewall restarts, so if you edited it on an already-active firewall, run sudo ufw disable followed by sudo ufw enable later once your rules are in place.

With IPv6 enabled, every rule you add will apply to both protocols, and you'll see confirmations like Rule added and Rule added (v6).

Step 3: Setting Default Policies

The recommended baseline is to deny all incoming traffic and allow all outgoing traffic. Nobody can reach your server unless you explicitly open a port, while applications on the server can still connect out. Set these policies explicitly:

sudo ufw default deny incoming
sudo ufw default allow outgoing

Each command confirms the change:

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)

Note: You can be stricter and deny outgoing traffic too with sudo ufw default deny outgoing. This helps prevent unwanted outbound connections (e.g. reverse shells), but you'll have to add a rule for every outgoing connection your server needs, including apt updates and DNS. Only do this if you're prepared to manage those rules.

Step 4: Allowing SSH

Before enabling the firewall, allow SSH so you don't lose access. Using the OpenSSH application profile is the clearest option:

sudo ufw allow OpenSSH

You'll see:

Rule added
Rule added (v6)

The following alternatives achieve the same result:

# By service name
sudo ufw allow ssh

# By port and protocol
sudo ufw allow 22/tcp

If your SSH daemon listens on a non-standard port such as 2222, allow that port instead. Always name the protocol, since a bare port number opens both TCP and UDP:

sudo ufw allow 2222/tcp

To add basic brute-force protection, use limit instead of allow. This caps new connections from a single IP at six per 30 seconds:

sudo ufw limit ssh

Step 5: Enabling UFW

With SSH allowed, it's safe to turn the firewall on:

sudo ufw enable

Type y and press ENTER to confirm. UFW reports that it is active and will start on boot:

Firewall is active and enabled on system startup

Verify your rules:

sudo ufw status verbose

The verbose output shows the status, default policies, logging level, and every active rule in one place:

Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip

To                         Action      From
--                         ------      ----
22/tcp (OpenSSH)           ALLOW IN    Anywhere
22/tcp (OpenSSH (v6))      ALLOW IN    Anywhere (v6)

If you ever need to turn the firewall off, run sudo ufw disable. This stops it and removes it from startup.

Step 6: Allowing Web Server Traffic

Web servers like Nginx and Apache listen on port 80 (HTTP) and 443 (HTTPS). Open them by port:

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

Or use the application profile your web server registered on installation, which is often cleaner. For Nginx:

sudo ufw allow 'Nginx Full'

For Apache:

sudo ufw allow 'Apache Full'

Both profiles open ports 80 and 443 together. Use 'Nginx HTTP' / 'Apache' if you only want port 80, or 'Nginx HTTPS' / 'Apache Secure' for only 443.

Step 7: Working with Application Profiles

When you install network software, it usually registers a UFW application profile, which is a named bundle of the ports that service needs. List the profiles available on your system:

sudo ufw app list

The output depends on what you've installed:

Available applications:
  Apache
  Apache Full
  Apache Secure
  Nginx Full
  Nginx HTTP
  Nginx HTTPS
  OpenSSH

To see exactly what a profile opens before you allow it:

sudo ufw app info 'Nginx Full'
Profile: Nginx Full
Title: Web Server (Nginx, HTTP + HTTPS)
Description: Small, but very powerful and efficient web server

Ports:
  80,443/tcp

After upgrading a package, its profile may change. Refresh a single profile or all of them:

sudo ufw app update 'Nginx Full'
sudo ufw app update all

Step 8: Allowing Port Ranges, UDP, and Specific IPs

Port ranges: specify the low end, a colon, the high end, and the protocol. The protocol is required for ranges:

# Allow TCP ports 1000 through 2000
sudo ufw allow 1000:2000/tcp

# Deny UDP ports 1234 through 4321
sudo ufw deny 1234:4321/udp

UDP services: DNS, NTP, and VPNs like WireGuard use UDP, so you must name the protocol explicitly:

sudo ufw allow 51820/udp   # WireGuard
sudo ufw allow 53/udp      # DNS

Specific IP addresses: allow all traffic from a trusted address:

sudo ufw allow from 203.0.113.10

Or restrict that address to a single port. This is a common pattern for locking SSH down to your office or VPN IP:

sudo ufw allow from 203.0.113.10 to any port 22

You can also allow an entire subnet using CIDR notation:

sudo ufw allow from 203.0.113.0/24 to any port 3306

FTP: if you run an FTP server, allow the control port (21) and, for active mode, the data port (20):

sudo ufw allow ftp
sudo ufw allow 20/tcp

Note: Most FTP deployments use passive mode, which requires an additional range of high-numbered ports configured in your FTP server (e.g. pasv_min_port/pasv_max_port in vsftpd.conf). Open that range with a rule like sudo ufw allow 49152:65535/tcp once you know the values.

Step 9: Denying Connections

Because the default policy is already deny incoming, you rarely need explicit deny rules. They're useful for temporarily blocking a service without removing its allow rule, or for blocking a specific IP:

# Block HTTP
sudo ufw deny 80/tcp

# Block all traffic from an address
sudo ufw deny from 198.51.100.25

UFW evaluates rules in order, so if you need a deny rule to take priority over an existing allow rule, insert it at the top:

sudo ufw insert 1 deny from 198.51.100.25

Step 10: Deleting Rules

You can delete a rule by repeating its specification with delete in front:

sudo ufw delete allow 80/tcp
Rule deleted
Rule deleted (v6)

For long or complex rules, it's easier to delete by number. First list the rules with their indexes:

sudo ufw status numbered
Status: active

     To                         Action      From
     --                         ------      ----
[ 1] OpenSSH                    ALLOW IN    Anywhere
[ 2] 80/tcp                     ALLOW IN    Anywhere
[ 3] 443/tcp                    ALLOW IN    Anywhere
[ 4] OpenSSH (v6)               ALLOW IN    Anywhere (v6)
...

Then delete the rule by its number and confirm with y:

sudo ufw delete 2

Note: Rule numbers shift after each deletion. Re-run sudo ufw status numbered before deleting another rule.

Step 11: Enabling Logging

Logging records the traffic UFW handles, which is invaluable for spotting blocked connection attempts and debugging rules. Turn it on:

sudo ufw logging on

Choose a level to balance detail against log volume:

sudo ufw logging medium
Level What it logs
low Blocked packets that don't match the default policy (the default)
medium Adds new connections and some matched packets
high More detail, with rate limiting
full Everything, with no rate limit

For most servers low or medium is the right choice. Entries are written to /var/log/ufw.log:

sudo tail -f /var/log/ufw.log

sudo ufw status verbose shows the current level on its Logging: line.

Step 12: Resetting UFW

If you need to clear everything and start over:

sudo ufw reset

UFW asks you to confirm, backs up your current rule files to /etc/ufw/*.rules.<timestamp>, deletes all user-defined rules, disables the firewall, and restores the default policies (deny incoming, allow outgoing).

After a reset, re-allow SSH before re-enabling the firewall:

sudo ufw allow OpenSSH
sudo ufw enable

Troubleshooting

Locked out of SSH after enabling UFW: This happens when ufw enable runs before an SSH rule exists. If you still have an open terminal, run sudo ufw allow OpenSSH immediately; your current session keeps working. If you've already been disconnected, log in through your provider's web console and add the rule there before reconnecting over SSH.

Rules not persisting after reboot: UFW saves rules to disk and reloads them on boot once enabled. If sudo ufw status reports inactive after a reboot, run sudo ufw enable again and confirm the systemd unit is enabled:

sudo systemctl enable --now ufw
sudo systemctl is-enabled ufw

IPv6 rules not applying: Confirm IPV6=yes in /etc/default/ufw, then restart the firewall with sudo ufw disable && sudo ufw enable. Rule confirmations should show both Rule added and Rule added (v6).

Conclusion

Your server now has a firewall that denies everything by default and allows only the traffic you've explicitly opened. The minimal, safe sequence to remember is:

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH
sudo ufw enable

From there, open only the ports your services actually need, consider sudo ufw limit ssh and restricting SSH to known IPs, keep logging on, and review your rules periodically with sudo ufw status numbered.

For more on UFW, see the official Ubuntu guide on How to Configure a Firewall with UFW and the UFW manual page.

Attachments

Back to all articles
Newsletter

Stay in the loop

Product updates, infrastructure insights, and platform news delivered to your inbox.