Learn 🧠 All Concepts (20) 🤖 What is an LLM? 📚 RAG Explained ⚡ AI Agents 💻 Run AI Locally 🇮🇳 AI in India 📖 Learn Tracks 🔧 DevOps Track ⚙️ AI Ops Track 🗺️ AI Engineer Roadmap
Tools 🔧 AI Tools Directory 🔓 Open Source AI ⭐ Top GitHub Repos ✦ Claude Skill Repos 🚀 Ready-to-Deploy Projects
Build 🏗️ Build Hub 🎯 Master Prompts 🧩 RAG Agents 🚀 App Megaprompts
Workflows ⚡ All Workflows (22) 🎥 Text to Video 🎞️ Image to Video 🔊 Text to Speech ♻️ Automation
Resources 🧪 Colab Notebooks ⚙️ n8n Workflows 📈 Algo Trading 💰 Passive Income
🗂️ Browse All Topics About AItheGuru
Learn Linux for Production Support Suresh locks down the open server
Linux for Production Support Ch 29 / 32 Advanced
🛡️

Suresh locks down the open server

ufw, firewalld, fail2ban, nmap — network security that takes an afternoon

⏱ 13 min 6 commands 5 takeaways
🛡️
In this chapter
Suresh
Engineer who inherited an exposed server
The story

Suresh inherited a server that was accessible from everywhere. Port 22 (SSH) was open to the internet. Port 3306 (MySQL) was open to the internet. The application ports were open to the internet. It had been running this way for 2 years.

He ran a port scan from his laptop using an online tool. 14 ports were publicly accessible. He could see the MySQL port. He could see Redis. He could see the internal admin panel.

He spent one afternoon locking it down. Here is what he did.

UFW — UNCOMPLICATED FIREWALL (UBUNTU/DEBIAN)

ufw is a frontend for iptables that makes firewall rules readable and manageable.

sudo ufw status                 # see current rules and whether ufw is active
sudo ufw status verbose         # more detail
sudo ufw status numbered        # show rule numbers (needed for deletion)
# Enable ufw (CAREFUL: enable SSH first or you will lock yourself out):
sudo ufw allow 22/tcp           # ALWAYS do this first
sudo ufw enable                 # now enable

BASIC RULES

# Allow by port number:
sudo ufw allow 80/tcp           # HTTP
sudo ufw allow 443/tcp          # HTTPS
sudo ufw allow 22/tcp           # SSH
# Deny a port:
sudo ufw deny 3306/tcp          # block MySQL from outside
# Allow by service name:
sudo ufw allow ssh              # same as allow 22/tcp
sudo ufw allow http             # same as allow 80/tcp
sudo ufw allow https            # same as allow 443/tcp
# Allow a specific IP to access a specific port:
sudo ufw allow from 10.0.0.5 to any port 5432     # only this IP can reach PostgreSQL
sudo ufw allow from 10.0.0.0/24 to any port 5432  # only this subnet can reach PostgreSQL
# Allow from an IP on any port (trusted server):
sudo ufw allow from 10.0.0.10
# Delete a rule:
sudo ufw status numbered        # get the number
sudo ufw delete 3               # delete rule number 3
# Reset all rules (start over):
sudo ufw reset

SURESH'S LOCKDOWN

# Step 1: Only allow what is needed from the internet:
sudo ufw default deny incoming      # block everything by default
sudo ufw default allow outgoing     # allow all outbound
sudo ufw allow 22/tcp               # SSH (will restrict to specific IPs later)
sudo ufw allow 80/tcp               # HTTP
sudo ufw allow 443/tcp              # HTTPS
# Step 2: Allow internal services only from the internal network:
sudo ufw allow from 10.0.0.0/24 to any port 5432   # PostgreSQL
sudo ufw allow from 10.0.0.0/24 to any port 6379   # Redis
sudo ufw allow from 10.0.0.0/24 to any port 8080   # Internal app port
sudo ufw allow from 10.0.0.0/24 to any port 9200   # Elasticsearch
# Step 3: Restrict SSH to known IPs:
sudo ufw delete allow 22/tcp        # remove the open SSH rule
sudo ufw allow from 203.0.113.10 to any port 22    # only office IP
sudo ufw allow from 203.0.113.11 to any port 22    # only VPN IP
# Step 4: Enable:
sudo ufw enable
sudo ufw status verbose

