← All checks

Host firewall

critical on-server

What it inspects

In order: `ufw status` as root (passes if the first line says active); `nft list ruleset` (passes if a chain on the input hook has a drop or reject policy and at least one rule; a ruleset that has only Docker NAT rules fails); then `iptables -S` (passes if the INPUT policy is DROP or REJECT with at least one INPUT rule). If none of these finds protection it fails. firewalld itself is not queried; only the ufw, nft and iptables output above is read. On the RHEL family this scan will still report FAIL after firewalld is active; that is a known scanner limitation, and `firewall-cmd --state` / `firewall-cmd --list-all` is the real confirmation.

Why it matters

Without a default-deny firewall every service that happens to listen on a public address is reachable from the internet, including databases and admin panels started by accident. A host firewall limits the exposure to the ports you chose, and it keeps protecting the server when a package or container opens something new.

How to verify

# Debian/Ubuntu with ufw:
sudo ufw status verbose
# Any distro:
sudo nft list ruleset
sudo iptables -S

How to fix

Allow the SSH port sshd really uses first, then turn on a default-deny firewall: ufw on Debian/Ubuntu, firewalld on the RHEL family. Ports 80/443 that are in use stay open; if other public TCP or UDP listeners exist, the snippet stops until you allow them and set UMBERMARK_FW_CONFIRM=yes. On the RHEL family this scan will still report FAIL after firewalld is active; that is a known scanner limitation, and `firewall-cmd --state` / `firewall-cmd --list-all` is the real confirmation.

Allow SSH, keep web ports that are in use, then enable default-deny

Debian / Ubuntu

# DEFAULT-DENY INCOMING. Keep this session open, and have console or out-of-band access ready.
# Order matters: SSH is allowed first, on the port sshd really uses, then ports already serving web traffic.
# Any other port the server must serve to the internet (80/443 are handled below, anything else is not)
# needs its own line BEFORE you paste this:  ufw allow <port>/tcp
# If sshd listens on several ports, add a ufw allow line for each one.
# Docker: published container ports bypass ufw's rules; restrict those where they are published.
# DHCP client ports (68, 546) and local-network name lookup (mDNS 5353, LLMNR 5355) are not counted: nobody reaches the server through them.
# Safety stop: if anything else listens on all addresses (TCP or UDP, for example a VPN such as WireGuard that
# you may use to reach this server), this prints the ports and changes NOTHING. Allow what you need
# (first `apt-get install -y ufw` if ufw is missing, then `ufw allow <port>/<tcp or udp>`), then run `export UMBERMARK_FW_CONFIRM=yes` and paste this again.
if command -v ss >/dev/null 2>&1; then
P="$(sshd -T | awk '/^port / && !p {print $2; p=1}')"
OTHER="$(ss -ltnu | awk 'NR>1{print $5}' | grep -E '^(0\.0\.0\.0|\*|\[::\]):' | sed 's/.*://' | sort -u | grep -vxE "${P:-22}|68|80|443|546|5353|5355" || true)"
if [ -n "$OTHER" ] && [ "${UMBERMARK_FW_CONFIRM:-}" != yes ]; then
echo "Other public listeners (port numbers): $OTHER"
echo "Default-deny would cut them off. Nothing was changed. Install ufw if needed (apt-get install -y ufw), allow what you need with ufw allow <port>/<tcp or udp>, then set UMBERMARK_FW_CONFIRM=yes and re-run."
else
apt-get install -y ufw
ufw allow "${P:-22}/tcp"
for w in 80 443; do
if ss -tln | awk '{print $4}' | grep -E "[:.]$w\$" >/dev/null; then ufw allow "$w/tcp"; fi
done
ufw default deny incoming
ufw --force enable
ufw status verbose
fi
else
echo 'ss not found: install iproute2 and re-run, so ports that are in use (80/443) can stay open'
fi

RHEL / Rocky / Alma / Fedora

# DEFAULT-DENY INCOMING with firewalld (its public zone rejects anything not allowed). Keep this session
# open, and have console or out-of-band access ready.
# SSH is allowed first, on the port sshd really uses, then ports already serving web traffic (80/443).
# Any other port the server must serve to the internet needs its own rule BEFORE you paste this:
#   firewall-cmd --permanent --add-port=<port>/tcp
# If sshd listens on several ports, add a rule for each one.
# On the RHEL family this scan will still report FAIL after firewalld is active; that is a known scanner limitation,
# and `firewall-cmd --state` / `firewall-cmd --list-all` is the real confirmation.
# DHCP client ports (68, 546) and local-network name lookup (mDNS 5353, LLMNR 5355) are not counted: nobody reaches the server through them.
# Safety stop: if anything else listens on all addresses (TCP or UDP, for example a VPN such as WireGuard that
# you may use to reach this server), this prints the ports and changes NOTHING. Allow what you need
# (firewalld stopped or not installed: `dnf install -y firewalld` then `firewall-offline-cmd --add-port=<port>/<tcp or udp>`; firewalld running: `firewall-cmd --permanent --add-port=<port>/<tcp or udp>` and `firewall-cmd --reload`), then run `export UMBERMARK_FW_CONFIRM=yes` and paste this again.
if command -v ss >/dev/null 2>&1; then
P="$(sshd -T | awk '/^port / && !p {print $2; p=1}')"
OTHER="$(ss -ltnu | awk 'NR>1{print $5}' | grep -E '^(0\.0\.0\.0|\*|\[::\]):' | sed 's/.*://' | sort -u | grep -vxE "${P:-22}|68|80|443|546|5353|5355" || true)"
if [ -n "$OTHER" ] && [ "${UMBERMARK_FW_CONFIRM:-}" != yes ]; then
echo "Other public listeners (port numbers): $OTHER"
echo "Default-deny would cut them off. Nothing was changed. Allow what you need (firewall-offline-cmd --add-port=<port>/<proto> while firewalld is stopped, firewall-cmd --permanent --add-port=<port>/<proto> when running), then set UMBERMARK_FW_CONFIRM=yes and re-run."
else
dnf install -y firewalld
WEB=""
for w in 80 443; do
if ss -tln | awk '{print $4}' | grep -E "[:.]$w\$" >/dev/null; then WEB="$WEB $w"; fi
done
if systemctl is-active --quiet firewalld; then
firewall-cmd --permanent --add-port="${P:-22}/tcp"
for w in $WEB; do firewall-cmd --permanent --add-port="$w/tcp"; done
firewall-cmd --reload
else
firewall-offline-cmd --add-port="${P:-22}/tcp"
for w in $WEB; do firewall-offline-cmd --add-port="$w/tcp"; done
systemctl enable --now firewalld
fi
firewall-cmd --state
firewall-cmd --list-all
fi
else
echo 'ss not found: install iproute and re-run, so ports that are in use (80/443) can stay open'
fi

References

Scan your server free