Home / Guides / VPS Security Hardening Checklist — 12 Steps After the First Login
How-to

VPS Security Hardening Checklist — 12 Steps After the First Login

A practical hardening checklist: keys over passwords, firewall defaults, automatic patches, fail2ban, audit surface and backups you actually test.

BitCloudVPS no-KYC abstract: shield and dissolving ID card
Short answer

A practical hardening checklist: keys over passwords, firewall defaults, automatic patches, fail2ban, audit surface and backups you actually test.

Identity and access

  1. Add your SSH public key, then disable password authentication for root.
  2. Create a named sudo user; reserve root for console/rescue only.
  3. Enable 2FA on the hosting panel — the panel is part of your attack surface too.

Business $24/mo (6 vCPU / 16 GB DDR5) is the production size. Crypto invoice, no KYC.

Launch now

Network surface

  1. Default-deny firewall: allow 22 (or your moved port), 80/443, and each service you actually run.
  2. Close the panel ports you do not use; bind admin interfaces to localhost or a VPN.
  3. Install fail2ban (or sshguard) — log noise drops by an order of magnitude.

System and data

  1. Turn on unattended security upgrades for the base system.
  2. Schedule snapshots plus an off-box backup; an untested backup is a rumor, not a backup.
  3. For sensitive data at rest, add a LUKS container opened after boot — see the encrypted VPS guide.

Short answer: the ten controls that stop the attacks that actually arrive

Short answer: an unhardened VPS on a public IP starts receiving automated attacks within minutes of going live - SSH password brute force, scanning for exposed panels, exploitation of unpatched services. Ten controls stop essentially all of it: SSH keys only with password auth disabled, root login disabled, a default-deny firewall exposing only the ports you use, fail2ban on the two services that face the internet, unattended security updates, 2FA on the hosting panel, minimal installed packages, correct file permissions on keys and configs, off-server backups, and a weekly log scan. None of these require a vendor product; every one is a command you run once and a policy that stays set.

The checklist sections above group these into identity, network surface, and system-and-data. This guide executes them in order, with the exact commands, the expected output of each verification, the failure modes people hit mid-way (chiefly locking themselves out), and the two scans you run at the end to prove the work landed. Budget one focused hour on a fresh server - six minutes if you script it, which by the second server you will.

Prerequisites and order of operations

Sequence matters more than people expect, because the fastest way to lose an afternoon is disabling password SSH before the key path is proven. Have these five things confirmed before you touch a config.

Ready whenHow to confirmWhy the order
An SSH key pair you controlssh -i ~/.ssh/id_ed25519 root@server logs in without a password promptEvery later step assumes key access works
A second console pathPanel console session opens to a login promptYour escape hatch if the firewall rule is wrong
A service inventoryss -tulpn output saved; you know what each listener isA default-deny firewall needs an explicit allow list, which is this list
Patch level currentapt update && apt full-upgrade returns nothing pendingHardening a kernel with a known local privesc wastes the hour
Panel 2FA feasibleAn authenticator app on a device you keepThe panel controls the VM; it belongs in the threat model with SSH

One structural note specific to this provider: DDoS filtering at L3/L4 is included on every plan at the network edge, which handles volumetric noise before it reaches you. That is not a substitute for the host firewall - it stops floods, not port scans or credential attacks - so the two layers complement rather than overlap. Deploy a fresh instance if the box you are starting from has an unknown history; hardening a compromised server is forensics, not this checklist.

Identity and access: keys only, in the order that cannot lock you out

The lockout scenario has one cause: closing the password door before proving the key door opens. Do it in this order and the failure is impossible.

  1. As root, add your key to /root/.ssh/authorized_keys (or better, create a sudo user: adduser ops && usermod -aG sudo ops, then place the key in /home/ops/.ssh/authorized_keys). Confirm a fresh SSH session with the key works before anything else.
  2. Only then edit /etc/ssh/sshd_config: PasswordAuthentication no, PermitRootLogin prohibit-password, PubkeyAuthentication yes, MaxAuthTries 3. Reload, do not restart: systemctl reload sshd.
  3. Test from a new terminal - not the session you are in - that key login still works. Expected: a shell. If you see a password prompt, the config reload failed; fix it before proceeding.
  4. Set chmod 600 on authorized_keys and chmod 700 on the .ssh directory; sshd silently refuses world-readable keys, and that silent refusal is the number one 'my key stopped working' ticket.
  5. Enable 2FA on the hosting panel account. Signup here works with a token and an optional email, and the panel is the one interface that can rebuild the VM - treat it as the crown jewel, not SSH.

