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
-dnames the domain (repeat for extra hosts)--redirectforce-forwards HTTP → HTTPS-mis 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 Forbidden —
www-datacan't read your files; fix perms with thechownabove. - 404 on
/— thetry_filesline or therootpath 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 -tfails — 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.