Introduction
A DMZ (Demilitarized Zone) is a network segment that sits between your internal trusted network and the untrusted internet. It hosts services that must be accessible from the internet (web servers, email, VPN endpoints) while protecting your internal network from direct internet access.
Why DMZ?
Without DMZ: Internet → Firewall → Internal Network (all services mixed)
With DMZ: Internet → Firewall → DMZ (public services) + Firewall → Internal Network
If an attacker compromises a web server in the DMZ, they still face another firewall barrier before reaching your internal network.
DMZ Design Patterns
Single Firewall (Three-Leg)
Internet
|
[Firewall] ---- DMZ (eth1: 192.168.1.0/24)
|
Internal (eth2: 10.0.0.0/8)Simple, cost-effective. One firewall with 3 interfaces. Risk: firewall is single point of failure.
Dual Firewall (Recommended for production)
Internet
|
[Firewall 1 - Edge]
|
DMZ (192.168.1.0/24)
|
[Firewall 2 - Internal]
|
Internal Network (10.0.0.0/8)Best security. Different vendors recommended (different exploits). Higher cost.
Firewall Rules for DMZ (pf/iptables concept)
# iptables rules for single-firewall DMZ
# From Internet to DMZ: allow only specific services
iptables -A FORWARD -i eth0 -o eth1 -p tcp --dport 80 -j ACCEPT # HTTP to web server
iptables -A FORWARD -i eth0 -o eth1 -p tcp --dport 443 -j ACCEPT # HTTPS to web server
iptables -A FORWARD -i eth0 -o eth1 -p tcp --dport 25 -j ACCEPT # SMTP to mail server
# From DMZ to Internet: allow established connections + DNS
iptables -A FORWARD -i eth1 -o eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -i eth1 -o eth0 -p udp --dport 53 -j ACCEPT
# From DMZ to Internal: DENY by default
iptables -A FORWARD -i eth1 -o eth2 -j DROP
# From Internal to DMZ: allow management
iptables -A FORWARD -i eth2 -o eth1 -p tcp --dport 22 -j ACCEPT # SSH to manage servers
# From Internal to Internet: allow all
iptables -A FORWARD -i eth2 -o eth0 -j ACCEPT
iptables -A FORWARD -i eth0 -o eth2 -m state --state ESTABLISHED,RELATED -j ACCEPT
# Default deny
iptables -P FORWARD DROPServices Typically in DMZ
| Service | Port | Notes |
|---|---|---|
| Web server (nginx/Apache) | 80, 443 | Reverse proxy to internal app servers |
| Mail server | 25, 587, 993 | SMTP, submission, IMAPS |
| VPN gateway | 1194, 443 | OpenVPN, WireGuard |
| DNS resolver (public) | 53 | Only if hosting public DNS |
| Jump host/Bastion | 22 | For admin access to DMZ |
Reverse Proxy in DMZ
A reverse proxy (nginx) in the DMZ proxies requests to internal app servers. The internal servers never touch the internet:
# DMZ nginx reverse proxy
server {
listen 443 ssl;
server_name app.company.com;
ssl_certificate /etc/ssl/app.crt;
ssl_certificate_key /etc/ssl/app.key;
location / {
# Forward to internal app server (10.0.1.10)
proxy_pass http://10.0.1.10:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}Microsegmentation in DMZ
Don't put all DMZ servers on one flat subnet. Segment by function:
DMZ Web Tier: 192.168.1.0/27 (web servers, load balancers)
DMZ App Tier: 192.168.1.32/27 (application servers)
DMZ DB Tier: 192.168.1.64/27 (databases — if they must be in DMZ)
DMZ Mgmt: 192.168.1.96/27 (jump hosts, monitoring)Rules between tiers: Web → App allowed; App → DB allowed; DMZ → Internal restricted.
Monitoring DMZ
# Install fail2ban on DMZ servers to block brute force
apt install fail2ban
# /etc/fail2ban/jail.local
[sshd]
enabled = true
maxretry = 3
bantime = 3600
findtime = 600
# Monitor connection attempts
netstat -an | grep ESTABLISHED | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -rnSummary
- DMZ isolates internet-facing services from your internal network
- Use dual firewall design for production environments
- Default-deny between DMZ and internal — only allow what's explicitly needed
- Use a reverse proxy to prevent direct internet access to internal servers
- Segment the DMZ itself — web, app, database tiers
