Technology

VPS Security Hardening Checklist: sshd_config, Fail2ban, Auto Updates and No-Root SSH

If you are running a VPS, SSH is usually the main door into your server. That also makes it the primary target for bots and attackers scanning the internet 24/7. A default install might work for quick tests, but for anything that handles real users, payments or internal data, you need a deliberate hardening checklist. In this guide, we will walk through the concrete steps we use at dchost.com when preparing Linux VPS servers: tightening sshd_config, configuring Fail2ban, enabling automatic security updates, and disabling direct root login – without locking yourself out.

The goal is not to turn you into a full-time security engineer. Instead, we will give you a practical, repeatable process you can apply on every new VPS or dedicated server. We will explain the “why” of each setting in simple terms, and then show you the exact configuration snippets. Apply these steps once, document them, and then reuse the same checklist across all your environments – whether you are hosting on a single VPS, multiple VPSs, or even colocated servers in a data center.

İçindekiler

A Practical VPS Security Hardening Checklist

Before we dive into file edits and commands, it helps to see the big picture. For most Linux VPS setups, a minimal but strong SSH-focused hardening checklist looks like this:

  • Create a non-root user with sudo access.
  • Harden the SSH service via /etc/ssh/sshd_config.
  • Install and configure Fail2ban to block brute-force attempts.
  • Enable automatic security updates for the OS.
  • Disable direct root SSH logins once everything is tested.
  • Add a firewall and monitoring on top (we will point to deeper guides for these).

We will assume a typical Linux VPS (Ubuntu/Debian or AlmaLinux/Rocky/RHEL family). If your distribution uses slightly different package names, the concepts stay the same.

1. Create a Non-Root Sudo User

Hardening SSH properly is much easier when you stop logging in as root directly. Root has unlimited powers; a single mistake or stolen credential can be catastrophic. A safer pattern is:

  • Log in as a regular user.
  • Use sudo to run administrative commands when needed.

Step 1: Create the user

While you still have root access (console or SSH), create a new user. Replace deploy with a username that makes sense for you:

# Ubuntu / Debian / AlmaLinux / Rocky / RHEL (as root)
adduser deploy
# or on some distros
useradd -m -s /bin/bash deploy
passwd deploy

Choose a strong password even if you plan to disable password logins later. It is your short-term safety net while setting up SSH keys.

Step 2: Add the user to the sudo group

On many distributions, members of the sudo or wheel group can run administrative commands via sudo:

# Ubuntu / Debian
usermod -aG sudo deploy

# AlmaLinux / Rocky / RHEL
usermod -aG wheel deploy

Test that sudo works:

su - deploy
sudo id

You should be prompted for the deploy user’s password, and then see an output containing uid=0(root) when sudo id runs successfully.

Step 3: Set up SSH keys for the new user

Password-based logins are one of the easiest ways for bots to brute-force access. SSH keys are far more resilient. From your local machine:

# Generate a key pair if you don't have one yet
ssh-keygen -t ed25519 -C "yourname@laptop"

# Copy the public key to the server for the deploy user
ssh-copy-id deploy@your-server-ip

If ssh-copy-id is not available, you can manually paste your public key into /home/deploy/.ssh/authorized_keys and set permissions:

mkdir -p /home/deploy/.ssh
chmod 700 /home/deploy/.ssh
nano /home/deploy/.ssh/authorized_keys  # paste your public key
chmod 600 /home/deploy/.ssh/authorized_keys
chown -R deploy:deploy /home/deploy/.ssh

If you plan to share access with teammates, we strongly recommend setting up a structured key workflow instead of sharing one key. You can find a detailed, step‑by‑step process in our guide on SSH key management and access sharing on a VPS.

2. Harden SSH with sshd_config

With a non-root user ready and SSH keys in place, the next step is to lock down the SSH daemon itself. This is done via /etc/ssh/sshd_config. Before you change anything, always keep one active SSH session open so you can fix mistakes if you misconfigure something.

Step 1: Back up your current sshd_config

cp /etc/ssh/sshd_config /etc/ssh/sshd_config.backup

If something goes wrong, you can revert quickly.

Step 2: Optional – Change the SSH port

Security professionals sometimes argue about this, but changing the SSH port does reduce noise from automated bots. It is not a primary defense, but it makes your logs much cleaner. For example, change the port to 2222:

Port 2222

Remember to:

  • Open the new port in your firewall (we will link to a firewall guide later).
  • Update your SSH command, e.g. ssh -p 2222 deploy@your-server-ip.

