Why a firewall is the first line of defence on your VPS

An Ubuntu server is exposed to automated scanning traffic from the moment it is attached to a public IP address. If services such as SSH, database ports or admin panels are left listening by default, there is no mechanism at all to block connection attempts to those services regardless of who sent them. A firewall closes that gap: by explicitly defining which ports will be reachable from outside, it narrows the attack surface. Only the services you genuinely need (SSH, HTTP, HTTPS, for example) stay open to the outside, and everything else is denied by default.

What UFW is and how it relates to iptables

UFW (Uncomplicated Firewall) is the official frontend on Ubuntu and Debian that simplifies the complex syntax of iptables/nftables. Instead of writing iptables rules directly, you work with readable commands such as ufw allow 22/tcp; UFW translates those commands into the necessary kernel-level packet filtering rules in the background. That way you can build a readable and later auditable rule set without wrestling with complex chain logic.

Installation, default policies and checking the status

UFW comes preinstalled on most Ubuntu servers; if it is not installed it can be added with apt install ufw. The first thing to do before enabling UFW is to set the default policies. The standard and safe base configuration is this: deny all incoming connections by default, allow only the ones you explicitly permit, and leave outgoing connections alone.

Every allow, deny or limit rule you add on top of those two lines is applied in order. As rules are added, UFW keeps them in a numbered list; you can see that order with sudo ufw status numbered and the active policies and all rules with sudo ufw status verbose. Once the configuration is finished it is enabled with sudo ufw enable, and it can be switched off with sudo ufw disable when needed.

Basic UFW commands

CommandDescription
<code>sudo ufw allow 22/tcp</code>Allow TCP port 22 (SSH) from anywhere
<code>sudo ufw deny 23</code>Deny port 23 (Telnet)
<code>sudo ufw allow from 203.0.113.10 to any port 22</code>Allow SSH only from a specific IP
<code>sudo ufw allow 6000:6007/tcp</code>Allow a port range
<code>sudo ufw limit ssh</code>Apply rate-limited protection to the SSH port
<code>sudo ufw delete allow 80</code>Delete a previously added rule
<code>sudo ufw status verbose</code>Show the active rules and policies

A service name can be used instead of a port number; UFW resolves names such as ssh, http and https into port numbers from the definitions in the /etc/services file. When you want to restrict traffic coming from a specific source, the from ... to any port ... proto ... pattern is used; this is handy, for example, for making an admin panel reachable only from your office IP.

UFW also supports application profiles: the sudo ufw app list command lists the predefined profiles registered by installed packages (Nginx or OpenSSH, for example). With a profile name such as sudo ufw allow 'Nginx Full' you can open both port 80 and port 443 with a single command; this is a more readable alternative to typing port numbers from memory.

Why rule order matters

UFW compares an incoming packet against the rules in the list in order and applies the first matching rule; the rest of the list is not evaluated. That is why a more specific deny rule must not be overridden by a general allow rule that comes before it. To add a specific IP at the top of the list, the command sudo ufw insert 1 deny from 198.51.100.5 to any can be used; that rule is then evaluated before all the other rules added later.

Protecting SSH against brute-force attacks: ufw limit

The SSH port (22 by default) is the most scanned port and the one subjected to the most automated login attempts on any server open to the internet. Using only ufw allow 22/tcp permits the connection but does not limit the number of attempts. UFW's limit action is designed for this: if an IP address makes 6 or more connection attempts to the same port within 30 seconds, UFW starts denying that IP automatically. It is enabled with the command sudo ufw limit ssh or sudo ufw limit 22/tcp. This is a simple but effective protection against brute-force SSH login attempts.

Common mistakes

  • Running ufw enable without allowing the SSH port: this drops the remote connection instantly and locks you out of the server if you have no console access.
  • Using only ufw allow 22/tcp for SSH and skipping ufw limit: it permits the connection but does not limit automated login attempts.
  • Ignoring the importance of rule order: UFW rules are evaluated in order; a deny rule added to block a specific source can be overridden by a more general allow rule that comes before it in the list.
  • Forgetting IPv6: on Ubuntu, UFW is enabled for IPv6 by default as well (IPV6=yes in /etc/default/ufw). Rules added with service names are applied automatically for both IPv4 and IPv6, but from rules written against a specific IPv4 address do not cover IPv6 traffic; a separate rule is needed for IPv6 sources.
  • Skipping verification with ufw status verbose after making a change: carrying on without making sure the rules really are in the expected order and active leads to wrong assumptions.

It is easy to make a syntax mistake when typing these commands by hand; especially when several rules are added one after another, the wrong protocol, a missing to any port pattern or a forgotten from clause can leave the rule doing nothing. The tool below generates the correct ufw command automatically from the action, port, protocol and source IP you choose, and adds the SSH safety warning to the top of every script as a fixed line.