Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

VPS Setup

Overview

This guide covers the initial security setup for a fresh VPS. A new VPS typically comes with password authentication enabled and no protection against attacks. We’ll secure it by:

  1. Updating the system packages
  2. Creating a non-root user with sudo access
  3. Setting up SSH key authentication (more secure than passwords)
  4. Configuring automatic security updates (keeps the system patched)
  5. Installing Fail2Ban (blocks brute-force attacks)

After completing this guide, your VPS will have a solid security foundation for hosting services.

Prerequisites

  • A VPS running Ubuntu Server (commands should be similar on other Debian-based distributions)
  • Root or sudo access
  • SSH client on your local machine (Terminal on macOS/Linux, or Windows Terminal)

Initial System Update

Before doing anything else, update your system’s package list and install pending updates. This ensures you start with the latest security patches.

sudo apt update && sudo apt upgrade -y

What is sudo? It’s short for “superuser do” — it runs commands with administrator privileges. You’ll use sudo frequently when configuring your server.

Create a Non-Root User

Many VPS providers give you a default user (like ubuntu or root). It’s best practice to create your own non-root user for daily use.

Check if a user already exists

whoami

If you see root or a provider-created username, you can either use that or create a new one.

Create a new user

sudo adduser <username>

Set a password and fill in the optional details (you can press Enter to skip them).

Give the user sudo access

sudo usermod -aG sudo <username>

This allows the user to run commands with sudo (administrator privileges).

Switch to the new user

su - <username>

From here, all commands assume you’re logged in as this non-root user.

SSH Setup

SSH keys are more secure than passwords because they can’t be guessed or brute-forced. The key pair consists of a private key (stays on your machine) and a public key (goes on the server).

Generate a Key Pair

On your local machine, generate an ed25519 key:

ssh-keygen -t ed25519

Press Enter to accept the default location. Optionally set a passphrase for extra security.

This creates two files:

  • ~/.ssh/id_ed25519 - your private key (never share this)
  • ~/.ssh/id_ed25519.pub - your public key (safe to share)

Copy the Public Key to VPS

ssh-copy-id <username>@<vps-ip>

This appends your public key to the server’s ~/.ssh/authorized_keys file. You’ll need to enter your password one last time.

If ssh-copy-id fails (e.g., your VPS only supports key authentication from the provider), copy the contents of ~/.ssh/id_ed25519.pub manually and append it to the server’s ~/.ssh/authorized_keys file:

cat ~/.ssh/id_ed25519.pub
# Copy the output, then paste it into the VPS:
echo "<paste-your-public-key-here>" >> ~/.ssh/authorized_keys

Configure SSH Client

Add this to ~/.ssh/config on your local machine to simplify connections:

Host *
    AddKeysToAgent yes
    IdentitiesOnly yes
    ServerAliveInterval 60

Host vps
    HostName <vps-ip>
    User <username>
    Port 22
    IdentityFile ~/.ssh/id_ed25519

# UseKeychain yes  # macOS only — uncomment to store key in macOS Keychain

Host github.com
    HostName github.com
    User git
SettingPurpose
AddKeysToAgent yesAutomatically add keys to SSH agent
IdentitiesOnly yesOnly use explicitly configured keys
ServerAliveInterval 60Send keepalive every 60 seconds to prevent disconnection

Why isn’t IdentityFile in the Host * block? Putting it there would force ALL SSH connections to use that key, which can break connections to other servers. Keep it specific to each host.

macOS users: Uncomment UseKeychain yes to store your key passphrase in the macOS Keychain, so you don’t need to enter it every time.

Now you can connect with just:

ssh vps

No password needed.

Disable Password Authentication

Now that SSH keys are working, disable password-based login for better security. This prevents brute-force attacks.

Edit the SSH server config:

sudo vim /etc/ssh/sshd_config

Find and change these lines (remove the # if they’re commented out):

PermitRootLogin no
PasswordAuthentication no
ChallengeResponseAuthentication no

What do these do?

  • PermitRootLogin no: Blocks direct root login. Always use your user account with sudo instead.
  • PasswordAuthentication no: Disables password login — only SSH keys work.
  • ChallengeResponseAuthentication no: Disables another password-based auth method.

Restart SSH to apply:

sudo systemctl restart sshd

⚠️ Important: Test that SSH keys work before closing your current session! Open a new terminal and run ssh vps to verify. If something went wrong, you can still use the existing session to fix the config.

Timezone

Set the server timezone so logs show the correct local time:

sudo timedatectl set-timezone Asia/Jakarta

Verify with:

timedatectl

Replace Asia/Jakarta with your timezone. List available timezones with timedatectl list-timezones.

Auto Security Updates

Security vulnerabilities are discovered regularly. Unattended-upgrades automatically installs security patches so you don’t have to manually update.

Install and configure:

sudo apt install -y unattended-upgrades
sudo dpkg-reconfigure --priority=low unattended-upgrades

Select “Yes” when prompted to enable automatic updates.

The system will now:

  • Check for security updates daily
  • Install them automatically
  • Keep your system patched without intervention

Configuration (Optional)

Config file location: /etc/apt/apt.conf.d/50unattended-upgrades

To enable automatic reboots when required (e.g., kernel updates), add:

Unattended-Upgrade::Automatic-Reboot "true";

View update logs at: /var/log/unattended-upgrades/unattended-upgrades.log

Fail2Ban

Fail2Ban monitors log files for failed login attempts. When it detects repeated failures from an IP address, it bans that IP by adding a firewall rule.

This protects against brute-force SSH attacks where attackers try thousands of password combinations.

Install and Enable

sudo apt install -y fail2ban
sudo systemctl enable fail2ban
sudo systemctl start fail2ban

Check Status

View all active jails:

sudo fail2ban-client status

View SSH jail specifically (shows banned IPs):

sudo fail2ban-client status sshd

Unban an IP

If you accidentally get banned (e.g., too many failed logins):

sudo fail2ban-client set sshd unbanip <ip>

Custom Settings (Optional)

The default settings work well for most cases. To customize, create a local config:

sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo vim /etc/fail2ban/jail.local
SettingDefaultDescription
maxretry5Number of failures before ban
bantime10mHow long the ban lasts
findtime10mTime window for counting failures

Example: With defaults, 5 failed logins within 10 minutes triggers a 10-minute ban.

SSH jail (sshd) is enabled by default - no extra configuration needed.