Optional but cheap: move SSH off 22 to cut log noise by two orders of magnitude. This is convenience hardening, not security - scanners find any port within days - but a quiet auth log makes the real signals visible in step seven.

Network surface: a default-deny nftables ruleset you can read in one screen

Every listener on a public IP is an attack surface, and the inventory from the prerequisites is usually longer than the owner expects - a plain Debian image with one web app routinely shows five or six listeners. The fix is default deny, with explicit allows only for what you named.

  1. Write /etc/nftables.conf: a table with input policy drop, allow established/related, allow loopback, allow TCP 22 (or your SSH port), and one line per real service - 80/443 for a web server, 51820/udp for WireGuard. ICMP to hosts you ping for monitoring.
  2. Apply with nft -f /etc/nftables.conf - keep the current SSH session open and test a new one immediately. If the new session connects, the ruleset is safe; if not, the open session is your way back in.
  3. Enable persistence: systemctl enable nftables. Verify with nft list ruleset | head -30 and confirm the input chain's policy line reads drop.
  4. Prove it from outside: nmap -p- your-server-ip should report exactly the ports you allowed and filtered or closed for everything else. Save this scan output; it is the before/after record of your surface.

IPv6 deserves one explicit sentence in the ruleset: many rulesets deny IPv4 and leave IPv6 wide open, and your plan includes a /64 of IPv6 - test the scan with nmap -6 too. The unmetered 1-10 Gbps port on every plan makes an open listener cheap for an attacker to lean on, which is one more reason the inventory should match reality rather than habit.

System and data: fail2ban, automatic updates, least software

With identity and network done, the remaining controls are maintenance-sized. Three of them, each a one-time setup.

  1. fail2ban for the two exposed services: apt install -y fail2ban, enable the sshd jail, and add a jail for nginx or your panel if one is public-facing. Verify with fail2ban-client status sshd after a day - expect a nonzero 'Totally banned' count, which is evidence the tool is doing its job on a public IP.
  2. Unattended security updates: apt install -y unattended-upgrades, confirm the security origin is enabled in /etc/apt/apt.conf.d/50unattended-upgrades, then check the timer with systemctl list-timers apt-daily*. Reboot policy is your call; check-reboot-required after kernel updates tells you when one is pending.
  3. Remove what you do not run: dpkg -l | wc -l against a minimal baseline, systemctl list-units --type=service --state=running for live daemons. Every uninstalled package is a CVE you will never patch. This is also where the least-privilege question lands - services that must run should get dedicated users, not root.

The data layer is the one this checklist cannot finish for you: filesystem permissions and an off-server backup schedule are workload-specific. The backup-and-restore guide on this site covers the 3-2-1 pattern with restic; the one-line summary here is that a hardened server without an off-box backup is a single point of failure with good posture - ransomware does not respect file modes.

How to verify it worked: the two scans and the one drill

Verification is three checks, all runnable in ten minutes, and all worth re-running monthly because hardening decays through config drift and new services.

  1. External port scan, both stacks: nmap -p- server-ip and nmap -6 -p- server-ip. Expected: only your allow-listed ports answer; everything else filtered. Any surprise listener goes back to the inventory and either into the firewall or off the machine.
  2. Credential exhaustion test: ssh -o PreferredAuthentications=password root@server. Expected: Permission denied (publickey) - the word publickey in the server's offer list is the proof that password auth is off, and this one line settles the question permanently.
  3. Recovery drill: simulate the loss of the box. From a fresh terminal, confirm (a) your SSH key is in a password manager or on a second device, (b) the panel 2FA codes are recoverable, (c) the most recent restore point of your data is loadable somewhere other than the live server. A hardening pass that fails the recovery drill has optimized the wrong thing.

Write the three results down with dates. The point is not the document - it is that verification becomes a habit attached to a checklist instead of a feeling attached to a memory, which is the difference between posture and security theater.

Troubleshooting: locked out, service down, updates stuck

Three incidents account for nearly all post-hardening panic. Each has a recovery path that does not require the vendor.

