Recently bought a server for my indie hacking projects. This is my brain dump for what I will do for any new VPS I have:
- The essentials
- System Updates
- SSH Setup
- Disable root password login
- Firewall (UFW)
- Fail2Ban
- Good-to-haves
- Self-hosted Vercel/Heroku: Dokploy/Coolify/Nixopus
- Monitor w/ Uptime Kuma
System Updates
First thing I always do is make sure everything is up to date.
# 🌐 On your server:
sudo apt update && sudo apt upgrade -yIf you're not on Ubuntu, also do this to auto-install security patches (it's a set-and-forget):
# 🌐 On your server:
sudo apt install unattended-upgrades -y
sudo dpkg-reconfigure --priority=low unattended-upgradesSSH Setup
We use Ed25519 instead of RSA. It's the modern standard: more secure, faster, and the keys are much shorter.
# [1️⃣ Generate the key]
# 🖥️ Generate a private/public key pair
ssh-keygen -t ed25519 -C "my-server-key" # my-server-key is a human-readable label, you can also omit and will default to your device name
# [2️⃣ Add the public key to the server]
# 2.1: ⚡ The fast way
# 🖥️ Do this
ssh-copy-id -i ~/.ssh/id_ed25519.pub root@your-server-ip
# It should say: Number of key(s) added: 1
# 2.2: 🐌 The slow way
# 🖥️ Copy it
cat ~/.ssh/id_ed25519.pub | pbcopy # Copies on Mac; xclip on Linux; clip on Windows
# 🌐 Write to authorized_keys
mkdir -p ~/.ssh
vi ~/.ssh/authorized_keys
# Paste key, save, and exit.
# Important: Lock down permissions or SSH might ignore it! (ssh doesn't like it if it's readable by other users)
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keysI'm new... How do SSH keys work?
Here is the easiest analogy to understand SSH keys. It is asymmetric encryption, which works like a specific Lock and Key pair:
-
id_ed25519 (The Private Key 🔑): This stays on your computer. You never share this. It is the only key in the world that can open the lock. Generally most devs have just 1 of this for all their servers (this is fine 🐶🔥).
-
id_ed25519.pub (The Public Key 🔒): This is the lock. You upload this to your server. Anyone is allowed to see the lock, but only your private key can open it.
Isn't it safer if the private key is on the server? Think of the Public Key as a Padlock you install on the server's door. The Private Key is the only key in the world that can open that padlock. When you connect, the server points to the padlock and says "Prove you have the key for this." Your laptop uses the private key to solve a math puzzle to prove it, without ever actually sending the secret key over the internet..
Typing ssh [email protected] is hard.
# 🖥️ Run this on your computer
vi ~/.ssh/config
# Add this block of code there
Host myserver
HostName 123.123.123.123 # <-- 1️⃣ Replace with your server IP
User root # <-- 2️⃣ The user you log in as
IdentityFile ~/.ssh/id_ed25519 # <-- 3️⃣ Optional, but good if you have multiple keys
# 🖥️ Now you can do
ssh myserverRemove password login
Once you have logged in using your SSH key, disable the password "door mat" so bots stop trying to guess it.
vi /etc/ssh/sshd_config
# Find: PasswordAuthentication yes
# 💡 You might find ones that start with `#`, those are comments, find the ones that don't.
# Change to: PasswordAuthentication no
sudo systemctl restart ssh
# Logout, then try to go back in with the password just to see if it's disabled.
exit
ssh -o PubkeyAuthentication=no -o PreferredAuthentications=password -o PasswordAuthentication=yes root@your-server-ip
# It should say: [email protected]: Permission denied (publickey).Log out, then back in with your key to be 100% sure it still works.
How do I recover my server if I can't ssh root@your-server-ip anymore?”
root@your-server-ip anymore?”Every serious host (Hetzner has “Rescue”, Netcup has “Recovery Console”) gives you a browser-console.
Boot into it, mount your disk, edit /etc/ssh/sshd_config → PasswordAuthentication yes, reboot, log in with the root password you set at install, drop in a fresh pubkey, then lock it back down.
After that, add a second SSH key and bookmark the console URL + root password in your password manager so this never ruins a weekend.
Firewall (UFW)
Lock down the ports. Only allow what's necessary (SSH, HTTP, HTTPS). That means you can't access stuff like postgres://, etc.
sudo ufw allow ssh
sudo ufw allow http
sudo ufw allow https
sudo ufw enableStill need to hit your Postgres from your laptop? (SSH tunnel)
SSH-tunnel in your GUI (TablePlus, DBeaver, etc.).
- Usually, GUI tools have an SSH section: server IP, user
root, pick yourid_ed25519key.
The client rides the already-allowed SSH port (22) and hops to 5432 internally—no extra firewall rules needed.
Fail2Ban
Simple brute-force protection that bans IPs after too many failed login attempts.
sudo apt install fail2ban -y
# Make sure it's running
sudo systemctl status fail2banGood-to-haves
-
Self-hosted Vercel/Heroku:
- https://dokploy.com - my favorite, UI is more intuitive
- https://coolify.io - neck and neck w/ dokploy
- https://nixopus.com - new very promising
-
Uptime Kuma
- I personally find this essential, you never know when you have downtime. You want to monitor this.
- If you haven't yet, add it to any server you own or as a new dokploy app: https://uptime.kuma.pet.
- Make sure to set it to ping all the services you care about, you can also use it for cron heartbeat monitoring (you add it to the cron execution code), and wire up Telegram/Discord/Slack/Emails so the alerts actually reach you.
References
how levelsio secures a VPS (the guy literally runs a 1m business w/ a VPS) — @levelsio