Configuring UFW Firewall Rules On Linux Servers

Configuring UFW Firewall Rules On Linux Servers

What You’ll Need

  • Hetzner VPS or Contabo VPS running Ubuntu 22.04 LTS or Debian 12
  • DigitalOcean droplet (alternative infrastructure provider)
  • Root or sudo privileges on your remote server
  • Namecheap registered domain name (if routing traffic for public web applications)

Table of Contents

Understanding UFW Architecture and Default Policies

Securing a Linux server starts with controlling network access. Uncomplicated Firewall (UFW) serves as a user-friendly frontend to iptables and nftables. It handles firewall rules without requiring you to master complex table syntax. When I provision a new instance on a Hetzner VPS or DigitalOcean, UFW is the very first defensive layer I enable.

Before enabling UFW, you must understand packet evaluation order and default behaviors. By default, UFW drops incoming connection requests and allows outgoing connection requests. If you turn UFW on without configuring an explicit SSH rule, you will immediately lock yourself out of your server.

UFW uses configuration files stored in /etc/default/ufw and /etc/ufw/. The main control file defines how default chains behave. You can inspect your current configuration file with this command:

cat /etc/default/ufw

The output defines system policies across all interfaces:

IPV6=yes
DEFAULT_INPUT_POLICY="DROP"
DEFAULT_OUTPUT_POLICY="ACCEPT"
DEFAULT_FORWARD_POLICY="DROP"
DEFAULT_APPLICATION_POLICY="SKIP"
MANAGE_BUILTINS=no
IPT_SYSCTL=/etc/ufw/sysctl.conf
MANAGE_IPS=yes

If your configuration shows DEFAULT_INPUT_POLICY="ACCEPT", modify it immediately using CLI commands. I prefer setting defaults explicitly through commands rather than manually editing the configuration file to prevent syntax errors.

Reset UFW to clean state if you want to eliminate existing rules:

sudo ufw reset

The terminal prompts for confirmation before wiping custom rules:

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.20260330_120000'
Backing up 'before.rules' to '/etc/ufw/before.rules.20260330_120000'
Backing up 'after.rules' to '/etc/ufw/after.rules.20260330_120000'
Backing up 'user6.rules' to '/etc/ufw/user6.rules.20260330_120000'
Backing up 'before6.rules' to '/etc/ufw/before6.rules.20260330_120000'
Backing up 'after6.rules' to '/etc/ufw/after6.rules.20260330_120000'

Set default security policies across the system:

sudo ufw default deny incoming
sudo ufw default allow outgoing

This configuration ensures that any inbound traffic not explicitly allowed gets rejected, while internal applications can pull system updates, make API requests, and send outbound logs.

Setting Up Core Service Rules and Application Profiles

With default drop policies configured, you must open essential infrastructure ports before enabling the firewall daemon. Always permit SSH connections first to safeguard remote administration sessions.

To allow standard SSH over port 22:

sudo ufw allow 22/tcp

If your server runs SSH on a non-standard port like 2222 to reduce automated brute-force attempts, allow that custom port explicitly:

sudo ufw allow 2222/tcp

Public web platforms require open ports for standard HTTP and HTTPS traffic. If you are running web services, follow our detailed guide on Configuring Nginx Reverse Proxy with Certbot SSL to complete your public web stack setup. Open standard web ports with these commands:

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

UFW includes application profiles stored in /etc/ufw/applications.d/. These profiles map human-readable application names directly to specified protocol ports. Check available application profiles on your system:

sudo ufw app list

You will see output similar to this:

Available applications:
  Nginx Full
  Nginx HTTP
  Nginx HTTPS
  OpenSSH

Allow an entire profile directly by specifying its name:

sudo ufw allow "Nginx Full"

If you manage custom backend systems, you can define your own application profile. For instance, if you are Deploying Self-Hosted PocketBase on Cloud Servers, you can create a profile for PocketBase on port 8090. Create a file named /etc/ufw/applications.d/pocketbase:

[PocketBase]
title=PocketBase Backend Server
description=Self-contained database and real-time backend engine.
ports=8090/tcp

