server-hardening-check.sh
Hardening audit that walks SSH config, sudo, firewall and kernel settings and prints a [PASS]/[FAIL] per control.
Note
Live script from my home-lab server. Tokens, IDs, phone numbers and other secrets have been replaced with
placeholders like
<WHATSAPP_GROUP_ID> — everything else is the real, running code.
#!/bin/bash
echo "========================================="
echo " Server Hardening Audit"
echo "========================================="
echo ""
FAIL=0
PASS=0
check_pass() {
echo "[PASS] $1"
PASS=$((PASS+1))
}
check_fail() {
echo "[FAIL] $1"
FAIL=$((FAIL+1))
}
echo "Checking OS updates..."
UPDATES=$(apt list --upgradable 2>/dev/null | grep -v Listing | wc -l)
if [ "$UPDATES" -eq 0 ]; then
check_pass "System fully updated"
else
check_fail "$UPDATES packages need updating"
fi
echo ""
echo "Checking firewall..."
if sudo ufw status | grep -q "Status: active"; then
check_pass "Firewall enabled"
else
check_fail "Firewall NOT enabled"
fi
echo ""
echo "Checking open ports..."
OPEN_PORTS=$(ss -tuln | grep LISTEN | grep -v 127.0.0.1 | grep -v ::1)
if [ -z "$OPEN_PORTS" ]; then
check_pass "No public listening ports"
else
check_fail "Public ports open:"
echo "$OPEN_PORTS"
fi
echo ""
echo "Checking Docker containers exposing ports..."
EXPOSED=$(docker ps --format "{{.Names}} {{.Ports}}" | grep "0.0.0.0")
if [ -z "$EXPOSED" ]; then
check_pass "No Docker containers exposing public ports"
else
check_fail "Docker containers exposing ports:"
echo "$EXPOSED"
fi
echo ""
echo "Checking Cloudflare tunnel..."
if docker ps | grep -q cloudflared; then
check_pass "Cloudflare tunnel running"
else
check_fail "Cloudflare tunnel NOT running"
fi
echo ""
echo "Checking root SSH access..."
if grep -q "PermitRootLogin no" /etc/ssh/sshd_config; then
check_pass "Root SSH login disabled"
else
check_fail "Root SSH login enabled"
fi
echo ""
echo "Checking password authentication..."
if grep -q "PasswordAuthentication no" /etc/ssh/sshd_config; then
check_pass "Password login disabled (key-only SSH)"
else
check_fail "Password authentication enabled"
fi
echo ""
echo "Checking fail2ban..."
if systemctl is-active --quiet fail2ban; then
check_pass "Fail2ban running"
else
check_fail "Fail2ban NOT installed or running"
fi
echo ""
echo "Checking Docker daemon socket permissions..."
if [ -S /var/run/docker.sock ]; then
PERM=$(stat -c "%a" /var/run/docker.sock)
if [ "$PERM" = "660" ]; then
check_pass "Docker socket secure"
else
check_fail "Docker socket permissions weak ($PERM)"
fi
fi
echo ""
echo "========================================="
echo "Audit Complete"
echo "PASS: $PASS"
echo "FAIL: $FAIL"
echo "========================================="
if [ "$FAIL" -eq 0 ]; then
echo "System is well hardened"
else
echo "System needs hardening improvements"
fi