Welcome to HowToShipIt — practical how-to guides for developers: code, AI tools, and servers, explained step by step.

How to Set Up a VPS From Scratch: Ubuntu, Nginx, and SSL

Introduction: How to Set Up a VPS with Ubuntu, Nginx and SSL

This guide walks you through how to set up a VPS with Ubuntu, Nginx, and SSL — from an empty virtual server to a live, HTTPS-secured website. By the end, your server will be hardened with SSH keys and a firewall, serving your site over Nginx with a free Let’s Encrypt certificate that renews itself.

Everything here is tested for Ubuntu 24.04 LTS. If you follow the steps in order, you should have a production-ready web server in about 30–45 minutes. All you need is a VPS account and a domain name.

What You’ll Need

  • A VPS (virtual private server) running Ubuntu 24.04 LTS — any provider works.
  • A domain name you can point at the server (a real domain is required for Let’s Encrypt SSL — IP-only setups can’t get a public certificate).
  • An SSH client: the built-in Terminal on macOS/Linux, or Windows Terminal / PowerShell on Windows.

Step 1 — Choose a VPS Provider

Pick a provider, create an account, and launch a server with Ubuntu 24.04 LTS (64-bit). A 1 vCPU / 1–2 GB RAM plan is plenty for a small site and costs a few dollars a month.

Three honest options, all widely used:

  • Hetzner Cloud — the best value in the industry: generous specs for very little money, and a clean control panel. Data centers are mostly in Europe and the US.
  • DigitalOcean — slightly pricier, but the control panel is beginner-friendly and its tutorial library is the best free resource on the web.
  • Hostinger — cheap plans with lots of hand-holding for beginners (though its upsells can get noisy).

During setup, most providers let you paste an SSH public key — do this if the option exists, since it saves you a step later. Note your server’s public IP address; you’ll need it constantly.

Step 2 — Connect to Your Server Over SSH

SSH (Secure Shell) is how you remotely control your VPS. From your local machine’s terminal, run:

ssh root@YOUR_SERVER_IP

Replace YOUR_SERVER_IP with your VPS’s IP. The first time you connect, you’ll see a fingerprint warning — type yes. Then enter your password (or your SSH key will log you in automatically if you pasted one at signup).

Once connected, you should see something like root@vps:~#. You’re now working on the server.

Update the system first

Before installing anything, update the package lists and install pending upgrades:

apt update && apt upgrade -y

Step 3 — Create a Non-Root User

Running everything as root is dangerous: one typo can wipe the system, and bots on the internet hammer the root account 24/7. Create your own user instead.

adduser deploy

You’ll be asked for a password and a few optional details. Then give the new user sudo privileges:

usermod -aG sudo deploy

Now copy your SSH key setup to the new user so you can log in as them later:

mkdir -p /home/deploy/.ssh
cp ~/.ssh/authorized_keys /home/deploy/.ssh/
chown -R deploy:deploy /home/deploy/.ssh
chmod 700 /home/deploy/.ssh
chmod 600 /home/deploy/.ssh/authorized_keys

Switch to the new user to confirm it works:

su - deploy

From now on, run commands with sudo in front. Check it works:

sudo whoami

This should print root — meaning your sudo rights work. Run the rest of this guide as deploy (or whatever name you picked).

Step 4 — Harden SSH: Key Authentication Only

Password logins are the weakest link on any server. Switch SSH to key-only authentication and disable root login entirely.

Generate a key on your local machine

On your local computer (not the server), generate an Ed25519 key if you don’t have one yet:

ssh-keygen -t ed25519 -C "your_email@example.com"

Accept the defaults and set a passphrase. Then copy your public key to the server:

ssh-copy-id deploy@YOUR_SERVER_IP

You should now be able to log in without a password prompt:

ssh deploy@YOUR_SERVER_IP

Do not continue until key login works. Open a second terminal, log in with your key, and keep your original session open while you change the SSH config. That way you always have a way back in if something goes wrong.

Disable passwords and root login

Ubuntu 24.04’s OpenSSH reads drop-in config files from /etc/ssh/sshd_config.d/ before the main config, so the cleanest approach is to add your own file rather than editing the stock one:

sudo nano /etc/ssh/sshd_config.d/60-hardening.conf

Paste these three lines:

PasswordAuthentication no
PermitRootLogin no
KbdInteractiveAuthentication no

Test the config for syntax errors before restarting SSH:

sudo sshd -t && echo "config OK"

If it prints config OK, restart the service. On Ubuntu, the SSH service unit is called ssh:

sudo systemctl restart ssh

Verify from a second terminal that you can still log in with your key — and that a password login is now refused.

Step 5 — Set Up the UFW Firewall

Ubuntu ships with UFW (Uncomplicated Firewall). The rule is simple: allow what you need, then enable. Allow SSH first, or you will lock yourself out.

sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable

When UFW warns that enabling it may disrupt existing SSH connections, type y — your SSH session survives because you allowed it first.

