Skip to content
Linux VPS hardening · v0.4.0

Harden a fresh server without locking yourself out.

SSH keys, a firewall and automatic updates in one run. If an SSH or firewall change locks you out, it rolls back on its own.

curl -fsSL https://github.com/bhimrazy/vps-ready/releases/latest/download/install.sh | sudo sh

Linux x86_64 and arm64 · View the script first

root@vps: ~
$ sudo vps-ready audit
Audit of Debian GNU/Linux 13 (trixie): 29 controls
STATUS ID SEVERITY CONTROL
FAIL KRN-004 medium ptrace scope restricted
kernel.yama.ptrace_scope is 0, expected 1, 2 or 3
Otherwise a compromised process can read the memory of your other
processes, including secrets such as keys held by ssh-agent.
fix: sudo vps-ready apply --module kernel.sysctl
FAIL NET-005 medium IPv4 ICMP redirects not accepted
ICMP redirects are accepted on new interfaces (default) and eth0:
accept_redirects 1 in all and on each, forwarding 0 on each
Accepted ICMP redirects change the server's routes, so a forged
redirect can send its traffic through another machine on the local
network.
fix: not automated yet
FAIL KRN-001 low Kernel pointers hidden
kernel.kptr_restrict is 0, expected 1 or 2
Kernel memory addresses help an attacker aim a kernel exploit; hiding
them from normal users makes that harder.
fix: sudo vps-ready apply --module kernel.sysctl
25 passed, 3 failed (2 medium, 1 low), 0 unknown, 1 skipped
Skipped: Docker is not installed.
vps-ready can fix 2 of the 3 (KRN-004, KRN-001): run `sudo vps-ready plan`.
The other one needs a manual fix for now; it says so above.
Run `vps-ready audit --all` to list the 25 passing controls too.
Why

A new server is open to the internet from minute one.

Rent a VPS and it usually comes with root login on, passwords allowed and no firewall. Bots find it fast. Locking it down by hand takes an afternoon of guides, and one wrong SSH setting can lock you out for good.

Simulated log
120

failed logins in this simulation, the kind a fresh server sees all day

2 min agonow
journalctl -u ssh -f120 failed logins
14:03:58 Failed password root from 203.0.113.41
14:04:01 Invalid user ubuntu from 198.51.100.17
14:04:02 Failed password root from 192.0.2.88
14:04:05 Invalid user postgres from 203.0.113.9
14:04:06 Failed password admin from 198.51.100.203
14:04:09 Failed password root from 192.0.2.150

Simulated SSH log of a typical fresh server. Addresses are documentation examples.

From wide open to locked down, in one run.

Switch views to see what vps-ready does to a typical fresh server. You see the exact plan before anything changes.

Shown for the web profile0 of 6 protected
Root login over SSHssh.server
Anyone can try to log in as root exposed
How you log inuser.admin, ssh.server
Passwords accepted, so they can be guessed exposed
Firewallfirewall.inbound
Every port open to the internet exposed
Password guessingssh.bruteforce
Bots can guess forever exposed
Security updatesupdates.auto
Installed only when you remember exposed
Kernel settingskernel.sysctl
Distribution defaults exposed
How it works

Look first. Change second. Undo anytime.

Five commands, run on the server itself. Nothing changes until you approve the plan, and SSH and firewall changes only stay once you prove you can still log in.

1

Audit

vps-ready audit

Checks 29 controls and reports pass, fail, unknown or skipped. Changes nothing.

2

Plan

vps-ready plan

Prints the exact diff of every file and setting it would touch, and which parts are reversible.

3

Apply

vps-ready apply

Applies everything in a journaled transaction and verifies each change. SSH and firewall changes arm the safety timer first.

4

Confirm

vps-ready confirm

Run from a new SSH login. It proves you can still get in and cancels the safety timer.

5

Roll back

vps-ready rollback

Restores files, settings, users and services from the journal. Runs on its own if no one confirms in time.

Safety net

If a change locks you out, it rolls back on its own.

Before changing SSH or the firewall, vps-ready starts a safety timer (5 minutes by default). Log in again from a new terminal and run vps-ready confirm to keep the changes. If you can't get back in, everything rolls back, even if the server reboots.

Both endings shown
0:001:002:003:004:005:00applysafety timer armed firstnew SSH login runs vps-ready confirmSafety timer canceledthe changes stayno confirmin timeEverything rolled backeven after a reboot5:00
Only a new login counts.The confirming session must start after the change, on a port the SSH server listens on, as one of the admin users in the plan.
Refuses to lock you out.It won't turn off root or password login unless an admin user with SSH keys and sudo exists, and it checks that user against the live SSH server config.
Versus guides

Guides tell you what to type. vps-ready makes it safe to type it.

A guide is fine until one wrong SSH line locks you out. vps-ready checks before it changes anything, and rolls back on its own if you lose access.

