Skip to content
Français
Account: not signed in, sync available My learning
Select theme
Français

Configure a firewall with UFW

By updated

Improve this page

UFW (Uncomplicated Firewall) is a command-line frontend for nftables/iptables. It is installed by default on Ubuntu (disabled at boot), available through apt on Debian, and designed to make configuring a host firewall accessible without learning the iptables syntax. It is the right entry point for a standalone Debian/Ubuntu server. In this guide, you set a strict default policy, open the useful flows, validate the firewall state, and equip yourself with a rollback plan so you never lock yourself out of your own server.

What you will learn

  • Install UFW on Debian/Ubuntu and understand when it is not available elsewhere
  • Allow SSH before any activation to avoid the lockout
  • Set a default policy (deny incoming, allow outgoing) and enable it
  • Add allow, deny, limit rules by service or by port
  • Check the state and the number of each rule with ufw status verbose / numbered
  • Roll back cleanly after a bad rule

In what context?

UFW is made for the host firewall of a Linux server or workstation. You use it when:

  • you are on Ubuntu or Debian and want a simple firewall, quick to audit
  • you want a readable syntax (sudo ufw allow 22/tcp) rather than iptables chains
  • you are setting up a first filtering layer before considering direct nftables or firewalld

If you are on RHEL, Fedora, CentOS Stream or Rocky, the default is firewalld, UFW is not packaged by default there and mixing it with firewalld creates silent conflicts. On these systems, stick with firewalld.

Prerequisites

  • A Debian 13 or Ubuntu 24.04 LTS server
  • A user with sudo rights
  • Key-based SSH access already configured; if you use SSH with a password, first read SSH keys
  • A fallback access (physical console, cloud provider console, serial…) in case of lockout

Install UFW

The package is called ufw everywhere, but its status differs by distribution: absent on a minimal Debian, usually already present on Ubuntu, and outside the default repositories on the RHEL family.

Terminal window
sudo apt update
sudo apt install -y ufw

Check that the command responds:

Terminal window
sudo ufw status

Expected output after installation, before activation:

Status: inactive

Allow SSH before any activation

This is the most important step of the guide. Before enabling UFW, create the rule that keeps your SSH session alive, otherwise the default policy will refuse your next connection.

  1. Allow SSH explicitly

    Terminal window
    sudo ufw allow 22/tcp

    If your SSH listens on a non-standard port:

    Terminal window
    sudo ufw allow 2222/tcp comment 'SSH admin'
  2. Rate-limit SSH to slow down brute-force attacks

    Terminal window
    sudo ufw limit 22/tcp

    limit refuses any new connection from a source address that has attempted 6 or more in 30 seconds: the rule it sets is --hitcount 6 --seconds 30 in /etc/ufw/user.rules. It is not a ban, the IP gets access back as soon as its rate drops. Useful against brute-force bots; not a substitute for SSH keys and full SSH hardening if you expose SSH on the Internet (see Harden SSH (in French)).

  3. Review the rule

    Terminal window
    sudo ufw show added

    It must show ufw limit 22/tcp or ufw allow 22/tcp depending on your choice.

As long as UFW is not enabled, the ufw allow/limit/deny commands are not active yet: they are added to a queue visible with sudo ufw show added. They will all be applied at once at activation, in the next step.

Enable UFW with a strict policy

By default, UFW applies two policies that form the right starting point for a server: nothing comes in unless allowed, everything can go out.

  • deny incoming: any inbound traffic not explicitly allowed is refused
  • allow outgoing: all outbound traffic is allowed

This is the right baseline. Enable it:

Terminal window
sudo ufw enable

You will see a warning, then the message Firewall is active and enabled on system startup. Check immediately:

Terminal window
sudo ufw status verbose

Expected output:

Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip
To Action From
-- ------ ----
22/tcp LIMIT IN Anywhere
22/tcp (v6) LIMIT IN Anywhere (v6)

The verbose view states the direction of each rule (LIMIT IN), where a plain ufw status shows LIMIT. The disabled (routed) value is that of a server that does not route: it becomes deny (routed) as soon as IP forwarding is enabled, for example on a Docker host.

Your current SSH connection must still work. If it drops, use your fallback access and run sudo ufw disable.

Open the useful services

UFW knows service names through /etc/services. The two syntaxes below are equivalent:

Terminal window
# by service name
sudo ufw allow http
# by port number
sudo ufw allow 80/tcp

A few common cases, each with a comment that will explain the rule during the next audit:

Terminal window
# Web server
sudo ufw allow http
sudo ufw allow https
# Mail server (encrypted SMTP + IMAP)
sudo ufw allow 587/tcp comment 'SMTP submission'
sudo ufw allow 993/tcp comment 'IMAPS'
# Restrict a service to an internal network
sudo ufw allow from 192.168.10.0/24 to any port 3306 proto tcp comment 'MySQL LAN only'
# Block an IP hammering a public service (e.g. exposed HTTP)
# Useless on a port already blocked by deny-by-default
sudo ufw deny from 203.0.113.42 to any port 80 proto tcp