SymptomCauseFix
SSH refuses all logins after the firewall stepAllow rule missed the SSH port, or the ruleset applied to the wrong interfaceOpen the panel console session (out-of-band, not SSH), nft list ruleset, add the missing allow, re-apply. This is why the second console path was a prerequisite
Website unreachable, SSH fine, after nftables loadWeb ports not in the allow list, or a state rule dropped return trafficnft add rule inet filter input tcp dport {80,443} accept, test, then persist in the conf file - ad-hoc rules die at reload
'Permission denied (publickey)' for a key that worked yesterdayPermissions changed on .ssh, or fail2ban banned your own IP after failed attemptsCheck fail2ban-client status sshd first; then ls -la ~/.ssh on the server - 700 on the dir, 600 on authorized_keys
unattended-upgrades holds back packagesOrigin not enabled or a manual apt lock left behindapt-get upgrade -s to preview, remove stale /var/lib/dpkg/lock-frontend only when no apt process runs

The pattern across all four: the panel console is the recovery instrument, and it exists precisely because remote-access changes are the risky ones. Keep a console tab open during any firewall or SSH work and the worst case is a five-minute detour.

Monitoring and the weekly five-minute review

Hardening is a state, and states drift. The maintenance version of this checklist is a five-minute weekly review of four signals, all local, no agent required: journalctl -u ssh --since '7 days ago' | grep -c Failed (brute-force trend - spike means a new scanner, sustained zero means your port move worked), fail2ban-client status sshd (bans happening), apt list --upgradable (patch backlog), and ss -tulpn diffed against the inventory from day one (new listeners are how intrusions announce themselves quietly). Add last -20 to see who actually logged in.

When a signal looks wrong - a listener you cannot name, logins from an unfamiliar key - the response is the drill, not intuition: snapshot state, rotate keys, restore from the last known-good backup onto a fresh instance. On this network the fresh instance is a 60-second deploy at the same price tier, and because checkout never had card rails - 19 crypto assets, token-only signup, Harborline Node Ltd. registered in Saint Kitts and Nevis - rebuilding infrastructure does not mean re-proving who you are. The Business tier at $30/mo list adds room for a dedicated log host if you outgrow local journals.

BitCloudVPS Starter · Zurich · from $6.80/mo annual

Deploy a fresh box and harden it in an hour

Rotation and offboarding: what to change when a key, a token, or a person leaves

The direct answer: hardening is not a one-time pass, it is a rotation schedule — and the checklist is only as good as what you do the day access changes. When a person or a key leaves your project, work the list in this order: revoke the SSH public key from every authorized_keys and from any CI deploy key; rotate the restic or rclone credentials that box holds; regenerate API tokens for services the box talks to; and only then consider whether the box itself needs a reinstall. A key you removed but a credential you forgot is how 'offboarded in March' becomes 'breached in October'.

Put the rotation on calendar terms rather than memory. Quarterly: rotate database passwords and any long-lived service tokens; run auditctl-style review of last and lastb output, and find / -perm -4000 -type f for unexpected SUID binaries. Annually or after any incident: rotate SSH host keys if you have reason to, and rebuild the box from your hardened image instead of patching a mystery — the reinstall-plus-restore-from-backup drill takes an hour when you have rehearsed it and a weekend when you have not. On this host the account layer mirrors the same discipline: signup is token-only with optional email, so the signup token and the panel credentials are themselves crown jewels — store them in a password manager, enable 2FA where the panel offers it, and never reuse a production-box SSH key passphrase as the hosting account passphrase. Rotation costs an afternoon a quarter; an unrotated key costs whatever the box holds.

Hardening the account and payment layer: the side of the checklist most guides skip

The direct answer: your server can be airtight while your hosting account is the weak point, because whoever controls the panel controls DNS, reinstallation, and rescue mode — which is remote code execution with extra steps. Treat the hosting account as production surface. Use a unique password in a manager, turn on 2FA for the panel, and keep the signup token offline: this host supports token-only signup with no KYC at any tier, which is a privacy win that becomes a liability if the token sits in a plaintext note.

