🏗️ 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):
# 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/24Using firewalld (CentOS):
# 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" acceptScenario 2: Database Server
A database server should only allow access from application servers, with no external exposure.
# 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 --reloadScenario 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.
# 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.