All systems operational 6 offshore regions No-KYC checkout
Hands-on Field guide

Harden a new VPS: the first hour after deploy

A server is never as exposed as it is in the minutes after it boots. The image is generic, the root password came out of a provisioning system, everything the distribution ships is listening, and the address is already in somebody's scan queue. This is the checklist we run on every fresh box before it does anything useful: four controls, about an hour of work, and one habit — never close the session you arrived on — that matters more on a $8.00/mo offshore VPS than anywhere else, because here nobody can identify you back into a machine you have locked yourself out of.

Updated 2026-08-27 · 14 min read · Fleet operations
On this page
  1. The first hour is not optional
  2. What actually attacks a small server
  3. SSH: keys, and exactly one door
  4. Default-deny, and the half of the firewall nobody configures
  5. Updates you do not have to remember
  6. Rate limiting, fail2ban, and the noise floor
  7. Locking yourself out is the real risk here
  8. What to add next, depending on what the box does
  9. Step by step
SP·01

The first hour is not optional

The internet's IPv4 space is small enough that scanning all of it takes a well-funded stranger a few minutes and a laptop a few hours. Hosting ranges are published, catalogued and rescanned constantly, so a new address is not obscure — it is a fresh entry in a list that already exists. In practice the first automated SSH login attempt on a newly booted box arrives long before you have finished reading your welcome email, and it will be followed by thousands more from unrelated sources, all of them trying the same few hundred passwords against the same few usernames. None of that is aimed at you. It is a machine sorting the internet into answers and does not answer, and the only thing that decides which pile you land in is what you did in the first hour.

The good news is that the work is boring and finite. Four controls do almost all of it: authenticate with keys instead of passwords, refuse every inbound port you are not deliberately serving, apply security updates without being asked, and stop operating as root. Each takes a few minutes and none of it is exotic. What makes it worth writing down specifically for an offshore, no-KYC server is the asymmetry at the other end — the recovery path. On a mainstream host, a bad sshd_config ends with a support ticket, an ID check and a console session. Here there is no identity on file to check, which is the entire point of the product and also the reason a careless keystroke costs you the machine rather than twenty minutes. Every step below is written with that in mind.

SP·02

What actually attacks a small server

Two very different populations show up in the logs and it is worth separating them, because they are defeated by different things. The overwhelming majority is indiscriminate mass scanning: bots working through the address space looking for SSH that accepts passwords, databases bound to 0.0.0.0, admin panels with default credentials, forgotten staging copies, unpatched web applications with a public exploit. This population does not care what your server is for. It cannot be reasoned with, it never stops, and it is beaten completely by the checklist in this guide — not because the checklist is clever, but because the bots are looking for machines that skipped it and there are plenty of those.

The second population is targeted — someone who wants your specific box — and it is rare, expensive and almost never gets in through SSH. It arrives through the application you deployed, a dependency you did not audit, a credential you reused, or a laptop that was compromised before it ever touched the server. That is why hardening does not end at the firewall: the real questions become what your service runs as, what it can reach outbound, and how quickly you patch. Worth knowing while you plan: our VPS plans are KVM full virtualization, so you run your own kernel and the whole toolbox — nftables, ufw, namespaces, seccomp, custom sysctl — actually works, which is not true of container-based "VPS" products where the kernel belongs to somebody else.

SP·03

SSH: keys, and exactly one door

Password authentication on a public SSH port is the single largest self-inflicted risk on a rented server, and removing it is the highest-value five minutes in this guide. Generate an Ed25519 keypair on your own machine — never on the server, where the private half would be born on the very host you are trying to protect — protect it with a passphrase, and load it into an agent so the passphrase costs you one prompt per session rather than one per login. Copy the public half up, confirm it works, and only then turn passwords off. With PasswordAuthentication no and KbdInteractiveAuthentication no in place, the thousands of daily guesses stop being a risk and become mere noise: there is no password to guess, so the attempt fails before it is even interesting.

Root deserves its own decision. PermitRootLogin prohibit-password keeps key-based root access for emergencies; PermitRootLogin no is stricter and forces every session through a named account with sudo, which is what you want the moment more than one person touches the box. Add AllowUsers so a stray account created by some package can never be a login path. Moving the daemon off port 22 is worth doing, but be honest about why: it is not a security control — anyone who scans your address will find the new port in seconds — it is log hygiene, and it removes the great majority of automated noise so that the entries left in auth.log are ones you should actually read. Whatever you change, validate with sshd -t before reloading, and keep your current session open until a second terminal has connected successfully. That habit is the difference between a typo and a lost server.

SP·04

Default-deny, and the half of the firewall nobody configures

