Linux Firewall Setup: Configure UFW and firewalld on a VPS (IPv4 and IPv6)

15 min read 2 views 0
On this page

A fresh Linux server answers on every port that a service happens to open, so a host firewall is one of the first things to configure. This guide shows how to set up a Linux firewall with UFW on Debian and Ubuntu and with firewalld on CentOS, Rocky Linux and AlmaLinux: allowing SSH before anything else, opening web ports, restricting sensitive services to specific source IPs, covering IPv6, and recovering if you lock yourself out. Since every JUSTG cloud server in Johannesburg, Moscow, Tokyo and Seoul comes with free IPv6, the IPv6 part matters just as much as IPv4.

Step 1: Check Open Ports and Your SSH Port

Before writing any rule, find out what is actually listening and which port SSH uses. If you moved SSH to a custom port, every SSH rule below must use that port instead of 22.

# Which ports are services actually listening on?
ss -tulpn
# Which port does SSH use?
sshd -T | grep -i '^port' 

Step 2: Prepare a Safety Net Before Enabling the Firewall

A single wrong rule can cut your SSH session. A short background timer that switches the firewall off again gives you an automatic way back in. Cancel it once you have confirmed you can still log in from a new terminal.

# Safety net: turn the firewall off again in 10 minutes unless you cancel it
nohup sh -c 'sleep 600; ufw disable' >/dev/null 2>&1 &             # UFW
nohup sh -c 'sleep 600; systemctl stop firewalld' >/dev/null 2>&1 & # firewalld

# Everything works? Cancel the timer:
pkill -f 'sleep 600' 

Step 3: Configure UFW on Debian and Ubuntu

UFW (Uncomplicated Firewall) is a simple front end to the kernel firewall. Set the default policy to deny incoming traffic, then allow SSH first and only then enable the firewall. ufw limit allows SSH but temporarily blocks an address that opens too many connections in a short time.

apt update && apt install -y ufw

# Make sure IPv6 rules are managed too
grep '^IPV6' /etc/default/ufw          # should print IPV6=yes

ufw default deny incoming
ufw default allow outgoing

# SSH FIRST (use your real SSH port if you changed it)
ufw limit 22/tcp                       # allow + basic brute-force rate limit
# Web server
ufw allow 80,443/tcp

ufw enable                             # answer "y"
ufw status verbose

Step 4: Restrict UFW Rules by Source IP (IPv4 and IPv6)

Databases, admin panels and monitoring agents should never be open to the whole Internet. Allow them only from known addresses. UFW evaluates rules in order, so a deny rule must be inserted above any broader allow rule.

# Allow MySQL only from one office IPv4 and one IPv6 network
ufw allow from 198.51.100.25 to any port 3306 proto tcp
ufw allow from 2001:db8:10::/64 to any port 3306 proto tcp

# Block an abusive network (insert at the top so it is matched first)
ufw insert 1 deny from 203.0.113.0/24

# List rules with numbers and delete one
ufw status numbered
ufw delete 4

Step 5: Configure firewalld on CentOS, Rocky Linux and AlmaLinux

firewalld works with zones; the network interface is normally in the public zone, which already allows SSH. Rules added with --permanent survive a reboot but only take effect after --reload.

dnf install -y firewalld              # CentOS 7: yum install -y firewalld
systemctl enable --now firewalld

firewall-cmd --get-default-zone        # usually "public"
# SSH FIRST (or: --add-port=2222/tcp for a custom port)
firewall-cmd --permanent --add-service=ssh
# Web server
firewall-cmd --permanent --add-service=http --add-service=https
# Close what you do not use
firewall-cmd --permanent --remove-service=cockpit

firewall-cmd --reload
firewall-cmd --list-all
If SSH runs on a custom port, add that port with --add-port before you remove the ssh service. On Rocky and AlmaLinux the port must also be allowed in SELinux.

Step 6: Limit firewalld Access by Source IP with Rich Rules

Rich rules let you combine a source address, port and action in one line. Write one rule for IPv4 and one for IPv6, because each rule applies to a single address family.

# Allow MySQL from one IPv4 address and one IPv6 network only
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="198.51.100.25" port port="3306" protocol="tcp" accept'
firewall-cmd --permanent --add-rich-rule='rule family="ipv6" source address="2001:db8:10::/64" port port="3306" protocol="tcp" accept'

# Drop all traffic from an abusive network
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="203.0.113.0/24" drop'

firewall-cmd --reload
firewall-cmd --list-rich-rules

Step 7: Make Sure IPv6 Is Filtered Too

A common mistake is a perfect IPv4 rule set while the same services are wide open over IPv6. UFW only manages IPv6 when IPV6=yes (look for the "(v6)" lines in ufw status); firewalld zones and services cover both families automatically. Test from another machine:

# Your server's IPv6 address
ip -6 addr show scope global

# From ANOTHER machine: test a port over IPv4 and IPv6
nc -vz 203.0.113.50 443
nc -vz 2001:db8:50::10 443
nc -vz 2001:db8:50::10 3306      # should fail from a non-allowed address

Step 8: Watch Out for Docker Published Ports

Docker writes its own iptables rules, so a port published with -p 8080:80 can be reachable even when UFW or firewalld would block it. Publish containers on 127.0.0.1 and put a reverse proxy in front, or manage the DOCKER-USER chain.

# Publish a container port on localhost only, then proxy it with Nginx
docker run -d -p 127.0.0.1:8080:80 nginx

Step 9: Recover from a Firewall Lock-Out

If SSH stops responding after a change, wait for the safety timer from Step 2. Otherwise open the VNC console: log in to the JUSTG client area, go to My Products & Services, select the server and open its management panel (submit a ticket if you cannot find the console). Log in as root and allow SSH again:

# Debian / Ubuntu (UFW)
ufw allow 22/tcp          # or: ufw disable
# CentOS / Rocky / AlmaLinux (firewalld)
firewall-cmd --panic-off 2>/dev/null
firewall-cmd --add-service=ssh   # runtime only; add --permanent once fixed
# last resort
systemctl stop firewalld

FAQ

Should I run UFW and firewalld at the same time?

No. Both manage the same kernel tables and will conflict. Use UFW on Debian/Ubuntu and firewalld on CentOS/Rocky/AlmaLinux, and disable the other if it is installed.

My firewalld rules disappeared after a reboot. Why?

They were added without --permanent, which only changes the running configuration. Run firewall-cmd --runtime-to-permanent to save the current rules.

Can I block an IP address that is attacking my server?

Yes: ufw insert 1 deny from 203.0.113.66 with UFW, or a rich rule with drop in firewalld. For large volumetric attacks a host firewall is not enough; contact support.

If you still have trouble configuring your Linux firewall, please submit a ticket at https://www.justg.com/submitticket.php and JUSTG technical support will help you.

Was this answer helpful?