Skip to content
RunStack
Wiki· Updated 19 Oct 2026

rs harden — server hardening

What each rs harden step changes, how to check it and how to undo it.

rs harden turns on basic protection step by step. Every step asks; SSH and the firewall roll back unless you confirm a login from a new window within 3 minutes. The script page is in the catalog.

sudo rs harden --plan    # just look
sudo rs harden           # step by step with questions
sudo rs harden --yes     # no questions, except SSH and firewall (never changed without a terminal)

1. Automatic security updates

Installs unattended-upgrades and writes /etc/apt/apt.conf.d/20auto-upgrades.

systemctl status unattended-upgrades
less /var/log/unattended-upgrades/unattended-upgrades.log
# turn off
printf 'APT::Periodic::Unattended-Upgrade "0";\n' > /etc/apt/apt.conf.d/20auto-upgrades

The system does not reboot for a new kernel by itself — rs security shows when a reboot is needed.

2. fail2ban

File /etc/fail2ban/jail.d/rs-sshd.local: 5 attempts in 10 minutes → banned for an hour; SSH ports are taken from sshd -T.

fail2ban-client status sshd              # who is banned
fail2ban-client set sshd unbanip 203.0.113.10
# undo
rm /etc/fail2ban/jail.d/rs-sshd.local && systemctl restart fail2ban

3. SSH by key only

The step runs only if the user you logged in as (SUDO_USER) has a key in ~/.ssh/authorized_keys and sshd_config includes sshd_config.d. File /etc/ssh/sshd_config.d/00-runstack-harden.conf:

PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin prohibit-password
MaxAuthTries 3
X11Forwarding no
sshd -T | grep -E 'passwordauth|permitroot|maxauth'   # what is in effect
# undo
rm /etc/ssh/sshd_config.d/00-runstack-harden.conf && sshd -t && systemctl reload ssh

No key? Create one on your computer, add it to the server, then run the step again:

ssh-keygen -t ed25519
ssh-copy-id user@server

4. ufw firewall

SSH ports are always open. For other ports not bound to 127.0.0.1 the script asks. If ufw or an nftables firewall with a default deny is already running, the step is skipped.

ufw status numbered
ufw allow 8443/tcp
ufw allow from 203.0.113.10 to any port 5432 proto tcp
ufw delete 3
# turn off
ufw disable

Docker bypasses ufw: ports from ports: in compose are open even if ufw denies them. Publish on 127.0.0.1:port or use rs <service> access.

If the Grafana + Prometheus stack is installed, the script adds a rule for node-exporter on the rs-mon0 bridge — otherwise Prometheus stops getting metrics.

5. Swap

File /swapfile of 2 GB (4 GB with 8 GB+ memory), an /etc/fstab entry, vm.swappiness = 10 in /etc/sysctl.d/90-runstack-swap.conf.

swapon --show && free -h
# remove
swapoff /swapfile && rm /swapfile && sed -i '\#^/swapfile #d' /etc/fstab

6. Time and kernel

Turns on NTP (timedatectl set-ntp true) and writes /etc/sysctl.d/90-runstack-harden.conf: syncookies, no ICMP redirects or source routing, martian logging, kernel.randomize_va_space = 2. Does not affect Docker or normal traffic.

# undo
rm /etc/sysctl.d/90-runstack-harden.conf && sysctl --system

Locked out anyway

The rollback timer fires even if the window hangs. If you still cannot log in — use the console (VNC) in your provider's panel, then remove the step's file (SSH) or run ufw disable. More on SSH — the cheat sheet.