Always check after each batch of rules:

Terminal window
sudo ufw status numbered

The number lets you delete a precise rule:

Terminal window
sudo ufw delete 3

Check and read the rules

Three check commands to keep at hand, each answering a different question about the state of the firewall:

NeedCommand
State + default policy + rulessudo ufw status verbose
Rules with number (for deletion)sudo ufw status numbered
Pending rules (before ufw enable)sudo ufw show added

To inspect blocked traffic, enable logging. Refused packets are kernel messages prefixed with [UFW BLOCK]: where they land depends on whether rsyslog is present, installed by default on Ubuntu Server but no longer on Debian since version 12.

Terminal window
sudo ufw logging medium
sudo tail -f /var/log/ufw.log

The [UFW BLOCK] entries show the refused packets; use them to diagnose a service that does not answer. On Debian 13 without rsyslog, the /var/log/ufw.log file does not exist: looking for it wrongly suggests that nothing is blocked.

Best practices

These habits avoid most UFW incidents; the first one alone prevents the lockout, the others keep the ruleset readable and persistent.

  • Always allow SSH before ufw enable, the golden rule.
  • Prefer limit over allow for SSH exposed on the Internet, combined with key-only SSH.
  • Comment each rule with comment '…': reviewing it in 6 months will be much easier.
  • Scope the rules to the right network (from 192.168.0.0/16 to any …) rather than opening Anywhere by default.
  • Do not mix UFW with hand-written iptables/nftables: UFW writes its own chains, a manual change creates silent conflicts.
  • Test persistence: sudo systemctl reboot then check ufw status verbose again. UFW is normally enabled at boot, but a cloud-init configuration can reset the state to inactive.

Security and rollback

Before running ufw enable, have these two safety nets in place:

  1. A second open SSH session on the server (activation does not cut established connections, but a failed rule could cut the next one).
  2. Console access configured and tested (IPMI, cloud KVM, serial port).

Full rollback in case of trouble:

Terminal window
# Disable UFW (back to the pre-activation state)
sudo ufw disable
# Reset all rules
sudo ufw reset

reset erases all the rules and disables UFW. It is drastic, use it if you are lost. After a reset, you must redo the SSH authorisation procedure before a new enable.

Quick troubleshooting

The table below starts from the symptom you observe, gives the most likely cause, then the action that fixes it.

SymptomProbable causeAction
SSH cut after ufw enableSSH port not allowed or rule too restrictiveConsole access → sudo ufw disable, fix, try again
Service reachable locally, not from outsidePort not allowed or rule with a from too narrowsudo ufw status numbered; adjust or add allow <port>/tcp
Empty ufw status after rebootUFW disabled at boot (Ubuntu cloud-init)sudo systemctl enable --now ufw + check sudo ufw enable
Rules missing from the INPUT chain of iptables -LNormal: UFW stores its rules in its own chains, called from INPUTsudo iptables -L ufw-user-input -n or stick to sudo ufw status
[UFW BLOCK] in the logs for a legitimate serviceService arrives on an interface that is not allowedAdd allow in on <iface> or widen the rule

Put it into practice

Open a service in the ufw firewall on a VM, check the active rule, and confirm that it persists after a reboot.

Key points

  • UFW is a simplified frontend for nftables/iptables, packaged by default on Ubuntu and installable on Debian.
  • Allow SSH before enabling: it is the only mistake that can cut you off from your server.
  • Use limit for SSH exposed on the Internet, allow for an internal network.
  • Recommended default policy: deny incoming, allow outgoing.
  • sudo ufw status verbose and sudo ufw status numbered are the two commands to memorise.
  • Each rule can carry a comment: use it systematically.
  • On RHEL/Fedora/Rocky, prefer firewalld; do not mix the two.
  • ufw reset as a last resort to start again from a blank page.

Knowledge check

Check that the essentials of this guide are acquired. The questions only cover what has just been explained here.

Knowledge check

Check what you have learned with this interactive quiz

6 questions
6 min
70% to pass

How it works

  • The timer starts when you click Start
  • Multiple choice, true/false and short answer questions
  • You can move between questions
  • Detailed results are shown at the end

Starts the quiz and the timer

FAQ: frequently asked questions

The questions below cover those that come up most often about UFW: its role, enabling without lockout, the difference between allow and limit, and the choice against firewalld.

Is this project useful to you?

The guides, courses, quizzes and labs stay free. If you use them regularly, you can contribute to their upkeep and development.

Become a supporting member (new tab) One-time support (new tab) Learn more

Follow the project on LinkedIn