server {
listen 80;
server_name example.com;
root /var/www/example.com/dist;
# /blog/ and /about/ redirect to /blog and /about, the URLs Stati writes
rewrite ^/(.+)/$ /$1 permanent;
location / {
# /about is about.html, / is index.html
try_files $uri $uri.html $uri/ =404;
}
# Stati writes site/404.md as 404.html
error_page 404 /404.html;
}
Stati writes every page as an .html file named after its URL: /about is dist/about.html, /blog is dist/blog.html next to the dist/blog/ folder of its posts, and only the home page is an index.html. stati preview and Netlify serve that as it is. Plain nginx needs the $uri.html in try_files.
The rewrite matters too. Without it, /blog/ hits the blog/ folder, which has no index.html of its own, and nginx answers with a 403. A permalink that ends in / is the one way to get a folder with an index.html in it, and $uri/ covers those.
While you're at it, keep the 404 page out of the sitemap and the search index:
sitemap: { enabled: true, excludePatterns: ['/404'] },
search: { enabled: true, exclude: ['/404'] },
For HTTPS on top, see redirect www and http to https in nginx.
In the Stati docs: Clean URLs and Front matter URL override.