How to host a static site on a VPS with Nginx
Managed platforms like Vercel or Netlify are great, but sometimes you just want a cheap VPS and complete control over your files. Setting up Nginx and Let’s Encrypt from scratch takes a bit of work, but it’s worth it for the flexibility. Here is how to do it.
Prerequisites
- A Linux VPS (Ubuntu or Debian works fine).
- A domain name pointing to your server’s IP address.
- Basic terminal knowledge.
1. Connect and create a non-root user
You shouldn’t run your server as root. It’s too easy to break things or leave security holes. SSH into your server as root first:
ssh root@your_server_ip
Create a new user (I’ll use deployer) and give them admin rights:
adduser deployer
usermod -aG sudo deployer
Switch to your new user:
su - deployer
Note: For future logins, SSH directly as this user (ssh deployer@your_server_ip).
2. Update your server
Always update your package lists before installing new software:
sudo apt update && sudo apt upgrade -y
3. Configure the firewall
VPS providers often assign IPs that get constantly scanned by bots. You need a firewall. UFW (Uncomplicated Firewall) is the easiest way to handle this. Open up SSH, HTTP, and HTTPS:
sudo apt install ufw -y
sudo ufw allow 22
sudo ufw allow 80
sudo ufw allow 443
sudo ufw logging off
sudo ufw enable
sudo ufw status
4. Install Nginx, Certbot, and Git
Now we need the actual web server, the tool to get our free SSL certificate, and Git to pull down our code.
sudo apt install nginx certbot python3-certbot-nginx git -y
5. Fetch your website files with Git
Create a parent directory for your website. Replace example.com with your actual domain.
sudo mkdir -p /var/www/example.com
Change the ownership of the directory to your current user. This lets you clone your repository without using sudo:
sudo chown -R $USER:$USER /var/www/example.com
Clone your static site repository into a static folder:
git clone https://github.com/yourusername/your-static-site-repo.git /var/www/example.com/static
(If you just want to test things out without a repo, you can make an index.html file manually instead:)
mkdir -p /var/www/example.com/static
echo "<h1>Hello World from my VPS!</h1>" > /var/www/example.com/static/index.html
6. Configure Nginx
Create a new Nginx server block for your domain:
sudo nano /etc/nginx/sites-available/example.com
Add this configuration. Make sure to swap in your actual domain and file paths:
server {
listen 80;
server_name example.com www.example.com;
root /var/www/example.com/static;
index index.html;
location / {
try_files $uri $uri/ =404;
}
access_log /var/log/nginx/example.com.access.log;
error_log /var/log/nginx/example.com.error.log;
}
Save and exit (in nano, press Ctrl+O, Enter, then Ctrl+X).
7. Enable the site and reload Nginx
Create a symlink to enable the site:
sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
Test your Nginx config for typos:
sudo nginx -t
If it passes, reload Nginx:
sudo systemctl reload nginx
8. Secure your site with SSL
HTTPS isn’t optional anymore. Browsers will flag your site if you don’t have it. Certbot makes this painless:
sudo certbot --nginx -d example.com -d www.example.com
Certbot will ask for an email address and prompt you to agree to the terms. It automatically updates your Nginx config to use the certificate and forces HTTP traffic to HTTPS.
9. Final verification
Test and reload Nginx one last time:
sudo nginx -t && sudo systemctl reload nginx
That’s it. Your site is live. Certbot sets up a background timer to renew your certificates automatically, so you don’t have to touch it again.