Verify your custom application profile is loaded:

sudo ufw app info PocketBase

The console displays the profile parameters:

Profile: PocketBase
Title: PocketBase Backend Server
Description: Self-contained database and real-time backend engine.

Port:
  8090/tcp

Allow the new profile through UFW:

sudo ufw allow PocketBase

Now enable UFW. Review your terminal carefully because enabling the service activates all rules immediately:

sudo ufw enable

Confirm activation status:

Command may disrupt existing ssh connections. Proceed with operation (y|n)? y
Firewall is active and enabled on system startup

Verify the detailed list of active rules:

sudo ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: loaded

To                         Action      From
--                         ------      ----
22/tcp                     ALLOW IN    Anywhere                  
80/tcp (Nginx Full)        ALLOW IN    Anywhere                  
443/tcp (Nginx Full)       ALLOW IN    Anywhere                  
8090/tcp (PocketBase)      ALLOW IN    Anywhere                  
22/tcp (v6)                ALLOW IN    Anywhere (v6)             
80/tcp (Nginx Full (v6))   ALLOW IN    Anywhere (v6)             
443/tcp (Nginx Full (v6))  ALLOW IN    Anywhere (v6)             
8090/tcp (PocketBase (v6)) ALLOW IN    Anywhere (v6)             

💡 Fast-Track Your Project: Don’t want to configure this yourself? I build custom n8n pipelines and bots. Message me with code SYS3-HUGO.

Advanced UFW Rule Management and IP Filtering

Broad rule definitions allowing full access from anywhere are acceptable for public websites, but administrative endpoints require strict network boundaries. Restricting infrastructure access to single static IPs or specific subnets minimizes exposure.

Allow connection to SSH (port 22) only from a trusted administrator IP address 198.51.100.45:

sudo ufw allow from 198.51.100.45 to any port 22 proto tcp

Allow an internal corporate subnet 192.168.1.0/24 access to a self-hosted PostgreSQL database on port 5432:

sudo ufw allow from 192.168.1.0/24 to any port 5432 proto tcp

If your server features multiple network interfaces (such as eth0 for external traffic and eth1 or tailscale0 for internal traffic), bind rules directly to specific network adapters.

Allow access to MySQL port 3306 exclusively over internal interface eth1:

sudo ufw allow in on eth1 to any port 3306 proto tcp

Deny traffic explicitly from malicious or offending subnets:

sudo ufw deny from 203.0.113.0/24

To prevent automated scripts from hammering exposed endpoints, use built-in rate limiting. UFW limit rules drop connections from IP addresses that attempt 6 or more connections within a 30-second window:

sudo ufw limit 22/tcp

Managing rules over time requires working with rule numbers. List active rules sequentially:

sudo ufw status numbered

The output shows numbered indices:

Status: active

     To                         Action      From
     --                         ------      ----
[ 1] 22/tcp                     LIMIT IN    Anywhere                  
[ 2] 80/tcp                     ALLOW IN    Anywhere                  
[ 3] 443/tcp                    ALLOW IN    Anywhere                  
[ 4] 5432/tcp                   ALLOW IN    192.168.1.0/24            
[ 5] 203.0.113.0/24             DENY IN     Anywhere                  

Delete a specific rule by supplying its exact index number:

sudo ufw delete 5

Insert a high-priority rule at position 1 to make sure evaluation takes place before downstream wildcard rules:

sudo ufw insert 1 allow from 198.51.100.50 to any port 22 proto tcp

Check the updated numbered list to verify rule order:

sudo ufw status numbered
Status: active

     To                         Action      From
     --                         ------      ----
[ 1] 22/tcp                     ALLOW IN    198.51.100.50             
[ 2] 22/tcp                     LIMIT IN    Anywhere                  
[ 3] 80/tcp                     ALLOW IN    Anywhere                  
[ 4] 443/tcp                    ALLOW IN    Anywhere                  
[ 5] 5432/tcp                   ALLOW IN    192.168.1.0/24            

NAT Port Forwarding and UFW Log Management

UFW can operate as a edge router or internal proxy by forwarding incoming packets on external interfaces directly to underlying private networks, container networks, or virtual machines.

