TechCircuit.

Technical news, guides and deep-dives across AI, programming and the open-source world


DevOps & Self-HostingSep 14, 2026497 words
How-To Guide

How to Host a Static Site on Nginx with Free Let's Encrypt HTTPS

Serving a static site on Nginx with free HTTPS is one of the most reliable jobs in self-hosting. I used exactly these steps to put a site live with a trusted certificate — here's the whole sequence, copy-paste friendly.

1Install Nginx and Certbot

On Ubuntu:

sudo apt update
sudo apt install -y nginx certbot python3-certbot-nginx
sudo systemctl enable --now nginx

Verify Nginx is serving: curl -s -o /dev/null -w "%{http_code}" http://<server-ip>/ should print 200 (the default welcome page, which you'll replace).

2Prepare your site files

Put the static files where Nginx will serve them — the conventional location is /var/www/<site>/:

sudo mkdir -p /var/www/mysite
# copy/index your site's index.html etc. into /var/www/mysite/
sudo chown -R www-data:www-data /var/www/mysite

Nginx runs as www-data, so files it reads need to be readable by that user (this is the #1 cause of 403 errors — a build directory under /root/ or another user's home that www-data can't traverse).

3Write a vhost config

Create /etc/nginx/sites-available/mysite:

server {
    listen 80;
    server_name mysite.example.com;
    root /var/www/mysite;

    location / {
        try_files $uri $uri/ =404;
    }

    location ~*\.(css|js|png|jpg|svg|ico|woff2?)$ {
        add_header Cache-Control "no-store";
    }
}

Enable it and reload:

sudo ln -s /etc/nginx/sites-available/mysite /etc/nginx/sites-enabled/mysite
sudo nginx -t          # must print "syntax is ok"
sudo systemctl reload nginx

4Point DNS at the server

For the certificate to work, your domain must resolve to this server. Add an A record for your hostname pointing at your server's public IP (most DNS panels support this; if you're on a provider with an API, that's scriptable).

Check it with:

dig +short mysite.example.com @8.8.8.8

It should print your server IP.

5Issue a free certificate

Certbot reads your Nginx config and fills in the 443 + redirect blocks automatically:

sudo certbot --nginx -d mysite.example.com --redirect -m you@example.com
  • -d names the domain (repeat for extra hosts)
  • --redirect force-forwards HTTP → HTTPS
  • -m is the contact for expiry notices

Confirm it worked:

curl -s -o /dev/null -w "%{http_code}" https://mysite.example.com/   # 200
curl -s -o /dev/null -w "%{http_code}" http://mysite.example.com/    # 301 (redirect)

6Automatic renewal

Certbot installs a systemd timer for you. Verify it's armed:

sudo systemctl list-timers | grep certbot
sudo certbot renew --dry-run   # confirms renewal path works

The 90-day certificates renew automatically; nothing further to do.

Common failures

  • 403 Forbiddenwww-data can't read your files; fix perms with the chown above.
  • 404 on / — the try_files line or the root path is wrong.
  • Certbot can't validate — your DNS A record isn't pointing at this server, or the domain resolves elsewhere. Fix DNS and wait for propagation, then re-run.
  • nginx -t fails — a syntax error in the vhost or a missing closing brace; check before reloading.

That's the whole path: install, serve, secure. From an empty box to a wire-verified HTTPS site in a few minutes.