root@sudosecurity:~/hardline/start $ cat start .md

Get started with Hardline

Harden your first Linux server with Hardline in about 15 minutes: install, audit, lock down SSH and the firewall with automatic rollback, then keep it that way.

Got a fresh VPS, or one that's been running for a while and you're not sure how locked down it is? This is the 15-minute version. You'll install Hardline, see where you stand, and lock down SSH and the firewall without the classic "well, I can't get back in" moment.

Nothing here needs you to know every sysctl by heart. Hardline tells you what it's about to do before it does it, and the risky stuff undoes itself if you lose access.

Before you start

  • A supported OS: Ubuntu 26.04, Ubuntu 24.04, Ubuntu 22.04, Debian 13, Debian 12 and RHEL 9 / Rocky Linux 9 / AlmaLinux 9. Anything else gets refused. That's on purpose, not a bug.
  • An SSH key that already works. Phase 1 turns password logins off. If you're still logging in with a password, set up a key first (ssh-copy-id you@server) and make sure it works.
  • A second way in, if you can get one. Most providers have a web console. You probably won't need it, but it's nice to know where it is.
  • sudo. Audits read root-only files, so everything runs as root.

1. Install it

One binary, no dependencies beyond OpenSSL 3, which every supported distro already has. These steps check the download against SudoSecurity's signing key before anything gets installed:

cd "$(mktemp -d)"
base=https://sudosecurity.org/hardline/releases/latest
bin=hardline-$(uname -m)-unknown-linux-gnu        # x86_64 or aarch64
curl -fsSLO "$base/$bin" -O "$base/SHA256SUMS" -O "$base/SHA256SUMS.sig"

# The SudoSecurity release key. Pin it; don't fetch it from the same server.
cat > release.pub <<'EOF'
-----BEGIN PUBLIC KEY-----
MCowBQYDK2VwAyEAPD8oWSZySVfdT2iWIXtGhZ81gxiRJ9SK3OWReFUf25A=
-----END PUBLIC KEY-----
EOF
openssl pkeyutl -verify -pubin -inkey release.pub -rawin -in SHA256SUMS -sigfile SHA256SUMS.sig
sha256sum -c --ignore-missing SHA256SUMS            # must print: OK

sudo install -o root -g root -m 755 "$bin" /usr/local/bin/hardline

You want to see Signature Verified Successfully and OK. If you don't, stop there and tell us. On Rocky/Alma/RHEL, sudo doesn't look in /usr/local/bin, so use sudo /usr/local/bin/hardline for everything below.

2. See where you stand

An audit is read-only. It doesn't touch a single file, so run it as often as you like:

sudo hardline audit

You get every check, grouped by phase, with PASS, FAIL, WARN or N/A, and an A–F grade at the end. Most fresh images land somewhere around a D. That's normal: distros ship for convenience, not lockdown.

  FAIL  perm-crontab                       /etc/crontab is 0600, root:root
  PASS  perm-etc-passwd                    /etc/passwd is 0644 or stricter, root:root
  FAIL  perm-sshd-config                   /etc/ssh/sshd_config is 0600, root:root

Curious about one? hardline explain perm-sshd-config tells you why it matters, what Hardline checks, what it changes and how to undo it. It works offline and doesn't need root.

3. Lock down SSH (the important one)

This is the part that usually goes wrong, so Hardline is extra careful here. First, preview it. This is a dry run that shows the exact lines it would write:

sudo hardline apply --phase 1

Looks good? Commit it:

sudo hardline apply --phase 1 --commit

Hardline validates the new config with sshd -t, reloads SSH and starts a 120-second countdown. Your current session stays open. Now:

  1. Leave that terminal alone. Open a new terminal on your computer.
  2. SSH into the server again, the normal way.
  3. Run sudo hardline confirm.
terminal 1 · already logged in$ sudo hardline apply --phase 1 --commitarmed: reverts in 120 s unless confirmed# leave this one openterminal 2 · a brand-new login$ ssh you@server$ sudo hardline confirmconfirmed: change kept
The new login is the proof. If it can't get in, don't touch anything and the change undoes itself.

If the new login works, confirm keeps the change. If it doesn't, don't do anything. When the timer runs out, Hardline puts the old config back on its own and SSH comes back the way it was. It even survives a reboot mid-countdown.

Why a new session? Because your old one is already logged in, so it proves nothing. Hardline refuses confirm from the same connection that ran apply. If you only have the provider's web console, there's --from-console.

4. Turn on the firewall

Same flow, same safety net. Hardline keeps SSH open (rate-limited per source) and every port something is already listening on, so your site doesn't go dark:

sudo hardline apply --phase 2            # preview
sudo hardline apply --phase 2 --commit   # then confirm from a new SSH session

On Ubuntu/Debian that's ufw by default (--firewall nftables if you'd rather), and firewalld on RHEL-family systems.

5. Do the rest

Phases 3 to 8 cover access control, auditing, TLS, containers, the kernel and accounts, including the permissions on files like /etc/shadow and sshd_config. None of them can lock you out, so you can go phase by phase or knock them all out at once:

sudo hardline apply --all             # preview everything
sudo hardline apply --all --commit    # SSH and firewall still wait for one confirm

Run sudo hardline audit again and watch the grade climb. A few checks stay report-only on purpose, like kernel lockdown, because changing them needs a reboot and can stop drivers from loading. hardline explain gives you the manual steps for those.

Changed your mind?

Every phase snapshots the files it touches first. Undoing one is a single command:

sudo hardline status               # what's pending, what's applied
sudo hardline rollback --phase 7   # puts phase 7's files back exactly as they were
sudo hardline diff                 # anything that drifted since your last apply

If you edited one of those files by hand afterwards, rollback won't clobber your edit unless you add --force.

6. Keep it that way

Hardening is a snapshot. Package updates, a teammate's "quick fix" or a setup script can quietly undo it. Turn on watch and Hardline re-checks the server on a timer:

sudo hardline watch enable                      # daily by default
sudo hardline watch notify set < webhook.txt    # optional: Discord, Slack or ntfy alerts
sudo hardline dashboard                         # a local status page with history

If there's a finding you're keeping on purpose (a bastion box that needs passwords, say), record it instead of living with a lower grade forever: sudo hardline accept <id> --reason "why" --expires 90d.

Where to next

Guides

Recipes for real setups: production boxes, Docker hosts, fleets, CI, Grafana and auditors.

Docs

Every command, flag, file, exit code and the JSON format.

Controls

Every check, why it matters and how to undo it, with STIG and CIS IDs.

Forums

Stuck, or found something weird? Ask. That's what they're there for.