A firewall on a server has one job: make the answer to "what is listening here?" equal to the list of things you deliberately published. Default-deny inbound, allow outbound, then open ports one at a time with a reason attached to each. Before you write a single rule, run ss -tulpen and read what is already bound — a default install listens on more than most people expect, and a database or cache that binds to 0.0.0.0 instead of 127.0.0.1 is the classic way a small server ends up in somebody's dataset. Bind local services to loopback first; the firewall is your second line, not your only one.

Then there is the half that gets skipped. Every plan here ships a /64 of IPv6 alongside its IPv4, and most modern daemons happily bind both families. If your rules only cover v4, a service you believe is firewalled is reachable over v6 by anyone who resolves the address — and IPv6 scanning of a known hosting prefix is entirely routine. ufw does handle both, but only when IPV6=yes is set in /etc/default/ufw; verify with ufw status verbose rather than assuming. Docker deserves the same suspicion: publishing a container port with -p inserts rules into its own iptables chain that are evaluated before ufw's, so a container you thought was protected is often wide open. Bind it to 127.0.0.1:port explicitly and put a reverse proxy in front. Whatever you configure, test it from somewhere else on the internet — a rule that has only ever been read is a rule that has never been tested.

SP·05

Updates you do not have to remember

Unpatched software is how most small servers are actually lost, and the reason is human rather than technical: patching is a chore that competes with everything else you have to do. Automate the security channel and the problem disappears. unattended-upgrades on Debian and Ubuntu applies security updates on a timer and stays out of the way; scope it to the security pocket rather than every available upgrade, so a routine feature release never reboots your application at three in the morning. This matters more on a self-managed offshore box than on a managed platform, because nobody is patching it for you and no account manager is going to email you about a critical CVE — there is no email address on file to reach.

Kernel updates need a restart to take effect, so decide your reboot policy deliberately instead of discovering it. needrestart will tell you which services are still running against deleted libraries, and an Unattended-Upgrade::Automatic-Reboot window in the small hours is fine for a stateless service. One important interaction: if you have followed our full-disk encryption guide and your root filesystem is encrypted, an automatic reboot stops at a passphrase prompt and stays there until you unlock it over the network. Either keep automatic reboots off on those machines, or make sure remote unlock is tested and you are awake for the window. Whichever you choose, write it down — a policy that lives only in your head stops existing the moment you are on holiday.

SP·06

Rate limiting, fail2ban, and the noise floor

Once password authentication is off, brute force against SSH cannot succeed. It is worth being clear about what tools like fail2ban buy you after that point: not a defence against guessing — that is already impossible — but a quieter log, less CPU spent on doomed handshakes, and a genuine control on the layers where secrets are still guessable. Point it at the places that matter: a web application's login form, a mail server's SMTP AUTH, an admin path someone is enumerating. ufw limit gives you a cheap connection-rate cap without any extra software at all. A handful of kernel knobs are worth the same five minutes — SYN cookies on, reverse-path filtering on, ICMP broadcast responses off, and IPv6 router advertisements ignored on a server that has a static address.

Know where the host stops, though. None of this survives a volumetric attack, because a flood fills the network pipe well before it troubles the CPU: by the time packets reach your nftables rules they have already consumed the bandwidth you were trying to protect. That is why L3/L4 scrubbing of up to 1.5 Tbps sits upstream of the fleet and is included on every plan rather than sold as an extra, with an optional L7 shield for application-layer floods that look like legitimate requests. Your host firewall handles precision; the network handles volume. Treating either as a substitute for the other is how people end up surprised.

SP·07

Locking yourself out is the real risk here

Of everything that can go wrong in this first hour, the overwhelmingly most likely outcome is not a break-in. It is you, at the end of a long session, reloading a broken sshd_config or enabling a firewall whose allow rule contains a typo, and discovering that the door has closed behind you. On a mainstream provider that is an annoyance. Here it deserves real respect, because registration is a handle and a password with eight recovery codes and no email anywhere in the loop, precisely so there is no identity to leak — and a provider that cannot identify you cannot identify you back into your server either. Nobody can vouch for you. That property is the product working as designed, and it is why the safeguards below are habits rather than suggestions.

Four of them cost nothing. Take a snapshot before you touch SSH or the firewall, so a bad reload is a rollback rather than a rebuild. Enrol a second public key from a different device — a phone, a work laptop, an offline backup — because one key on one disk is one spilled coffee away from being no key at all. Keep a second terminal connected while you change anything that could sever the first, and always test the new configuration from a fresh connection before you let go of the old one. And accept where the recovery ladder ends: snapshots live on the same host and are a rollback convenience, not a backup, so anything you would genuinely miss belongs in off-host storage — the daily encrypted backups add-on, or your own client-side encrypted copies pushed somewhere else. Your worst case should be redeploy and restore, measured in minutes, rather than gone.