First, enable kernel-level IP forwarding. Open /etc/ufw/sysctl.conf:

sudo nano /etc/ufw/sysctl.conf

Uncomment or insert these kernel variables to allow packet routing across interfaces:

net/ipv4/ip_forward=1
net/ipv6/conf/default/forwarding=1
net/ipv6/conf/all/forwarding=1

Next, enable packet forwarding in /etc/default/ufw:

sudo nano /etc/default/ufw

Change DEFAULT_FORWARD_POLICY from "DROP" to "ACCEPT":

DEFAULT_FORWARD_POLICY="ACCEPT"

Configure Network Address Translation (NAT) rules inside /etc/ufw/before.rules. Place your NAT definitions before the standard filter table configuration.

Open /etc/ufw/before.rules:

sudo nano /etc/ufw/before.rules

Add the complete NAT block at the very top of the file, above the default *filter line:

# NAT table configuration
*nat
:PREROUTING ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]

# Forward traffic coming into port 8080 on eth0 to internal container IP 10.8.0.5 on port 80
-A PREROUTING -i eth0 -p tcp --dport 8080 -j DNAT --to-destination 10.8.0.5:80

# Masquerade internal network traffic egressing out eth0
-A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE

COMMIT

Reload UFW to apply kernel routing and NAT rule structures:

sudo ufw reload

Firewall visibility is essential for tracking suspicious activity and auditing connection patterns. Manage logging levels with the logging command:

sudo ufw logging medium

Available logging levels include:

  • off: Disables logging entirely.
  • low: Logs blocked packets that match default policies or explicit block rules.
  • medium: Logs low level activity plus allowed connections, invalid packets, and new connections.
  • high: Logs everything with rate limiting.
  • full: Logs all packets without rate limits (generates massive log volume).

UFW writes packet decision logs directly to /var/log/ufw.log. Monitor raw log entries in real-time:

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

Log lines contain fields detailing matched rules, source networks, and ports:

Mar 30 12:45:10 server01 kernel: [UFW BLOCK] IN=eth0 OUT= MAC=52:54:00:12:34:56:52:54:00:65:43:21:08:00 SRC=198.51.100.99 DST=192.0.2.1 LEN=40 TOS=0x00 PREC=0x00 TTL=245 ID=54321 PROTO=TCP SPT=44123 DPT=23 WINDOW=65535 SYN URGP=0

Field definitions:

  • IN: Interface where packet entered the host machine (eth0).
  • SRC: Originating IP address of the traffic payload (198.51.100.99).
  • DST: Target IP address belonging to your server (192.0.2.1).
  • SPT: Source port assigned by requesting client (44123).
  • DPT: Destination port targeted on your host server (23 / Telnet).
  • SYN: Indicates an initial connection establishment attempt.

For production clusters, parsing raw text files manually on each server quickly becomes unmanageable. Standardize your infrastructure monitoring by Configuring Centralized Log Aggregation with Grafana Loki to stream /var/log/ufw.log entries directly into a central dashboard for real-time security alerts and threat analysis.

Getting Started

Building a secure Linux server starts with choosing host infrastructure, locking down unused ports, and auditing access controls.

  1. Deploy a secure server instance using a provider like Hetzner VPS, Contabo VPS, or a DigitalOcean droplet.
  2. Domain resolution for web services can be managed via Namecheap.
  3. Connect over SSH and apply default deny policies immediately.
  4. Open administrative SSH and web application ports before turning UFW on.
  5. Set up logging to monitor unexpected traffic patterns.

Outsource Your Automation

Don’t have time? I build production n8n workflows, WhatsApp bots, and fully automated YouTube Shorts pipelines. Hire me on Fiverr, mention SYS3-HUGO for priority. Or DM at chasebot.online.

Want to automate this yourself?

Start with n8n Cloud (free tier available) or self-host on a Hetzner VPS for full control.

Want this engine running on your own VPS?

This blog publishes itself — daily, unattended, on free API tiers. The full engine, Hugo theme, and setup guide are available as System 3.

Get System 3
system online