Firewall Basics
A firewall controls which network traffic can reach your server. Without one, every service listening on a port is accessible to the entire internet.
Rule of thumb: Block everything, then allow only what you need.
Hetzner Cloud Firewall vs OS Firewall
Hetzner offers a Cloud Firewall in their console. This filters traffic before it reaches your server. You should use both:
- Hetzner Cloud Firewall: First line of defense, filters at the network level
- OS Firewall (UFW/firewalld): Second line, catches anything the cloud firewall misses
UFW (Recommended for Ubuntu)
UFW (Uncomplicated Firewall) is the simplest option for Ubuntu servers.
#### Basic Setup
# Set defaults
sudo ufw default deny incoming
sudo ufw default allow outgoing
# Allow SSH (use your custom port)
sudo ufw allow 2222/tcp comment 'SSH'
# Allow web traffic
sudo ufw allow 80/tcp comment 'HTTP'
sudo ufw allow 443/tcp comment 'HTTPS'
# Enable the firewall
sudo ufw enable
#### Rules for Common Services
# Mailcow SMTP
sudo ufw allow 25/tcp comment 'SMTP'
sudo ufw allow 587/tcp comment 'SMTP submission'
sudo ufw allow 465/tcp comment 'SMTPS'
# Mailcow IMAP
sudo ufw allow 993/tcp comment 'IMAPS'
sudo ufw allow 143/tcp comment 'IMAP'
# Coolify (during initial setup only)
sudo ufw allow 8000/tcp comment 'Coolify dashboard'
firewalld (For RHEL/Rocky/Alma)
If you're on a RHEL-based system:
# Check status
sudo firewall-cmd --state
# Add permanent rules
sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
# Custom port
sudo firewall-cmd --permanent --add-port=2222/tcp
# Reload
sudo firewall-cmd --reload
Docker and Firewalls: The Gotcha
This is the #1 firewall mistake on Docker hosts.
Docker modifies iptables directly, bypassing UFW. If you expose a port in Docker (-p 5432:5432), that port is accessible from the internet regardless of your UFW rules.
Solutions:
1. Bind to localhost: Use 127.0.0.1:5432:5432 instead of 5432:5432
2. Use Docker networks: Services on the same Docker network can communicate without exposed ports
3. Configure Docker to respect UFW: Add to /etc/docker/daemon.json:
{
"iptables": false
}
Warning: Disabling Docker's iptables management breaks some Docker networking features. Test thoroughly.
Verification
Always verify your firewall is working:
# Check UFW status
sudo ufw status verbose
# Check what's actually listening
sudo ss -tlnp
# Scan from outside (use a different machine)
nmap -Pn your_server_ip
Our Recommended Configuration
For a Hetzner VPS running Coolify + Mailcow + web apps:
| Port | Protocol | Purpose |
|---|---|---|
| 2222 | TCP | SSH (custom port) |
| 80 | TCP | HTTP (redirects to HTTPS) |
| 443 | TCP | HTTPS |
| 25 | TCP | SMTP |
| 587 | TCP | SMTP submission |
| 465 | TCP | SMTPS |
| 993 | TCP | IMAPS |
Everything else should be denied.
Need the complete security configuration? Our guide covers firewall rules, Docker networking, and how to avoid the common pitfalls that leave databases exposed to the internet.
Want the Complete Setup Guide?
This blog post covers the basics. Our premium guide includes step-by-step commands, exact configurations, and the solutions to every gotcha we encountered.