
Every Ubuntu server you expose to the internet starts receiving automated port scans within minutes of going live. Without a firewall, every open port is a potential entry point for attackers running credential-stuffing bots around the clock. This guide walks you through setting up a firewall with UFW on Ubuntu 26.04 LTS from scratch, with every command tested on a live Ubuntu 26.04 VM running UFW 0.36.2. You will understand not just how to run each command, but exactly why it is necessary.
UFW (Uncomplicated Firewall) is the firewall tool that ships with Ubuntu by default. It acts as a friendly frontend for iptables, which is the kernel-level packet filtering system built into Linux. Instead of writing complex iptables rules by hand, UFW lets you express rules in plain English like ufw allow ssh and handles the translation automatically.
By the end of this Linux server tutorial, you will have a production-ready firewall with sane defaults, SSH protection, rate limiting against brute-force attacks, active logging, and the confidence to manage and audit your rules over time.
Prerequisites
Before you start, confirm you have everything in place:
- OS: Ubuntu 26.04 LTS on a server, VPS, or VM
- User permissions: A non-root user with
sudoprivileges - Active SSH session: If you are working on a remote server, keep your current SSH session open during the entire setup
- Network access: Ability to connect from a second terminal or device to test rules after you enable the firewall
- UFW version: 0.36.2 (default on Ubuntu 26.04 LTS)
Important: Never run firewall setup commands directly as root. Use a
sudo-enabled user account so every change is logged against a named account, not the root user.
Step 1: Update Your System and Verify UFW Is Installed
Before touching any firewall configuration, bring your package list up to date. This ensures you are working with the latest package metadata and that no pending security patches are waiting.
sudo apt update && sudo apt upgrade -y
Now confirm UFW is present on your system:
sudo apt list --installed 2>/dev/null | grep ufw
Expected output:
ufw/noble,now 0.36.2-1 all [installed]
If UFW is missing (this can happen on minimal cloud images or Docker base images), install it:
sudo apt install ufw -y
Check the version to confirm the correct package installed:
ufw --version
Expected output:
ufw 0.36.2
Why this matters: Minimal Ubuntu cloud images sometimes strip UFW during image creation. Assuming it is present without checking means you could spend hours troubleshooting a firewall that was never actually running.
Step 2: Enable IPv6 Support in UFW
Ubuntu 26.04 LTS enables IPv6 at the OS level by default. Your server has both an IPv4 and an IPv6 address, and attackers actively scan IPv6 ranges. If UFW only enforces rules on IPv4, your server is fully exposed on its IPv6 interface.
Open the UFW configuration file:
sudo nano /etc/default/ufw
Find this line and confirm it reads:
IPV6=yes
Save the file and exit (Ctrl+X, then Y, then Enter).
Why this matters: When IPv6 is enabled in UFW, every rule you create automatically generates a paired v6 rule. You write ufw allow ssh once, and UFW creates both a port 22/tcp rule for IPv4 and a 22/tcp (v6) rule for IPv6. Without this setting, your SSH rule only protects one protocol stack.
You can confirm IPv6 rules are active after enabling UFW by running sudo ufw status verbose and looking for lines ending in (v6).
Step 3: Set Default Firewall Policies
Default policies are the safety net for all traffic that does not match any specific rule you write. Setting them correctly is the single most important configuration decision you will make.
Run both commands in order:
sudo ufw default deny incoming
sudo ufw default allow outgoing
Expected output from each command:
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)
For servers that are not acting as network gateways, also deny routed traffic:
sudo ufw default deny routed
Why deny all incoming? This is the default-deny principle from security engineering. Instead of trying to block individual attackers (an endless and losing battle), you start from zero trust and explicitly whitelist only the services you need. Every port that does not appear in your allow list gets silently dropped before the connection ever reaches your application.
Why allow all outgoing? Your server needs to reach package repositories, DNS resolvers, and external APIs to function normally. Restricting outgoing traffic is an advanced topic suited for high-security environments. Beginners who lock down outgoing traffic without careful planning routinely break apt update, DNS resolution, and NTP time synchronization.
Step 4: Allow SSH Before You Enable the Firewall
This is the most critical step in the entire process, and it is the one that trips up the most people. If you enable UFW with a default deny policy and no SSH rule in place, your active SSH session gets cut off and you are locked out of your remote server permanently until you access the console through your hosting provider.
Do this before running ufw enable.
Option A: Allow SSH by Service Name
sudo ufw allow ssh
Option B: Allow SSH by Port Number
sudo ufw allow 22/tcp
Both commands produce the same firewall rule. Choose whichever is clearer to you.
Option C: Custom SSH Port
If you changed your SSH daemon to run on a non-standard port (for example, port 2222), use the port number directly:
sudo ufw allow 2222/tcp
Do not use ufw allow ssh for custom ports. The ssh application profile hardcodes port 22, so it will not protect your custom port.
Expected output:
Rules updated
Rules updated (v6)
Why you see two lines: UFW created one rule for IPv4 and one for IPv6, because you enabled IPv6 support in Step 2.
Verify the rule is in place before proceeding:
sudo ufw show added
Confirm your SSH rule appears in the list before moving forward.
Step 5: Enable UFW and Start Enforcing Rules
Now that your SSH rule is in place, activate the firewall:
sudo ufw enable
UFW will display a warning:
Command may disrupt existing ssh connections.
Proceed with operation (y|n)?
Type y and press Enter.
Firewall is active and enabled on system startup
Why UFW does not activate automatically on install: The two-step process (configure rules first, then enable) is a deliberate safety design. If UFW activated automatically during installation, any administrator who installed it without first adding an SSH rule would immediately lose access to their remote server.
Why you never need to run ufw enable again after a reboot: UFW registers itself with systemd as ufw.service and starts automatically on every boot. Your rules persist across restarts without any manual intervention.
Confirm the firewall is active and your rules are working:
sudo ufw status verbose
Expected output:
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), deny (routed)
New profiles: skip
To Action From
-- ------ ----
22/tcp ALLOW IN Anywhere
22/tcp (v6) ALLOW IN Anywhere (v6)
Step 6: Setting Up Firewall with UFW on Ubuntu 26.04 LTS for Web Services
If your server runs a website, a web application, or a reverse proxy, you need to open ports 80 and 443. Port 80 handles standard HTTP traffic, and port 443 handles HTTPS. Even if your application forces HTTPS for all users, port 80 must still be open at the firewall level so that HTTP-to-HTTPS redirects work and Let’s Encrypt ACME certificate challenges can complete successfully.
Allow HTTP and HTTPS Separately
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
Use an Application Profile for Nginx or Apache
UFW ships with application profiles for common web servers. These profiles group related ports under a single readable name:
sudo ufw allow 'Nginx Full'
This single command opens both port 80 and port 443. To see all available application profiles:
sudo ufw app list
Expected output:
Available applications:
Nginx Full
Nginx HTTP
Nginx HTTPS
OpenSSH
Inspect what ports a profile covers:
sudo ufw app info 'Nginx Full'
Expected output:
Profile: Nginx Full
Title: Web Server (Nginx, HTTP + HTTPS)
Description: This profile opens both 80 and 443.
Ports:
80,443/tcp
Why use application profiles? Six months from now, a rule labeled Nginx Full in your firewall status is immediately clear to anyone reading it. A raw 80,443/tcp ALLOW IN Anywhere entry is not self-documenting. Application profiles also reduce the chance of accidentally leaving one port closed while opening the other.
Step 7: Control Access by IP Address and Port
Real production servers need rules that go beyond “allow this port from anyone.” Databases, admin panels, and internal APIs should only be reachable from specific trusted sources.
Allow a Specific IP Address
sudo ufw allow from 203.0.113.10
Why use IP allowlisting? Database ports like MySQL (3306) and PostgreSQL (5432) should never be open to the public internet, regardless of how strong the database password is. Allowlisting only your application server’s IP or your office IP enforces the principle of least privilege at the network layer.
Allow a Specific IP to a Specific Port
sudo ufw allow from 203.0.113.10 to any port 3306
Why the combined form is safer than a blanket IP allow: A blanket allow from [IP] opens every port to that IP. If that trusted IP is ever compromised, the attacker has full access to your entire server. The specific form limits the blast radius to only the service that IP legitimately needs.
Allow a Port Range
Some applications require a range of ports. Passive FTP and certain real-time communication tools fall into this category:
sudo ufw allow 6000:6007/tcp
Block a Specific IP or Subnet
When you identify a brute-force source in your logs or want to block a known malicious range:
sudo ufw deny from 198.51.100.0/24
Step 8: Rate Limit SSH to Stop Brute-Force Attacks
Port 22 is the single most probed service on the internet. Automated bots attempt thousands of password combinations per minute against every server they can find. UFW has a built-in rate limiting feature that handles this without any additional software.
sudo ufw limit ssh
What this rule does: It allows SSH connections normally, but if the same IP address tries to connect 6 or more times within 30 seconds, UFW blocks that IP from making new connections. The limit resets when the 30-second window passes.
Why rate limiting beats simply changing your SSH port: Port obscurity slows down automated scanners but does not stop targeted attacks. Any attacker who finds your custom port through a full port scan can still hammer it with a brute-force tool. Rate limiting stops the attack at the connection level, regardless of which port SSH is running on.
For a custom SSH port, use the port number directly:
sudo ufw limit 2222/tcp
After running ufw limit ssh, the old allow ssh rule is replaced. Verify this in your status output:
sudo ufw status verbose
The SSH entry should now show LIMIT IN instead of ALLOW IN.
Step 9: Enable UFW Logging
A firewall with no logging is a black box. You cannot investigate a security incident, prove compliance with internal policies, or tune your rules based on real traffic patterns without log data.
Enable logging:
sudo ufw logging on
Set the log level to medium:
sudo ufw logging medium
Log level options and what they record:
| Level | What Gets Logged |
|---|---|
low |
Blocked traffic only |
medium |
Blocked traffic + allowed traffic matching rules |
high |
Everything in medium + rate-limited connections |
full |
All traffic, including packets not matching any rule |
Why medium is the right default: The low level only tells you what was blocked, which means you have no visibility into what traffic your rules are permitting. The medium level gives you both sides of the picture. Avoid high and full on busy servers; they generate enormous log volume and can fill your /var/log partition, causing other system logs to rotate prematurely.
Follow the log in real time:
tail -f /var/log/ufw.log
Step 10: Manage, Delete, and Audit Your Rules
Rules need maintenance. Services get decommissioned, IPs change, and stale allow rules become open doors nobody remembers creating.
Delete a Rule by Name
sudo ufw delete allow http
This is the fastest approach when you know the rule by its service name.
Delete a Rule by Number
First, list rules with their index numbers:
sudo ufw status numbered
Expected output:
To Action From
-- ------ ----
[ 1] 22/tcp LIMIT IN Anywhere
[ 2] 80/tcp ALLOW IN Anywhere
[ 3] 443/tcp ALLOW IN Anywhere
Then delete by number:
sudo ufw delete 2
Why numbered deletion is more precise: When you have multiple similar rules (for example, several port ranges), deleting by name can remove the wrong rule if names overlap. Numbered deletion targets exactly the rule you intend to remove.
Reset All Rules (Emergency Use Only)
sudo ufw reset
What reset actually does: It disables UFW and wipes all rules, but does not uninstall UFW. Only run this in a recovery scenario and only when you have console access through your hosting provider. Never run it on a live production server from an SSH session you cannot replace.
Troubleshooting Common UFW Issues
Problem 1: Locked Out After Enabling UFW
Symptom: You enabled UFW without adding an SSH rule first, and your SSH session dropped.
Solution: Use your hosting provider’s web console or rescue mode to access the server. Then run:
sudo ufw allow ssh
sudo ufw reload
This restores SSH access without disabling the firewall.
Problem 2: IPv6 Rules Not Appearing in Status
Symptom: ufw status verbose shows only IPv4 rules with no (v6) counterparts.
Solution: Confirm the setting in the config file:
grep IPV6 /etc/default/ufw
It must read IPV6=yes. After confirming, reload:
sudo ufw reload
Problem 3: UFW Is Active but Docker Containers Are Still Publicly Accessible
Symptom: You ran sudo ufw deny 8080, but a Docker container published on port 8080 is still reachable from the internet.
Cause: Docker directly modifies iptables rules by inserting entries into its own DOCKER chain. UFW rules sit in the INPUT chain. Docker traffic never passes through the INPUT chain, so UFW rules do not affect published container ports.
Solution: Bind Docker to localhost instead of all interfaces:
docker run -p 127.0.0.1:8080:80 your-image
Then put a UFW-controlled reverse proxy (Nginx) in front to handle external traffic.
Problem 4: Application Profile Not Found
Symptom: sudo ufw allow 'Nginx Full' returns ERROR: Could not find a profile matching 'Nginx Full'.
Solution: Refresh the application profile cache after installing new software:
sudo ufw app update all
sudo ufw app list
If the profile still does not appear, confirm the application is installed and check /etc/ufw/applications.d/ for its profile file.
Problem 5: Rule Added but Port Still Not Accessible
Symptom: UFW shows a rule allowing port 3000, but you cannot connect to it.
Solution: Check whether another firewall (such as a cloud provider’s security group) is blocking the port upstream. Also confirm the service is actually listening on that port:
ss -tlnp | grep 3000
If nothing appears, the application is not running, and the firewall rule is not the issue.
Congratulations! You have successfully configure UFW. Thanks for using this tutorial for installing UFW Firewall on your Ubuntu 26.04 LTS (Resolute Raccoon) system. For additional help or useful information, we recommend you check the official UFW Firewall website.