Step 3: Disable SSH protocol 1 (if still present)

Modern systems default to protocol 2, but it is good to be explicit:

Protocol 2

Step 4: Restrict which users can log in via SSH

Limit SSH access to your trusted users only. Add this near the end of sshd_config:

AllowUsers deploy

If you have multiple users, separate them with spaces:

AllowUsers deploy opsuser backup

Step 5: Force key-based authentication and disable passwords

Once you are certain your SSH key login works, disable password authentication to stop brute-force attempts from being effective:

PasswordAuthentication no
ChallengeResponseAuthentication no
UsePAM yes

Important: Only do this after you have successfully logged in as your non-root user with an SSH key in a separate terminal.

Step 6: Disable root login (preparation)

We will fully disable root login in a later section, but it is helpful to set the correct line now:

PermitRootLogin no

Again, do not restart SSH until you have tested your non-root user thoroughly.

Step 7: Other useful hardening options

Here are some commonly used sshd_config settings that improve security and reduce attack surface:

# Limit authentication attempts
MaxAuthTries 3

# Disconnect idle sessions (in seconds)
ClientAliveInterval 300
ClientAliveCountMax 2

# Optional: Only allow specific key types
PubkeyAcceptedKeyTypes ssh-ed25519,ssh-rsa

Step 8: Validate and reload SSH

Before reloading, run a configuration test:

sshd -t

If there is no output, your config is syntactically valid. Then reload the SSH daemon:

systemctl reload sshd   # Ubuntu / Debian / many distros
# or
systemctl reload ssh    # Some distros use this name

Open a new terminal window and verify you can log in as deploy with your SSH key. Only after that should you close old sessions.

If you want a broader, layered view of SSH and OS hardening, we also recommend our article The Calm, No‑Drama Guide: How to Secure a VPS Server, where we connect SSH security to firewalls, backups and monitoring.

3. Stop Brute‑Force Attacks with Fail2ban

Even with good sshd_config settings, bots will still try to connect and guess credentials. Fail2ban reads your logs and automatically bans IP addresses that show suspicious patterns, such as many failed SSH logins in a short period.

Step 1: Install Fail2ban

# Ubuntu / Debian
apt update
apt install fail2ban

# AlmaLinux / Rocky / RHEL
yum install epel-release -y
yum install fail2ban -y

Enable and start the service:

systemctl enable fail2ban
systemctl start fail2ban

Step 2: Create a local configuration

Never edit /etc/fail2ban/jail.conf directly. Instead, create /etc/fail2ban/jail.local (which overrides defaults):

nano /etc/fail2ban/jail.local

A good starting configuration for SSH might look like this:

[DEFAULT]
# Where to ban (iptables, nftables, firewalld, etc.)
banaction = iptables-multiport
bantime = 1h        # 1 hour
findtime = 10m      # Look at 10-minute windows
maxretry = 3        # 3 failed attempts before ban

[sshd]
enabled  = true
port     = ssh
logpath  = /var/log/auth.log
backend  = systemd

On RHEL-based systems, you might use a different log path such as /var/log/secure:

logpath  = /var/log/secure

Step 3: Whitelist your office or VPN IPs

To avoid accidentally blocking yourself or your team, add trusted IPs to the ignoreip directive:

[DEFAULT]
ignoreip = 127.0.0.1/8 192.0.2.10 203.0.113.0/24

Replace the example IPs with your real office VPN ranges or home IP addresses.

Step 4: Restart Fail2ban and verify jails

systemctl restart fail2ban
fail2ban-client status
fail2ban-client status sshd

The output should show the sshd jail as enabled and list any banned IPs once attacks start hitting your server.

Step 5: Tune ban policies over time

Fail2ban is not a “set it and forget it” tool. In the first days, watch your logs and jails:

  • If legitimate users get banned often, loosen maxretry or shorten bantime.
  • If you see thousands of attempts from the same country or range, consider longer bans (e.g., 24h or even permanent) and additional firewall rules.

Fail2ban can protect more than just SSH, such as web panel logins or web applications. For example, in another article we show how to combine Nginx rate limiting and Fail2ban to protect WordPress logins from bots. If that is relevant to you, check out our guide on stopping wp-login.php and XML‑RPC brute‑force attacks with Fail2ban.

4. Enable Automatic Security Updates

SSH and Fail2ban reduce the chance of someone getting in, but you also need to keep the underlying operating system patched. Many critical vulnerabilities (kernel, OpenSSH, glibc, etc.) are fixed via security updates. If you forget to apply them, your server may remain vulnerable for months.