FeatureCopy-paste guideConfig tools (Ansible and similar)vps-ready
Checks you won't lock yourself outnoyou write the checksyes, before SSH and firewall changes
Undoes itself if you lose accessnonoyes, even after a reboot
Shows the exact changes firstnoyes, in check modeyes, as a diff
One-command undo laternonoyes, from a journal
Setup neededan afternoon of readinga control machine and playbooksone binary on the server
Under the hood

Six modules, always run in a safe order.

The admin user exists before SSH is locked down, and SSH ports are open before the firewall closes everything else. Together the modules cover 29 audited controls.

user.admin

Creates a non-root admin user with sudo and installs your SSH keys. Refuses system accounts.

minimalweb

ssh.server

Turns off root and password login, after checking the live SSH server config won't lock you out.

minimalwebsafety timer

firewall.inbound

Blocks inbound traffic by default, in its own nftables table, and always allows SSH. Stays out of the way of ufw and firewalld.

minimalwebsafety timer

ssh.bruteforce

Installs fail2ban to ban addresses that keep failing to log in over SSH.

web

kernel.sysctl

Hides kernel pointers, restricts ptrace and BPF, and tightens network defaults.

minimalweb

updates.auto

Turns on unattended security updates so patches land without you.

minimalweb

Profiles. minimal sets up the admin user, SSH, the firewall, kernel settings and automatic updates. web adds ssh.bruteforce (fail2ban). You can also switch modules on one by one.

Systems. Runs on Linux x86_64 and arm64. Tested nightly in x86_64 VMs on Ubuntu 22.04 and 24.04 and Debian 12 and 13.

Tested

Tested where lockouts actually happen.

Unit tests can't prove you can still get in after a reboot. So the risky paths run against real systems.

  • UnitEvery module planned and verified against a fake filesystem.every change
  • ContainersApply and rollback for updates.auto and ssh.bruteforce; apply, confirm and rollback for user.admin.every change
  • Real VMsx86_64 VMs on QEMU/KVM: a real SSH server, real reboots and real second SSH logins.nightly
Roadmap

Built in small, safe releases.

Each release is tagged and signed. The guided setup ships in v0.4.0.

M0
SkeletonRepo, CI, release pipeline
M1
AuditDetect the host, check controlsv0.1.0
M2
EnginePlan, apply, journal, rollbackv0.2.0
M3
Lockout-safeSSH, firewall, admin user, safety timerv0.3.0
M4
WizardGuided setup and module explanationsv0.4.0
M5
Deploy-readySigned apt, dnf and apk packagesnext
M6
More distrosBroader support, deeper checks

Guided setup (v0.4.0)

Run sudo vps-ready on its own: it suggests a profile, asks a few plain questions, then applies the plan behind the same safety timer. vps-ready modules explains each module.

root@vps: ~
$ sudo vps-ready
Audit: 13 passed, 12 failed (1 high, 5 medium, 6 low), 4 unknown. vps-ready can fix 11 of them.
? What will this server run?
> Web apps or Docker: opens ports 80 and 443 (recommended: Docker is installed)
Something else: only SSH is open
? Admin user for logging in: admin
new account: logs in with 1 key copied from /root/.ssh/authorized_keys; sudo
without a password.
Unchecked ports will be blocked.
? Open ports besides SSH (22, always open)
[x] 80/tcp
[x] 443/tcp
[x] 443/udp
? Pick which modules to run yourself? (y/N) no
After you apply, you have 5 minutes to log in from a new terminal and confirm.
If you don't, every change is undone.
...
18 changes in 6 modules: 8 files, 1 directory, 6 kernel settings, 2 services, 1 user.
Apply 18 changes? [y/N] y
...
Next time, without questions:
sudo vps-ready apply --profile web
FAQ

Questions before you run it.

The short answers. The docs have the long ones.

Is it safe on a server that is already running things?

It audits first and shows the full plan. Nothing changes until you approve it. Every change is journaled, and sudo vps-ready rollback --last restores the previous state.

Which systems does it support?

Linux on x86_64 and arm64. It is tested nightly in x86_64 VMs on Ubuntu 22.04 and 24.04 and Debian 12 and 13. More distros are on the roadmap.

Will it fight with ufw, firewalld or Docker?

The firewall module stays out of the way when ufw or firewalld is in use. The audit checks whether container ports bypass the firewall.

Do I need root?

For changes, yes: apply, confirm, rollback and history need root, so run them with sudo on the server itself. detect and plan work without it, and so does audit, but some of its checks need root and show as unknown without it. There is no agent and no control machine.

What if I lose access after confirming?

Run sudo vps-ready rollback --last from any working session, or from your provider's console.

Get started

Audit first. It changes nothing.

Install it, run sudo vps-ready audit, and read the result. Then decide.

curl -fsSL https://github.com/bhimrazy/vps-ready/releases/latest/download/install.sh | sudo sh
Linux x86_64 and arm64. Checks the SHA-256, and the release signature when gh or cosign is installed.View install script