Ahosting Logo

VPS Hosting

Securing Your VPS: Best Practices

Five changes that remove most of the risk, in orderKey authentication onlythis endsautomatedpassword guessingoutrightA normal user with sudoso actions areattributable, androot is not aloginDefault-deny firewallopen what youserve, nothingelseAutomatic security updatesbecause the gapbetween patch andattack is shortFail2ban and monitoringthe layer thatassumes theothers failedThe first change removes more risk than the other four combined, and takes about two minutes.

A VPS with root access is a server you are responsible for. Nobody patches it for you, nobody notices when it is attacked, and the automated scanning starts within minutes of the address becoming reachable, not because anyone targeted you, but because every address is scanned continuously.

Five things remove most of the risk. They take about an hour and they matter far more than anything else you could install.

1. Stop password logins over SSH

Automated attempts against SSH are constant. A key removes the entire category, because guessing is no longer possible.

Create a key on your own machine, copy the public half to the server, and confirm you can log in with it before changing anything else. Then disable password authentication in the SSH configuration:

PasswordAuthentication no
PermitRootLogin prohibit-password

Reload SSH and open a second connection to test while the first is still open. If you have locked yourself out, the existing session is how you fix it. Closing the only session before testing is the classic way to need console access.

2. Log in as a normal user, not root

Create a user, give it sudo, and use that. Root is then reachable only through an account that has to authenticate first.

This is not ceremony. It means a mistake requires a deliberate sudo, and it removes the single most attacked username on the internet from your login surface.

3. Run a firewall that denies by default

The default posture should be that nothing is reachable unless you allowed it. Open SSH, HTTP and HTTPS; leave everything else closed.

Databases in particular should not be reachable from outside. A MySQL port open to the internet is scanned and attacked within hours, and there is almost never a reason for it. The application connects locally.

Add SSH to the allow list before enabling the firewall. Enabling a default-deny firewall over SSH without that rule disconnects you immediately.

4. Apply security updates automatically

Most compromises exploit a known vulnerability with a patch already available. The gap between disclosure and mass exploitation is measured in hours.

Enable unattended security updates. A server nobody patches becomes a liability regardless of how carefully it was configured on day one, and manual patching is a discipline that lapses within a month on every server anyone has ever owned.

5. Limit repeated failures

Install a tool that blocks an address after repeated failed logins. It does not make guessing impossible; it makes it too slow to be worth an attacker's time, which is the whole game against automated attacks.

Then: know what is running

List the services listening on a port and turn off anything you did not put there deliberately. A default image often runs more than you need, and every listening service is something to keep patched.

Check this again after installing anything, because packages frequently start services you did not ask for.

Backups are the layer that assumes the rest failed

Everything above tries to prevent a compromise. A backup is what you have when one of them did not work, and it must live somewhere the server cannot reach, or a compromised server takes the backups with it.

Backing up and restoring your VPS goes over doing that properly, including the restore test that turns an archive into an actual capability.

What this does not cover

Your application. A hardened server running an outdated CMS is compromised through the CMS, and none of the above prevents it.

Server security and application security are separate jobs and both are yours on a VPS. That is the trade you accepted for root access. Comparing the tiers walks through it honestly.

For blocking repeated login attempts specifically, Setting Up Fail2ban on a VPS goes over setting it up and verifying it actually works.

The most common way a server is compromised is an unapplied fix. How to Set Up Automatic Security Updates explains closing that gap without inviting breakage.

Two-factor codes that are typed correctly and rejected anyway usually have nothing to do with authentication. Why a Server Clock Matters and How to Keep It Right deals with the cause.

Reduce what is listening before hardening what remains

The five measures above protect the ways in. This one removes them.

ss -tlnp

A default installation typically listens on more than it needs: a database on every address rather than only the loopback one, a mail server nobody configured, a monitoring agent, a cache.

Anything that only serves the machine itself should bind to 127.0.0.1. That is stronger than a firewall rule, because it does not depend on the firewall being correct, and firewall rules are frequently correct for one address family and absent for the other.

A database listening on all addresses is the single most common finding here, and it is a serious one. Managing databases on a VPS goes into binding it properly.

Separate the application from the machine

Every service should run as its own unprivileged user, not as root and not as the same user as everything else.

The point is containment. A vulnerability in one application then reaches that application's files and nothing else: not the database credentials of a second site, not the backups, not the keys.

This costs nothing at setup and cannot be retrofitted easily, which is why it belongs in the first hour rather than later. Running an application as a systemd service explains the user setting that does it.

Know when something changes

Prevention fails eventually, and the second question is how long it takes to notice.

Three cheap signals cover most of it: an alert when a package is installed or removed, an alert when a user account is created, and a periodic check that the files in the web root have not changed unexpectedly.

ausearch -m ADD_USER -ts today 2>/dev/null
grep -E 'useradd|usermod' /var/log/auth.log | tail

None of this stops an intrusion. All of it shortens the gap between an intrusion and somebody knowing, which is what determines how much damage is done. Managing logs and log rotation walks through keeping the record long enough to be useful.

Two things that quietly undo the rest

A stale kernel. Automatic updates install the packages and a running machine keeps using the old kernel until it restarts. A server that has been up for eight months is running eight months of known kernel issues, whatever the package list says.

uname -r
ls /boot/vmlinuz-* | tail -1

If those differ, a reboot is outstanding. Schedule it rather than avoiding it. Setting up automatic security updates explains arranging that deliberately.

Forgotten access. Authorised keys for people who have left, a firewall exception added for one afternoon two years ago, an FTP account created for a contractor.

Read ~/.ssh/authorized_keys and the firewall rules once a year and remove anything you cannot account for. Access accumulates silently and nothing ever expires it.