There are two main patterns:

  • Automatic security updates for OS packages.
  • Manual or controlled updates for application-level changes (e.g., major PHP or database upgrades).

Automatic security updates on Ubuntu/Debian

Install the unattended-upgrades package:

apt update
apt install unattended-upgrades apt-listchanges

Enable it:

dpkg-reconfigure --priority=low unattended-upgrades

This wizard creates or updates /etc/apt/apt.conf.d/50unattended-upgrades. Inside, ensure that security repositories are enabled, for example:

Unattended-Upgrade::Origins-Pattern {
  "origin=Ubuntu,codename=${distro_codename},label=Ubuntu-Security";
};

You can also configure:

  • Email notifications when updates are applied.
  • Automatic removal of unused dependencies.
  • Automatic reboots if a kernel update requires it (use with care on production systems).

Automatic security updates on AlmaLinux / Rocky / RHEL

On these distributions, use dnf-automatic (or yum-cron on older releases).

yum install dnf-automatic -y

Edit the configuration file:

nano /etc/dnf/automatic.conf

Key options to review:

apply_updates = yes
upgrade_type = security
emit_via = email

Enable the timer to run periodically:

systemctl enable --now dnf-automatic.timer

You can check its status with:

systemctl list-timers *dnf-automatic*

Balancing automation and stability

On critical production systems, you may not want every single update applied automatically without any testing. Here is a balanced approach we often recommend:

  • Enable fully automatic security updates for the OS.
  • For application stack (e.g., web server, database), apply updates on a staging server first.
  • Use monitoring to detect issues after updates (e.g., HTTP checks, log alerts).
  • Always pair updates with a solid backup strategy so you can roll back if needed.

If you are still building your backup strategy, our guide on how to apply the 3‑2‑1 backup strategy on your VPS shows how to automate reliable, off‑site backups.

5. Safely Disable Direct Root Login

With a non-root sudo user, hardened sshd_config, Fail2ban and security updates in place, you can now remove one of the biggest risks: direct root SSH logins.

Why disabling root login matters

Root is a known username. Attackers know it exists and will try to guess its password. Even if you are using keys, disabling direct root login gives you:

  • An extra step for attackers (they must compromise a non-root account first).
  • Better auditability (sudo logs show which user ran which command).
  • A strong protection against accidental destructive commands while logged in as root.

Step 1: Confirm your sudo user works perfectly

Before touching root login, double-check from your local machine:

ssh deploy@your-server-ip
sudo -l
sudo systemctl status sshd

You should be able to use sudo without problems. If this fails, fix it now – do not proceed.

Step 2: Edit sshd_config to disable root login

Open the SSH configuration:

sudo nano /etc/ssh/sshd_config

Find the PermitRootLogin line and set it to:

PermitRootLogin no

Make sure you do not have conflicting lines (e.g., one commented and one active). There should be exactly one active PermitRootLogin no entry.

Step 3: Test configuration and reload

sudo sshd -t
sudo systemctl reload sshd

Now, try logging in as root from a new terminal:

ssh root@your-server-ip

You should see a “Permission denied” type error. Logging in as deploy with your key should still work. From now on, you will escalate privileges via sudo only.

Step 4: Adjust your operational habits

After disabling root SSH, make sure your operational workflows follow these principles:

  • Do not share the same SSH key among multiple humans; give each person their own user or their own key.
  • Use sudo for all administrative tasks and review /var/log/auth.log (or /var/log/secure) regularly.
  • If you use automation (Ansible, scripts, CI/CD), update them to connect as the non-root user and use sudo where required.

If you are designing a more advanced SSH architecture (e.g., SSH CA, FIDO2 keys, bastion host), our deep‑dive article on VPS SSH hardening with FIDO2 keys and SSH CA walks through production‑grade patterns we see in real projects.

6. Extra Layers: Firewall, Monitoring and Infrastructure Choices

The four pillars we covered so far (sshd_config, Fail2ban, automatic updates and no-root SSH) dramatically improve your VPS security posture. To complete the picture, you should also add a firewall and basic monitoring.

Add a host-based firewall

A firewall enforces which ports on your VPS are reachable from the internet. Even if you have cloud-level security, we strongly recommend a host firewall as a second layer:

  • UFW for simple, human-friendly rules on Ubuntu/Debian.
  • firewalld on many RHEL-based systems.
  • iptables or nftables for advanced setups.

At minimum:

  • Allow your SSH port (e.g., 2222).
  • Allow HTTP/HTTPS (80/443) if you are running a web server.
  • Deny everything else by default.