Check that the rules are in place:

sudo ufw status verbose

You should see port 22 (SSH), port 80 (HTTP), and port 443 (HTTPS) allowed, with a default policy of deny (incoming). The 'Nginx Full' profile is provided by the Nginx package itself and covers both 80 and 443.

Step 6 — Install Nginx and Deploy a Sample Site

Install Nginx

sudo apt install -y nginx
sudo systemctl enable nginx
sudo systemctl status nginx --no-pager

The status should show active (running). Visit http://YOUR_SERVER_IP in a browser — you should see the default Nginx welcome page.

Create a sample site

Let’s serve a real site. Create a document root for your domain and a simple page:

sudo mkdir -p /var/www/example.com
sudo nano /var/www/example.com/index.html

Put this in the file:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>It works!</title>
</head>
<body>
    <h1>Hello from my VPS!</h1>
    <p>Nginx is serving this page. SSL comes next.</p>
</body>
</html>

Now create an Nginx server block for your domain. Replace example.com with your real domain:

sudo nano /etc/nginx/sites-available/example.com
server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;
    root /var/www/example.com;
    index index.html;
    location / {
        try_files $uri $uri/ =404;
    }
}

Enable the site, disable the default, and test the config:

sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
sudo rm /etc/nginx/sites-enabled/default
sudo nginx -t && sudo systemctl reload nginx

nginx -t checks syntax before anything goes live; never skip it.

Step 7 — Point Your Domain at the Server

Log in to your domain registrar’s DNS panel and add two A records:

  • example.com → your VPS IP
  • www.example.com → your VPS IP

DNS can take a few minutes to a few hours to propagate. Verify it from your local machine:

dig +short example.com

It should print your VPS IP. Let’s Encrypt validates that you control the domain by connecting to port 80, so wait until DNS resolves correctly before continuing.

Step 8 — Get a Free SSL Certificate with Let’s Encrypt

Certbot is the official Let’s Encrypt client, and its Nginx plugin configures HTTPS automatically. The recommended install method on Ubuntu is via snap (snapd is preinstalled on Ubuntu 24.04):

sudo snap install core; sudo snap refresh core
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot

Now request a certificate for both the bare domain and www:

sudo certbot --nginx -d example.com -d www.example.com

Certbot will ask for an email address (for renewal reminders), ask you to agree to the terms, and then ask whether to redirect all HTTP traffic to HTTPS — say yes to the redirect.

When it finishes, visit https://example.com in your browser. You should see the padlock and your page loading over HTTPS.

Verify automatic renewal

Let’s Encrypt certificates expire after 90 days, but the certbot snap installs a renewal timer that runs twice a day. Test that renewal works:

sudo certbot renew --dry-run

You should see “Congratulations, all simulated renewals succeeded”. You never have to think about this again.

Step 9 (Optional) — Add fail2ban Against Brute Force

Even with passwords disabled, bots will keep knocking on your SSH port. fail2ban watches the logs and temporarily bans IPs that fail authentication too many times.

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

On Ubuntu, the sshd jail is enabled by default with sensible settings. Confirm it’s running:

sudo fail2ban-client status sshd

If you ever lock yourself out of something else, this is the service banning you — whitelist your own IP in /etc/fail2ban/jail.local if you want extra safety.

Common Pitfalls

A few things that trip beginners up:

  • Certbot says DNS or authorization failed. Your A records are wrong or haven’t propagated yet. Re-check with dig +short yourdomain.com and make sure port 80 is reachable (UFW and any provider-level firewall must allow it).
  • You can’t reach the site after enabling UFW. You allowed 'Nginx Full' after enabling the firewall, or not at all. Allow it now and reload: sudo ufw allow 'Nginx Full'.
  • nginx -t fails after editing a server block. Almost always a missing semicolon or a wrong root path. The error message names the exact line — fix it and test again.
  • Locked out of SSH. Most providers (Hetzner, DigitalOcean, Hostinger) offer a web console (VNC) in the control panel so you can log in as root directly and fix the config. Always keep one session open while changing SSH settings.

Final Checklist

Run through this to confirm everything is in place:

  • ssh deploy@YOUR_SERVER_IP — logs in with your key, no password prompt.
  • sudo ufw status verbose — shows SSH, HTTP, and HTTPS allowed; everything else denied.
  • https://example.com — loads with a valid certificate.
  • curl -I http://example.com — returns a 301 redirect to https://.
  • sudo certbot renew --dry-run — simulated renewal succeeds.
  • Run your domain through ssllabs.com/ssltest — you should get an A or A+ rating.

That’s it — a fully working, hardened web server on a fresh Ubuntu 24.04 VPS. From here, you can deploy real applications: serve static sites from /var/www/, proxy to a Node or Python app on localhost with Nginx, or add more domains with certbot --nginx -d newdomain.com.

Further Reading & References

Leave a Comment