FIREWALLD — CENTOS AND RHEL

sudo firewall-cmd --state                           # running?
sudo firewall-cmd --list-all                        # all rules
# Add rules:
sudo firewall-cmd --add-service=http --permanent
sudo firewall-cmd --add-service=https --permanent
sudo firewall-cmd --add-port=8080/tcp --permanent
# Block a service:
sudo firewall-cmd --remove-service=mysql --permanent
# Allow a specific IP to a port:
sudo firewall-cmd --add-rich-rule='rule family=ipv4 source address=10.0.0.5 port protocol=tcp port=5432 accept' --permanent
# Apply changes:
sudo firewall-cmd --reload

IPTABLES — THE UNDERLYING RULES

ufw and firewalld both write iptables rules. You can read them directly:

sudo iptables -L -n -v          # all rules with packet counts
sudo iptables -L INPUT -n       # just the INPUT chain (inbound traffic rules)
sudo iptables-save              # export all rules to stdout

FAIL2BAN — AUTOMATIC IP BANNING

Fail2ban watches log files and bans IPs that fail authentication repeatedly. Essential for any server with SSH exposed to the internet.

sudo apt install fail2ban
# Default config bans IPs with 5 failed SSH logins in 10 minutes for 10 minutes:
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo nano /etc/fail2ban/jail.local
# Key settings:
[sshd]
enabled = true
maxretry = 3           # ban after 3 failures (not 5)
findtime = 600         # within 10 minutes
bantime = 3600         # ban for 1 hour
sudo systemctl enable fail2ban && sudo systemctl start fail2ban
# Check status:
sudo fail2ban-client status sshd            # see SSH jail stats
sudo fail2ban-client status sshd | grep "Banned IP"   # currently banned IPs
# Unban an IP you accidentally locked out:
sudo fail2ban-client set sshd unbanip 203.0.113.10

PORT SCANNING YOUR OWN SERVER

Before and after any firewall changes, scan your own server to see what is exposed:

nmap -sV YOUR_SERVER_IP         # scan from your laptop
sudo nmap -sV localhost         # scan from the server itself
# Quick open port check:
nmap -p 1-65535 --open YOUR_SERVER_IP

After Suresh finished, a re-scan showed only ports 80, 443, and 22 (restricted to 2 IPs) visible from the internet. The MySQL, Redis, Elasticsearch, and admin panel ports were invisible. The server that had been exposed for 2 years was secured in one afternoon.

Key takeaways

sudo ufw default deny incoming then explicitly allow only what is needed — deny by default is the right starting point

Always allow SSH before enabling ufw — sudo ufw allow 22/tcp then sudo ufw enable — wrong order locks you out

Restrict database ports to internal network IPs only — MySQL and PostgreSQL should never be open to the internet

fail2ban watches logs and auto-bans IPs with repeated failures — install it on any server with SSH exposed

nmap your own server before and after changes — see exactly what an attacker would see from the internet

Commands from this chapter
$ sudo ufw allow 22/tcp && sudo ufw enable
Allow SSH first, THEN enable firewall — order matters
$ sudo ufw allow from 10.0.0.0/24 to any port 5432
Allow only internal subnet to reach PostgreSQL
$ sudo ufw status numbered
List all firewall rules with numbers for deletion
$ sudo apt install fail2ban && sudo systemctl enable fail2ban
Install and enable automatic IP banning
$ sudo fail2ban-client status sshd
Check SSH jail — see failed attempts and banned IPs
$ nmap -p 1-65535 --open YOUR_SERVER_IP
Scan your own server to see what is exposed from outside