For a full tutorial with examples, see our guide on how to configure a firewall on your VPS with ufw, firewalld or iptables.

Set up basic monitoring and alerts

Security is not just about preventing incidents; it is also about detecting them quickly. Monitoring helps you notice:

  • SSH login anomalies (sudden logins from unusual IPs).
  • Resource spikes that may indicate abuse or malware.
  • Services going down after an automatic update.

We like combining metrics, logs and uptime checks. A good starting point is our article on how to set up VPS monitoring and alerts with Prometheus, Grafana and Uptime Kuma.

Choose infrastructure that supports security

All of these best practices work best when your underlying infrastructure is reliable and transparent. At dchost.com, we run VPS, dedicated servers and colocation in professional data centers with attention to:

  • Consistent, stable kernel and OS images for your VPS installs.
  • Clear network policies that play nicely with host-based firewalls and Fail2ban.
  • Options for dedicated servers or colocation when you need stricter isolation or custom security hardware.

If you outgrow a single VPS, you can easily scale to multiple VPS nodes, a dedicated server, or even colocate your own hardware in our data centers while keeping the same hardening checklist.

Putting It All Together: Your Reusable VPS Hardening Checklist

Security hardening does not have to be a one‑off, stressful project. Once you convert it into a checklist, you can apply it calmly to every new VPS, dedicated server or environment you deploy. Here is a concise version of the process we covered:

  1. Create a non-root sudo user and set up SSH keys for that user.
  2. Harden sshd_config: restrict users, prefer keys, reduce auth attempts, optionally change the port, and prepare PermitRootLogin no.
  3. Install and configure Fail2ban to automatically block brute-force attacks on SSH (and later, on other exposed services).
  4. Enable automatic security updates for your Linux distribution so critical patches are applied even if you are busy.
  5. Disable direct root SSH login once you are confident your non-root user and sudo setup work correctly.
  6. Add a firewall and monitoring on top to build a layered defense.

Document these steps in your internal runbooks and apply them every time you deploy a new VPS at dchost.com, spin up a fresh node for a cluster, or prepare a dedicated server. Over time, you can extend the checklist with items like HTTP security headers, WAF rules, log retention and database hardening; our blog already covers many of these topics, such as HTTP security headers done right and step‑by‑step VPS security hardening for real‑world threats.

If you want help choosing the right VPS or dedicated server size for your workload and then applying this hardening checklist from day one, our team at dchost.com is here to guide you. Start with a clean VPS, follow the steps above, and you will be running on a significantly more secure foundation than most servers on the internet.

Frequently Asked Questions

Root is a universal, well-known username with full privileges. Attackers constantly target it with brute-force attempts, knowing that one successful login gives them complete control. By disabling direct root SSH access and instead logging in as a non-root user with SSH keys plus sudo, you add an extra layer: an attacker must first compromise a regular account and then escalate. You also gain better audit logs, because sudo records which named user ran each privileged command. In practice, removing root SSH access closes one of the most common and dangerous entry points on internet-facing servers.

Changing the default SSH port from 22 to a high, non-standard port is not a silver bullet, but it is still useful. It does not replace proper security controls like SSH keys, Fail2ban and disabling password logins. However, it significantly reduces the noise from automated bots that blindly scan port 22 across the internet. With a custom port and proper firewall rules, your logs become cleaner, real attacks stand out more, and Fail2ban has less work to do. So think of it as a low-cost, low-effort improvement that complements – not replaces – real hardening measures.

Fail2ban should strike a balance between blocking attackers quickly and not locking out legitimate users. As a starting point, we like maxretry 3, findtime 10 minutes and bantime 1 hour for SSH. Watch your logs for a few days: if legitimate admins occasionally mistype passwords or struggle with keys, you can slightly increase maxretry or reduce bantime. If you see clear brute-force waves from the same IP ranges, you can increase bantime significantly or add network-level blocks. The key is to treat Fail2ban as a living configuration: review its ban list regularly and tune it based on real traffic patterns.

Automatic security updates are strongly recommended for most VPS environments, but the level of automation depends on your risk tolerance and change management process. For small to medium projects, enabling unattended security updates for the OS (kernel, OpenSSH, system libraries) is usually safer than leaving known vulnerabilities unpatched for months. For large or sensitive systems, a common pattern is: auto-apply OS security fixes, but stage application-stack updates (web server, database, runtime) in a test environment first. In all cases, pair automatic updates with monitoring and good backups so you can quickly detect and recover from any rare regressions.