Setting Up a VPS with sensible defaults
In this guide I will walk you through setting up a VPS with secure and sensible defaults. First manually so you understand what's happening a bit better and then with cloud-init to automate the whole process.
This guide focuses on Ubuntu.
Manually: Understanding the basics
Step 1: Generate your SSH key
First things first - if you don't already have an SSH key, let's create one on your local machine:
ssh-keygen -t ed25519 -C "[email protected]"
Now copy the public key it generated into your VPS provider's SSH keys area. You can get the public key with cat ~/.ssh/id_ed25519.pub if it was stored in the default path.
Go ahead and use this key to create your new server.
Step 2: Create a non-root user
Log into your new server with ssh root@your-server-ip
We shouldn’t generally be interacting with the server as the root user. If compromised, an attackers gets complete system control, and you can accidentally damage critical files with no safety net. A regular user with sudo is safer since you need to explicitly escalate privileges when you need it. Let's create one:
adduser tutorial
adduser tutorial sudo
The first command creates the user and asks you to set a password. The second adds it to the sudo group. We're using tutorial for the non-root user as an example but you can name it whatever you want.
Step 3: Setting up SSH access for the new user
Now we need to copy your SSH key to the new user:
mkdir /home/tutorial/.ssh
cp ~/.ssh/authorized_keys /home/tutorial/.ssh/authorized_keys
chown -R tutorial:tutorial /home/tutorial/.ssh
chmod u+rwx,go-rwx /home/tutorial/.ssh
chmod 600 /home/tutorial/.ssh/authorized_keys
authorized_keys file. That's why we can simply copy it over to our new user..ssh directory needs to be 700 (owner-only access) and authorized_keys needs to be 600 (owner read/write only).Step 4: Harden the SSH configuration
We should go ahead and lock down SSH access. Open the SSH config:
sudo vi /etc/ssh/sshd_config
Find and change these lines to:
PermitRootLogin no
PasswordAuthentication no
Then restart SSH to apply the changes:
sudo systemctl restart ssh
ssh tutorial@your-server-ip. Some people also like to change the default ssh port from 22 to something else but I won't cover that here as it doesn't affect security in any meaningful way.
Step 5: Set up the firewall
Ubuntu comes with UFW (Uncomplicated Firewall). Let's set it up:
sudo ufw allow OpenSSH
sudo ufw allow http
sudo ufw allow https
sudo ufw enable
sudo ufw status verbose
When you run ufw enable, it'll warn you about disrupting SSH connections. Since we already allowed OpenSSH, you can safely proceed.
Step 6: Enable automatic security updates
Keep your server patched without having to remember to manually update:
sudo apt update
sudo apt install unattended-upgrades
sudo dpkg-reconfigure -plow unattended-upgrades
Select "Yes" when asked if you want to automatically download and install updates.
For personal projects and non-critical services, automatic updates are usually worth the peace of mind.
The cloud-init way: automation from the start
Doing all that manually can get old fast. I'll show you how to configure your server automatically on first boot with cloud-init because it is supported by most VPS providers.
Here's a configuration that does everything we just did manually:
#cloud-config
users:
- name: tutorial
groups: sudo
shell: /bin/bash
sudo: ALL=(ALL) ALL
lock_passwd: false
passwd: $6$randomsalt$yourHashedPasswordHere
ssh_authorized_keys:
- ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... [email protected]
# Disable password authentication for SSH
ssh_pwauth: false
# Disable root SSH login
disable_root: true
# Install required packages
packages:
- ufw
- unattended-upgrades
# Configure firewall and security updates
runcmd:
- ufw allow OpenSSH
- ufw allow http
- ufw allow https
- ufw --force enable
- dpkg-reconfigure -plow unattended-upgrades
Do you see that passwd: $6$randomsalt$yourHashedPasswordHere part? We need to change that. You can generate it with openssl passwd -6 on your local machine. If you're on Windows then WSL could be a good option to get access to some Linux standard tools such as openssl.
This will prompt you for the password and output the hash. Copy the output and replace $6$randomsalt$yourHashedPasswordHere with it.
Also, don't forget to change the ssh_authorized_keys part to include the key you generated in the first step.
Then go ahead and use it during the VPS creation step (it should mention cloud-init somewhere). I am using Hetzner (referral URL: https://hetzner.cloud/?ref=KHnQDk7q1gJg, you'll get 20€, I'll get 10€) but many other providers support cloud-init as well, such as AWS, Google Cloud Platform, Azure, DigitalOcean, Linode, Vultr and OVHcloud.
What's next?
And with that your foundation is ready! With either approach, you now have:
- A non-root user with sudo access
- SSH key authentication only (no passwords)
- Root login disabled
- Basic firewall protecting your server
- Automatic security updates
Author’s Note: Claude assisted with editing and proofreading this post but the concept and final content are my own.