Payment hygiene belongs in the same checklist. The checkout is crypto-only — BTC, XMR, ETH, LTC, DOGE and the rest of the 19 assets, including USDT on seven networks — so there is no card to cancel if the account leaks; your exposure is the balance, not a chargeback. Fund small, top up per need, and think before chasing the bonus tiers ($1,000 +10%, $2,000 +40%): a large prepaid balance is a single point of loss, and the privacy tradeoff of consolidating funds is real. Keep billing periods aligned across servers — month, quarter -10%, year -20% — so a compromise of one invoice notification does not reveal your full infrastructure map. Finish the pass with a five-minute drill: log out, recover access from your password manager only, and confirm you can reach the panel, read a server's IP, and that rescue mode requires the same 2FA. If any step surprises you, the account layer — not the firewall — is where your next hardening hour goes.

Where the limits are (October 2026)

Keep the threat model precise. Anonymous-adjacent hosting removes the host-side identity trail: token-only signup, optional email, no KYC review, crypto invoices that record a txid rather than a name. It does not blind the host to traffic it must carry, it does not make a logged-in panel session anonymous, and it does not protect workloads that identify themselves — an admin login from your home IP defeats the whole design. Exact limits of no-KYC anonymity. OPSEC guide. Full checklist. Payment-side note: chain analysis happens on public blockchains, not at the host. Coin choice and network choice are your OPSEC knobs, and the checkout keeps 19 of them open.

Does BitCloudVPS harden the server for me?

No — you get root, which means the hardening decisions (and their benefits) are yours. The checklist above is the standard baseline.

Is a VPS with password login unsafe by default?

It is weaker: password brute-force noise starts within minutes of a public IP. Keys first is the single highest-value step.

Do I need antivirus on a Linux VPS?

Rarely for the OS itself; run malware scanners on the content you serve (e.g. uploads) if you accept files from users.

How long does a full hardening pass take?

About an hour the first time: keys, firewall, fail2ban, unattended upgrades, verification scans. Scripted, it drops to minutes per server. The weekly review adds five minutes; the recovery drill is a quarterly half-hour.

Is unattended-upgrades safe on a production server?

Yes for security-origin updates, which is its default scope - they are backported fixes, not feature upgrades. The residual risk is a service restarting unattended; for that, schedule the reboot window and check needrestart after major kernel updates.

Should I change the SSH port?

It reduces log noise dramatically but adds no real security - scanners find nonstandard ports within days. Do it if you value readable logs, not because it stops attackers; keys-only and fail2ban are the controls that matter.

Do I need a host firewall if DDoS filtering is included at the edge?

Yes - they stop different things. Edge filtering absorbs volumetric floods; the host firewall controls which ports accept connections at all, which is what port scans and service exploits actually touch. Both layers, always.

What is the very first thing to do when I suspect a VPS is compromised?

Do not delete evidence and do not panic-patch: pull the network plug first — either stop the server from the panel or firewall it off — then snapshot disk contents to a storage box, and only after that start the rebuild. Assume root is gone: restore from a pre-incident backup into a fresh server, rotate every credential the old box ever held (SSH keys, API tokens, database passwords, the restic repository password), and re-point DNS last. Editing the compromised box in place is triage, not recovery.

Does IPv6 change my firewall rules?

Yes, and ignoring it is the classic hole. nftables (or ip6tables) needs its own ruleset — IPv4 deny-by-default does nothing to an open IPv6 path, and your /64 block gives every service a routable address. Mirror the v4 policy: permit established, permit your SSH source if you restrict it, permit ICMPv6 essentials (neighbor discovery, packet-too-big), drop everything else inbound. Verify with <code>nmap -6</code> from outside, not by reading rules you hope loaded.

Why does the checklist insist on 2FA for the hosting panel?

The panel is part of your attack surface: an attacker who takes it over can rebuild, snapshot or destroy your servers without ever touching SSH. Enable 2FA on it, keep SSH key-only, and turn on unattended security upgrades so the base system patches itself between your logins.

What does the host actually know about me?

Whatever you hand over: a signup token, an optional email address, the invoice you paid and the service traffic. No ID documents, no phone number, no KYC step exists to hand anything else over.

What won't an anonymous VPS protect against?

Self-inflicted links: personal logins from a home IP, leaked cookies, services that publish your address, and on-chain patterns that tie wallets together. The server removes one identifier; it does not fix operational mistakes.

Ready to launch?

Configure a VPS or dedicated server, set a password, then pay the invoice.

Network

Edge RTT

Uptime · 36h

Complaints · 36h

Pick a city