SP·08

What to add next, depending on what the box does

The checklist above is the floor, and it is the same for every machine. What goes on top depends entirely on the job. A public web server wants TLS, a reverse proxy terminating it, the application running as an unprivileged user, and the database on loopback or on another box entirely. A VPN endpoint is a different shape — one UDP port, no web stack, no public services at all — and is worked end to end in rolling your own WireGuard VPN. A mail server is the most demanding of the three and needs rDNS control on the address, which every plan includes; self-hosting mail on an offshore VPS covers the deliverability half. A Tor relay is deliberately the opposite of anonymous — it is a published, contactable service — and the tradeoffs are set out in running a relay on a no-KYC VPS. Anything holding private state at rest should also be encrypted, which is a separate control with its own failure modes, covered in LUKS and remote unlock.

It is worth ending where hardening sits in the larger picture, because it is only one of three layers and they fail independently. What the host knows about you is the first, and here it is close to nothing: a handle funded by a prepaid crypto balance from $30.00, no card and no document in the chain — the subject of paying for hosting anonymously. Whose law applies is the second, decided by where the hardware sits across our 6 regions rather than by where you sit, and worked region by region in which offshore location should you pick?. What the machine itself allows is the third, and that one is yours alone — no provider can configure it for you. A VPS from $8.00/mo is online in about 15 min, which means the hour that follows is where the actual security of the thing is decided. Spend it deliberately.

SP·09

Step by step

  1. 01

    Deploy, then get in before anything else

    Deploy from the panel and pick a distribution you will actually keep patched — a current Debian or an Ubuntu LTS is the boring, correct answer. A VPS is online in about 15 min and its root credentials land in your panel. Connect straight away, bring the system fully up to date, and set a hostname so later logs are readable. Nothing else happens on this box until the rest of these steps are done.

    ssh root@203.0.113.10
    apt update && apt full-upgrade -y
    hostnamectl set-hostname edge-01
    apt install -y ufw unattended-upgrades needrestart
  2. 02

    Move off root: a named user, a key, and sudo

    Generate the keypair on your laptop, never on the server. Then create a named account on the box, put the public half in its authorized_keys, and give it sudo. Open a second terminal and log in as that user right now — before you change anything else, while root over SSH still works as a fallback.

    # on your own machine
    ssh-keygen -t ed25519 -C "laptop"
    ssh-copy-id -i ~/.ssh/id_ed25519.pub root@203.0.113.10
    
    # on the server
    adduser --disabled-password --gecos "" ops
    usermod -aG sudo ops
    install -d -m 700 -o ops -g ops /home/ops/.ssh
    cp /root/.ssh/authorized_keys /home/ops/.ssh/
    chown ops:ops /home/ops/.ssh/authorized_keys
    chmod 600 /home/ops/.ssh/authorized_keys
  3. 03

    Lock the SSH daemon down — with a second terminal open

    Write the changes to a drop-in file rather than editing the shipped config, so a distribution upgrade never quietly reverts them. Validate the syntax with sshd -t before reloading, reload, then prove it from a brand-new connection while the current one is still alive. If the new connection fails, you still have a working session to undo it in. One distribution trap: on Ubuntu 24.04 the daemon is socket-activated, so Port in sshd_config is ignored — set the port with systemctl edit ssh.socket instead, or disable the socket unit.

    cat > /etc/ssh/sshd_config.d/10-hardening.conf <<'EOF'
    Port 2222
    PermitRootLogin prohibit-password
    PasswordAuthentication no
    KbdInteractiveAuthentication no
    AllowUsers ops
    X11Forwarding no
    MaxAuthTries 3
    LoginGraceTime 20
    EOF
    sshd -t && systemctl reload ssh
    # new terminal, do not close the old one:
    ssh -p 2222 ops@203.0.113.10
  4. 04

    Default-deny the firewall, on both IP families

    Confirm IPv6 is enabled in ufw, then deny everything inbound and open only the ports you are deliberately serving — including the new SSH port, which must be allowed before you enable the firewall. Check what is actually listening while you are here, and move anything that should be local onto loopback.

    grep IPV6 /etc/default/ufw          # must read IPV6=yes
    ufw default deny incoming
    ufw default allow outgoing
    ufw limit 2222/tcp
    ufw allow 80,443/tcp
    ufw enable
    ufw status verbose
    ss -tulpen                           # anything on 0.0.0.0 or :: ?
  5. 05

    Turn on unattended security updates

    Enable the security channel only, so patches land without a feature upgrade restarting your application unannounced. Decide the reboot policy explicitly — and leave automatic reboots off if the root filesystem is encrypted and needs a manual unlock.

    dpkg-reconfigure -plow unattended-upgrades
    cat > /etc/apt/apt.conf.d/51-local <<'EOF'
    Unattended-Upgrade::Automatic-Reboot "false";
    Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
    EOF
    unattended-upgrade --dry-run --debug | tail -20
  6. 06

    Trim the noise and tighten the kernel knobs

    Add fail2ban for the layers where a secret can still be guessed, and set the handful of sysctl values that are simply correct on a public server with a static address. This is cheap, and it makes the logs worth reading.

    apt install -y fail2ban
    cat > /etc/sysctl.d/99-harden.conf <<'EOF'
    net.ipv4.tcp_syncookies = 1
    net.ipv4.conf.all.rp_filter = 1
    net.ipv4.icmp_echo_ignore_broadcasts = 1
    net.ipv4.conf.all.accept_redirects = 0
    net.ipv6.conf.all.accept_ra = 0
    kernel.kptr_restrict = 2
    EOF
    sysctl --system
  7. 07

    Verify from the outside, then write the runbook

    Trust the view from the internet, not the view from inside the box. Confirm the old SSH port is gone, that nothing unexpected answers, and that key-only login is genuinely enforced. Then write down the three facts you will need on your worst day: where your second key lives, which snapshot you took, and where the off-host backup is.

    # from another machine
    ssh -p 22 ops@203.0.113.10          # must time out or be refused
    ssh -p 2222 -o PreferredAuthentications=password ops@203.0.113.10
    # expected: Permission denied (publickey)
    ssh -p 2222 ops@203.0.113.10 'sudo ufw status verbose; uptime'
