A firewall decides which network connections may reach your server. A web server usually needs just three ports open: 22 for SSH, 80 for HTTP and 443 for HTTPS. Everything else should be closed.
Always allow SSH before turning the firewall on. Otherwise the firewall closes your own connection and you need the host’s web console to get back in.
Allow SSH first, then the web ports 80 and 443, then switch the firewall on. On Ubuntu and Debian the tool is UFW; on AlmaLinux, Rocky Linux and Fedora it is firewalld. Everything not explicitly allowed is then blocked from outside.
What a firewall does here
A server firewall decides which incoming connections are accepted, by port number. A web server only needs three open to the world: 22 for SSH, 80 for HTTP and 443 for HTTPS. Everything else, such as the database on 3306 or an app on 3000, should only be reachable from the server itself. Many services listen on all addresses by default, so the firewall is what keeps them private.
Ubuntu and Debian: UFW
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status verbose
UFW denies all other incoming traffic and allows all outgoing traffic by default. To remove a rule later, list them with numbers and delete by number:
sudo ufw status numbered
sudo ufw delete 3
AlmaLinux, Rocky Linux and Fedora: firewalld
firewalld is usually installed and running already.
sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
sudo firewall-cmd --list-all
--permanent saves the rule; --reload applies saved rules.
Allow a port only from one address
Some services should be reachable, but only by you. For example, to allow a database connection only from your office IP:
sudo ufw allow from 198.51.100.7 to any port 3306 proto tcp
With firewalld, use a rich rule:
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="198.51.100.7" port port="3306" protocol="tcp" accept'
sudo firewall-cmd --reload
The same approach can restrict SSH to known addresses, which stops almost all password-guessing. Only do this if your own IP address is fixed, or you may lock yourself out.
Docker bypasses UFW
Docker writes its own firewall rules, and a container started with -p 8080:80 is reachable from the internet even if UFW blocks port 8080. Publish container ports to the local address only, and put Nginx in front:
docker run -p 127.0.0.1:8080:80 myapp
Slow down password guessing with fail2ban
Even with key-only SSH, bots try thousands of logins a day, filling logs. fail2ban watches logs and temporarily blocks addresses that fail too often:
sudo apt install fail2ban
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd
On RHEL-based systems, install it from EPEL with sudo dnf install epel-release fail2ban. The SSH protection is on by default on Debian and Ubuntu; elsewhere, create /etc/fail2ban/jail.local with an [sshd] section containing enabled = true.
SSH on a different port
If you moved SSH to, say, port 2222, open that port instead of the SSH service:
sudo ufw allow 2222/tcp
sudo firewall-cmd --permanent --add-port=2222/tcp
On RHEL-based systems, SELinux also has to allow the new port: sudo semanage port -a -t ssh_port_t -p tcp 2222.
Your host may have a firewall too
Many cloud providers offer a network firewall in their control panel, outside the server. If a port is open on the server but still unreachable, check there as well.
Check from outside
From your own computer, see which ports answer:
nc -zv 203.0.113.10 22 80 443
nc reports succeeded or open for ports that answer, and times out or refuses on the rest. Run it from a machine outside your host’s network, such as your laptop; testing from the server itself bypasses the firewall.
Locked out?
If you turned the firewall on without allowing SSH, use your host’s web console (often called Console, VNC or Recovery), which works like a screen and keyboard attached to the server. Log in there and run sudo ufw allow OpenSSH or sudo firewall-cmd --add-service=ssh.
Related
Something out of date? Software changes. If a step no longer works, tell us and we will check it and update the page.

