← Back to blog

Setting Up a Fresh Ubuntu VPS the Right Way

Md Asaduzzaman · · 4 min read

DevOpsLinuxVPSDeployment

You just bought a VPS from DigitalOcean, Hetzner, Vultr or Contabo and got an IP address and a root password. Before you deploy anything, spend half an hour making the server safe. Bots start scanning a new IP for weak SSH logins within minutes.

This guide uses Ubuntu 24.04 LTS, but the steps are almost the same on 22.04 and on Debian.

Throughout this post, replace 203.0.113.10 with your server's IP and asad with your own username.

1. Log in and update everything

bash
ssh [email protected]

apt update && apt upgrade -y
apt install -y curl git ufw fail2ban unattended-upgrades

If the upgrade installed a new kernel, reboot with reboot and log in again.

2. Set the hostname and timezone

bash
hostnamectl set-hostname my-server
timedatectl set-timezone Asia/Dhaka

A correct timezone makes logs and cron jobs much easier to read.

3. Create a normal user with sudo

Working as root all day means one typo can break the whole machine. Create your own user and give it sudo rights:

bash
adduser asad
usermod -aG sudo asad

4. Log in with an SSH key instead of a password

On your own computer (not the server), create a key if you don't have one yet, then copy it to the server:

bash
ssh-keygen -t ed25519 -C "[email protected]"
ssh-copy-id [email protected]

On Windows without ssh-copy-id, print the key with type $env:USERPROFILE/.ssh/id_ed25519.pub in PowerShell and paste it into /home/asad/.ssh/authorized_keys on the server.

Now open a new terminal and check that this works without a password:

bash
ssh [email protected]

Keep your root session open until you are sure, so you can't lock yourself out.

5. Harden SSH

Edit the SSH config:

bash
sudo nano /etc/ssh/sshd_config

Find these lines (remove the # in front if there is one) and set:

ini
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes

On Ubuntu, also check /etc/ssh/sshd_config.d/: some providers put a file there that turns password login back on. Then test the config and restart:

bash
sudo sshd -t
sudo systemctl restart ssh

From now on, only your key can log in, and root can't log in over SSH at all.

6. Turn on the firewall

UFW ("uncomplicated firewall") blocks everything except the ports you open. Allow SSH first, or you will cut your own connection:

bash
sudo ufw allow OpenSSH
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status

Ports 80 and 443 are for the website we will deploy later. Your database, Node.js app and Redis should not be open to the internet; they only need to listen on 127.0.0.1.

7. Block brute-force attempts with Fail2ban

Fail2ban watches the SSH log and bans IPs that fail to log in too many times. The default jail for SSH is enough for most servers:

bash
sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd

8. Automatic security updates

bash
sudo dpkg-reconfigure --priority=low unattended-upgrades

Choose Yes. Ubuntu will now install security patches by itself every day.

9. Add swap on small servers

A 1 GB VPS can run out of memory while running npm install or docker build. A swap file prevents the build from being killed:

bash
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
free -h

10. Point your domain at the server

In your domain provider's DNS settings, add two A records:

TypeNameValue
A@203.0.113.10
Awww203.0.113.10

DNS can take a few minutes to a few hours to update. Check it with ping example.com.

Checklist

  • System updated
  • Normal user with sudo
  • SSH key login, no passwords, no root login
  • Firewall allows only 22, 80 and 443
  • Fail2ban and automatic security updates
  • Swap on small servers
  • Domain pointing at the server

The server is now ready for real work. In the next post we install Node.js and deploy a React app behind Nginx with free HTTPS.

© ALL RIGHT RESERVED ASADUZZAMAN