SP·10 — FAQ

Quick answers

Does moving SSH off port 22 actually make the server safer?

Not meaningfully, and it is worth saying so plainly — anyone scanning your address finds the new port in seconds, so it stops no one who is looking at you. What it does deliver is log hygiene: the vast majority of automated login attempts only ever knock on 22, so moving off it cuts the noise dramatically and leaves an auth.log you might actually read. Do it for that reason, after key-only authentication is enforced, never instead of it.

Do I still need fail2ban once password login is disabled?

Not for SSH itself. With PasswordAuthentication no there is nothing to brute-force, and every attempt fails on the first packet regardless of how many times it is repeated. It remains genuinely useful one layer up, wherever a guessable secret still exists: a web application's login form, SMTP AUTH on a mail server, an admin path being enumerated. Treat it as a tool for the application layer and for keeping logs legible, not as the thing standing between you and a compromise.

I locked myself out of my VPS — can support get me back in?

No, and that is a consequence of the design rather than a policy we could relax. Accounts here are a handle with a password and eight recovery codes, with no email, name or document anywhere in the loop — so there is no identity to verify and no out-of-band channel that could prove a machine is yours. Protect yourself in advance instead: take a snapshot before touching SSH or the firewall, keep a second key from a different device in authorized_keys, never close a working session while changing the one that carries it, and keep off-host backups so that redeploy-and-restore is always an option.

Is the server firewall enough, or do I need DDoS protection?

They solve different problems. A host firewall is precision — it decides which services exist — but it cannot help against volume, because a flood saturates the network link long before packets ever reach your rules. That is why L3/L4 scrubbing of up to 1.5 Tbps sits upstream and is included on every plan rather than sold as an upsell, with an optional L7 shield for application-layer floods that arrive looking like ordinary requests. Configure the host firewall for correctness and let the network absorb bandwidth.

Which operating system should I pick for a hardened box?

The one you will keep patched. A current Debian stable or an Ubuntu LTS is the pragmatic default: long support windows, security updates that land on a predictable schedule, and every tool in this guide packaged and tested. All of them are available at deploy time along with AlmaLinux, Rocky, Fedora, Alpine, Arch, FreeBSD and Windows Server. Because VPS plans are KVM full virtualization you run your own kernel, so nothing here is limited by the platform — the choice is about your update habits, not about what we allow.

Should I disable the root account entirely?

Disable root login over SSH — yes, once a named account with sudo is proven to work. Deleting or locking the account itself is a different and more aggressive move that breaks some recovery paths and a few packages, and it buys little once nothing can authenticate as root remotely. The sensible middle is PermitRootLogin prohibit-password while you are still building, then PermitRootLogin no once you are confident in the sudo path — and an AllowUsers line so no future account becomes an unplanned door.

Put it into practice

VPS online in 15 min, dedicated handed over in 2–12 h. Top up from $30.00 in crypto — no identity attached.

Deploy a VPS