firewalld is the default firewall manager on AlmaLinux 9 and Rocky Linux 9. On your VPS Linux Infrawire it lets you open only the services you need, restrict SSH to your own IP and redirect ports, all without touching raw nftables rules.
The main risk is cutting your own SSH session. This guide is built around that: every risky change is tested first in the runtime configuration, then made permanent.
📋 Prerequisites
- A VPS running AlmaLinux 9 or Rocky Linux 9
- Root SSH access (IP and root password are available in your client area)
- A second SSH session kept open while you edit rules
1. Install and start firewalld
Bashdnf install -y firewalld systemctl enable --now firewalld firewall-cmd --state
The last command must print running. The default zone is public, which already allows SSH, Cockpit and DHCPv6 client traffic and drops the rest of the incoming connections.
2. Understand zones, services and ports
A zone is a set of rules applied to an interface. A service is a named group of ports (ssh is 22/tcp, http is 80/tcp, https is 443/tcp).
Bashfirewall-cmd --get-default-zone firewall-cmd --get-active-zones firewall-cmd --list-all firewall-cmd --get-services | tr ' ' '\n' | head -20
There are two configurations. Runtime applies immediately and disappears on reload or reboot. Permanent (--permanent) is stored on disk but only becomes active after firewall-cmd --reload.
3. Open services and ports
Bash# Services firewall-cmd --permanent --add-service=http firewall-cmd --permanent --add-service=https # A custom port firewall-cmd --permanent --add-port=8080/tcp # A port range firewall-cmd --permanent --add-port=30000-30100/udp # Apply the permanent configuration firewall-cmd --reload
To close something, use the matching --remove-service or --remove-port option. Remove the cockpit service if you do not use the web console: firewall-cmd --permanent --remove-service=cockpit.
4. Allow SSH only from your IP with a rich rule
Rich rules express conditions such as source address. Never remove the generic SSH rule before the restricted one is proven to work.
Bash# 1. Add the rule in runtime only (replace with YOUR public IP) firewall-cmd --add-rich-rule='rule family="ipv4" source address="YOUR_IP/32" service name="ssh" accept' # 2. Open a NEW terminal and confirm SSH still works from YOUR_IP # 3. Make it permanent, then remove the open SSH service firewall-cmd --runtime-to-permanent firewall-cmd --permanent --remove-service=ssh firewall-cmd --reload
If your IP changes, you lose access: keep the VPS console available from your client area as a recovery path. For an IPv6 address, write family="ipv6" and the IPv6 address instead.
5. Redirect a port
To send incoming traffic on port 80 to an application listening on 8080 on the same server:
Bashfirewall-cmd --permanent --add-forward-port=port=80:proto=tcp:toport=8080 firewall-cmd --reload
To forward to another machine, add toaddr=TARGET_IP to the forward-port option and enable masquerading with firewall-cmd --permanent --add-masquerade. The kernel must also allow forwarding, which firewalld handles for masquerading.
6. Verify the configuration
Bashfirewall-cmd --list-all firewall-cmd --list-rich-rules firewall-cmd --permanent --list-all ss -tlnp
Compare the runtime and permanent lists: they must match after a reload. From another machine, test a port with nc -zv VPS_IP 80. A listening service (ss -tlnp) is only reachable if the firewall allows its port.
🛠️ Troubleshooting
FirewallD is not running: start it with systemctl enable --now firewalld, then check journalctl -u firewalld for errors.
A new rule has no effect: you used --permanent without reloading. Run firewall-cmd --reload.
INVALID_SERVICE or INVALID_ZONE: typo in the name. List valid names with firewall-cmd --get-services and --get-zones.
SSH on a custom port is refused though the port is open: SELinux must know the port. Run semanage port -a -t ssh_port_t -p tcp 2222 (install policycoreutils-python-utils first), open the port in firewalld, then restart sshd.
Locked out: use the VPS console from your client area, then run firewall-cmd --permanent --add-service=ssh and firewall-cmd --reload. Avoid firewall-cmd --panic-on, which drops all traffic including your session.
🔒 Your VPS now exposes only what you choose, and SSH stays within reach!