Skip to content

🏗️ Real-World Scenarios

Scenario 1: Web Server

Your server runs Nginx + Node.js + MySQL, needs to open web ports and restrict database access.

Using UFW (Ubuntu):

bash
# Enable firewall
sudo ufw enable

# Allow SSH (restricting source is more secure)
sudo ufw allow from 203.0.113.0/24 to any port 22

# Allow web services
sudo ufw allow "Nginx Full"

# Only allow local access to MySQL
# (MySQL only listens on 127.0.0.1 by default — this is an extra safeguard)
sudo ufw allow from 127.0.0.1 to any port 3306

# Allow internal network to access Node.js debug port
sudo ufw allow from 192.168.1.0/24 to any port 9229

# View final rules
sudo ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip

To                         Action      From
--                         ------      ----
22/tcp                     ALLOW IN    203.0.113.0/24
80,443/tcp (Nginx Full)    ALLOW IN    Anywhere
3306                       ALLOW IN    127.0.0.1
9229                       ALLOW IN    192.168.1.0/24

Using firewalld (CentOS):

bash
# Start firewalld
sudo systemctl start firewalld
sudo systemctl enable firewalld

# Open web services
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https

# Restrict SSH source
sudo firewall-cmd --permanent --add-rich-rule='
  rule family="ipv4"
  source address="203.0.113.0/24"
  port protocol="tcp" port="22"
  accept'

# Allow internal network to access MySQL
sudo firewall-cmd --permanent --add-rich-rule='
  rule family="ipv4"
  source address="192.168.1.0/24"
  port protocol="tcp" port="3306"
  accept'

sudo firewall-cmd --reload

# Verify
sudo firewall-cmd --list-all
public (active)
  target: default
  interfaces: eth0
  services: dhcpv6-client http https
  rich rules:
    rule family="ipv4" source address="203.0.113.0/24" port port="22" protocol="tcp" accept
    rule family="ipv4" source address="192.168.1.0/24" port port="3306" protocol="tcp" accept

Scenario 2: Database Server

A database server should only allow access from application servers, with no external exposure.

bash
# UFW approach
sudo ufw default deny incoming
sudo ufw allow from 192.168.1.100 to any port 3306    # App server 1
sudo ufw allow from 192.168.1.101 to any port 3306    # App server 2
sudo ufw allow from 10.0.0.0/24 to any port 22        # Management subnet SSH
sudo ufw allow 9100/tcp                                # Prometheus monitoring
sudo ufw enable

# firewalld approach
sudo firewall-cmd --permanent --set-default-zone=drop   # Most strict

# Only trust internal management SSH
sudo firewall-cmd --permanent --zone=drop --add-rich-rule='
  rule family="ipv4"
  source address="10.0.0.0/24"
  port protocol="tcp" port="22"
  accept'

# Only allow application servers to access MySQL
sudo firewall-cmd --permanent --zone=drop --add-rich-rule='
  rule family="ipv4"
  source address="192.168.1.100"
  port protocol="tcp" port="3306"
  accept'

sudo firewall-cmd --permanent --zone=drop --add-rich-rule='
  rule family="ipv4"
  source address="192.168.1.101"
  port protocol="tcp" port="3306"
  accept'

sudo firewall-cmd --reload

Scenario 3: DMZ Setup

A DMZ (Demilitarized Zone) is like a visitors' reception room in an apartment complex — outsiders can come in, but they can't access your home.

bash
# Use firewalld's dmz zone
sudo firewall-cmd --permanent --zone=dmz --add-service=http
sudo firewall-cmd --permanent --zone=dmz --add-service=https
sudo firewall-cmd --permanent --zone=dmz --add-service=ssh

# Bind DMZ interface to the dmz zone
sudo firewall-cmd --permanent --zone=dmz --change-interface=eth0

# Bind internal interface to the trusted zone
sudo firewall-cmd --permanent --zone=trusted --change-interface=eth1

# DMZ server can access internal database (specific port)
sudo firewall-cmd --permanent --zone=dmz --add-rich-rule='
  rule family="ipv4"
  destination address="192.168.1.200"
  port protocol="tcp" port="3306"
  accept'

# Enable masquerading (NAT) so internal machines can access the internet
sudo firewall-cmd --permanent --zone=external --add-masquerade

sudo firewall-cmd --reload

# View DMZ configuration
sudo firewall-cmd --zone=dmz --list-all
dmz (active)
  target: default
  interfaces: eth0
  services: http https ssh
  rich rules:
    rule family="ipv4" destination address="192.168.1.200"
    port port="3306" protocol="tcp" accept

💡 Tip: 💡 Security best practices summary: Deny all inbound by default, only open necessary ports. Restrict SSH source IP — don't open it to the world. Database ports should only be accessible from application servers. Use non-standard ports (e.g., SSH on 2222) to reduce scanning. Regularly review firewall rules and clean up unused ones. Enable logging and monitor for anomalous connections. Test rules with temporary rules first, then make permanent once confirmed.