PHP Architect logo

Want to check out an issue? Sign up to receive a special offer.

Ubuntu Firewall Setup in Less Than 5 Minutes (Plus One Step That Will Lock You Out)

Posted by on April 21, 2026



 

Setting up a Virtual Private Server (VPS) without a firewall is asking for trouble. Ideally, you’d have a dedicated security person to handle all of this, but that’s rarely the case. One thing I always do on a fresh Linux server is configure a firewall. It used to be a real headache, but Ubuntu ships with the Uncomplicated Firewall (UFW), and that changes things considerably.

In this video, we’ll cover what a firewall actually does and how to configure UFW on Ubuntu 24.04, which is the current LTS as of this recording (26.04 is right around the corner, but the commands won’t be much different).

Hello developers, and welcome to the PHP Architect Channel! I’m your host, Scott Keck-Warren. If you’re new here, we cover topics related to the PHP ecosystem. Subscribe so you don’t miss our videos.

What is a Firewall?

A software firewall monitors and controls incoming and outgoing network traffic based on rules you define. I like to think of it as a gatekeeper (it decides which connections to allow and which to block based on things like port number and protocol). Without one, every open port on your server is reachable by anyone on the internet, including the automated scanners that are constantly sweeping for vulnerabilities. Unlike a hardware firewall (a physical device on your network), a software firewall runs directly on the server, giving you control over that specific machine with little to no CPU overhead.

Most operating systems now include a built-in firewall, but it’s not always enabled by default.

Tools like https://www.shodan.io/ make it trivial to find every open port on the internet. A zero-day drops, and suddenly, that forgotten open port is a liability. Keeping only necessary ports open is how you control your attack surface.

What Is UFW?

Linux has a built-in firewall called iptables, and it’s extremely powerful.

The problem is that iptables rules look like this:

iptables -A INPUT -p tcp --dport 22 -j ACCEPT

One rule isn’t bad. Ten or fifteen, and the config becomes unreadable fast, and you need to worry about ordering, or you might disable all network traffic.

UFW sits on top of iptables and lets you write firewall rules in something closer to plain English. It comes pre-installed on Ubuntu, so most of you already have it.

The Gotcha That Will Ruin Your Day

Before we go any further, I need to tell you the single most common mistake people make with UFW. I’ve seen it happen to experienced developers, and I might have done it myself once or twice (I’m not saying either way):

Always allow SSH before you enable UFW.

When you enable UFW, the default behavior is to deny all incoming connections unless an explicit “allow” rule exists.

If you enable it without adding an SSH rule first, you’ve locked yourself out. The only fix is to log into your emergency console and disable UFW, if you can even get to it.

So the rule is simple: SSH first, enable second. Every time.

One more tip: if you’re making complex changes, add a crontab entry to automatically disable UFW every five minutes. Worst case, you’re locked out for five minutes:

*/5 * * * * root ufw disable

Do remember to remove this when you’re done making changes.

Installing and Enabling UFW

Let’s start by checking whether UFW is already on your system:

sudo ufw status
Status: inactive

If the command isn’t found, UFW isn’t installed. You can install it with apt:

sudo apt install ufw

Following our rule from before, we’re going to allow SSH first:

sudo ufw allow ssh
Rules updated
Rules updated (v6)

This creates a rule that allows TCP traffic on port 22 (the default SSH port). You can also write it explicitly with “[port number]/[protocol]”:

sudo ufw allow 22/tcp
Skipping adding existing rule
Skipping adding existing rule (v6)

In our case, we’ve already defined the same rule using allow ssh, so we get told it’s already defined.

Both do the same thing, but you’ll need the explicit form for services that don’t have a named rule like “ssh”.

With SSH safely allowed, now you can cross your fingers and 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.

UFW is now running and will start automatically every time your server boots.

We can run ufw status again to see our defined rules.

sudo ufw status
Status: active

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

Allowing and Denying Ports

Your server is locked down, but only SSH works. Let’s fix that.

Say you’re running a web application with FrankenPHP and MySQL. You need HTTP and HTTPS open to the public, but MySQL should stay locked down.

FrankenPHP doesn’t ship with a UFW application profile the way Nginx and SSH do, so add your rules by port number:

sudo ufw allow 80/tcp
Rule added
Rule added (v6)
sudo ufw allow 443/tcp
Rule added
Rule added (v6)

Add an explicit deny rule for MySQL, too. It’s not strictly necessary since UFW blocks everything by default, but it documents intent and stops someone from accidentally opening it later:

sudo ufw deny 3306/tcp
Rule added
Rule added (v6)

Verify with:

sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
22/tcp                     ALLOW       Anywhere
80/tcp                     ALLOW       Anywhere
443/tcp                    ALLOW       Anywhere
3306/tcp                   DENY        Anywhere
22/tcp (v6)                ALLOW       Anywhere (v6)
80/tcp (v6)                ALLOW       Anywhere (v6)
443/tcp (v6)               ALLOW       Anywhere (v6)
3306/tcp (v6)              DENY        Anywhere (v6)

Anyone can look at that output and understand exactly what traffic your server accepts. I find that clarity is genuinely useful when I come back to a server six months later.

We’ll have more after this word from our partners.

Application Profiles

Some services ship with named profiles, which is a bit cleaner than remembering port numbers. To see what’s installed on your system:

sudo ufw app list
Available applications:
  OpenSSH

On a fresh Ubuntu 24.04 install, you’ll usually just see OpenSSH. Install Nginx or Apache, and their profiles show up automatically. You can use a named profile like this:

sudo ufw allow "OpenSSH"
Rule added
Rule added (v6)
sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere
OpenSSH (v6)               ALLOW       Anywhere (v6)

Since FrankenPHP doesn’t ship with a UFW profile, the manual port rules we wrote earlier are the right approach. Named profiles are convenient when they exist, but they’re not required.

Rate Limiting

Your SSH port is open to the internet, which means bots are ALREADY trying to brute-force their way in. Check /var/log/auth.log if you don’t believe me. You can watch it happen in real time. It’s equal parts fascinating and horrifying.

Fortunately, UFW has this covered:

sudo ufw limit ssh
Rules updated
Rules updated (v6)
sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
22/tcp                     LIMIT       Anywhere
80/tcp                     ALLOW       Anywhere
443/tcp                    ALLOW       Anywhere
3306/tcp                   DENY        Anywhere
22/tcp (v6)                LIMIT       Anywhere (v6)
80/tcp (v6)                ALLOW       Anywhere (v6)
443/tcp (v6)               ALLOW       Anywhere (v6)
3306/tcp (v6)              DENY        Anywhere (v6)

This updates your existing SSH allow rule with a rate-limited version. It blocks any IP that makes more than 6 connection attempts within 30 seconds. Legitimate users never hit that limit. Automated scripts get shut down fast.

Managing Your Rules

Over time, you’ll need to clean up rules as your server changes. To see rules with line numbers:

sudo ufw status numbered
sudo ufw status numbered
Status: active

     To                         Action      From
     --                         ------      ----
[ 1] 22/tcp                     LIMIT IN    Anywhere
[ 2] 80/tcp                     ALLOW IN    Anywhere
[ 3] 443/tcp                    ALLOW IN    Anywhere
[ 4] 3306/tcp                   DENY IN     Anywhere
[ 5] OpenSSH                    ALLOW IN    Anywhere
[ 6] 22/tcp (v6)                LIMIT IN    Anywhere (v6)
[ 7] 80/tcp (v6)                ALLOW IN    Anywhere (v6)
[ 8] 443/tcp (v6)               ALLOW IN    Anywhere (v6)
[ 9] 3306/tcp (v6)              DENY IN     Anywhere (v6)
[10] OpenSSH (v6)               ALLOW IN    Anywhere (v6)

Delete by number:

sudo ufw delete 10
Deleting:
 allow OpenSSH
Proceed with operation (y|n)? y
Rule deleted (v6)

And if you ever want to start completely fresh:

sudo ufw reset
Resetting all rules to installed defaults. This may disrupt existing ssh
connections. Proceed with operation (y|n)? y
Backing up 'user.rules' to '/etc/ufw/user.rules.20260413_141509'
Backing up 'before.rules' to '/etc/ufw/before.rules.20260413_141509'
Backing up 'after.rules' to '/etc/ufw/after.rules.20260413_141509'
Backing up 'user6.rules' to '/etc/ufw/user6.rules.20260413_141509'
Backing up 'before6.rules' to '/etc/ufw/before6.rules.20260413_141509'
Backing up 'after6.rules' to '/etc/ufw/after6.rules.20260413_141509'

That wipes every rule and disables UFW. If you reset, remember the golden rule: allow SSH before you enable it again.

It’s also important to notice that during our reset, UFW backups the rules just in case we didn’t mean to.

What You Need To Know

  1. UFW is a readable frontend for iptables. It makes firewall management something you can do in a few commands instead of a full afternoon.
  2. Allow SSH before enabling UFW. ALWAYS. No exceptions.
  3. Use sudo ufw allow and sudo ufw deny with port numbers for services like FrankenPHP that don’t have named profiles.
  4. Add sudo ufw limit ssh to throttle brute-force login attempts.
  5. Use sudo ufw status numbered to audit your rules and sudo ufw delete to remove the ones you no longer need.

 

Leave a comment

Use the form below to leave a comment:

 

Our Partners

Collaborating with industry leaders to bring you the best PHP resources and expertise