104 lines
4.2 KiB
Nix
104 lines
4.2 KiB
Nix
#
|
|
# nginx for Solid Scribe on NixOS.
|
|
#
|
|
# Merge this into your configuration.nix and `nixos-rebuild switch`.
|
|
# Replace REPO_PATH with the absolute path of the repo clone on the server.
|
|
#
|
|
# Four things differ from the previous config, and the first two are required
|
|
# for the Vue 3 client to work at all:
|
|
#
|
|
# 1. SPA fallback. The old Vue 2 client used vue-router's default HASH mode
|
|
# (no `mode:` was set), so every request was just "/" and routing happened
|
|
# after the "#". That is why share links looked like /#/public/note/...
|
|
# The Vue 3 client uses createWebHistory, so /notes, /settings and
|
|
# /share-target are real HTTP requests. Without tryFiles they all 404.
|
|
#
|
|
# 2. root moves up to the vhost. It was inside locations."/", which left
|
|
# /assets/, /sw.js and /manifest.json unresolvable once they needed their
|
|
# own location blocks.
|
|
#
|
|
# It also no longer points into the repo. deploy.sh publishes the built
|
|
# client to /var/www/ss/releases/<timestamp> and atomically repoints the
|
|
# /var/www/ss/current symlink at it. Pointing nginx at that stable path
|
|
# means a deploy is one rename -- nginx resolves the symlink per request,
|
|
# so no reload is needed and no request sees a half-copied directory.
|
|
# Rollback is the same rename pointing at an older release.
|
|
#
|
|
# 3. proxyWebsockets on /socket. recommendedProxySettings does NOT add the
|
|
# Upgrade/Connection headers, so Socket.IO has been silently falling back
|
|
# to long-polling -- that's the live note-sync path running degraded.
|
|
#
|
|
# 4. Cache headers. See the warning below.
|
|
#
|
|
# !! CLOUDFLARE !!
|
|
# The tunnel sits in front of this and Cloudflare caches .js by DEFAULT, which
|
|
# includes /sw.js. If the edge caches the service worker, the update check can
|
|
# never see a new one and the app is pinned to an old build with no remote way
|
|
# to recover. The nginx headers below are necessary but NOT sufficient --
|
|
# add a Cloudflare Cache Rule that BYPASSES cache for /sw.js (and /index.html)
|
|
# before cutting over.
|
|
#
|
|
# Also confirm which Host header cloudflared sends. This vhost is keyed on
|
|
# "192.168.1.7"; if the tunnel forwards the public hostname instead, nginx will
|
|
# not match this vhost and will fall through to the default server. Either add
|
|
# the public hostname to serverAliases or set the tunnel's httpHostHeader.
|
|
#
|
|
|
|
services.nginx = {
|
|
enable = true;
|
|
recommendedProxySettings = true;
|
|
recommendedGzipSettings = true;
|
|
|
|
virtualHosts."192.168.1.7" = {
|
|
# serverAliases = [ "notes.example.com" ]; # if the tunnel forwards the public host
|
|
|
|
# Published by deploy.sh; a symlink to the live release. Not in the repo.
|
|
root = "/var/www/ss/current";
|
|
|
|
locations."/" = {
|
|
tryFiles = "$uri $uri/ /index.html";
|
|
};
|
|
|
|
# Never let the HTTP layer cache the service worker or the app shell.
|
|
locations."= /sw.js".extraConfig = ''
|
|
add_header Cache-Control "no-cache, no-store, must-revalidate";
|
|
expires -1;
|
|
'';
|
|
|
|
locations."= /index.html".extraConfig = ''
|
|
add_header Cache-Control "no-cache, no-store, must-revalidate";
|
|
expires -1;
|
|
'';
|
|
|
|
# The manifest changes rarely but should not be pinned for a year.
|
|
locations."= /manifest.json".extraConfig = ''
|
|
add_header Cache-Control "no-cache";
|
|
expires -1;
|
|
'';
|
|
|
|
# Vite content-hashes everything under /assets, so these are immutable.
|
|
locations."/assets/".extraConfig = ''
|
|
add_header Cache-Control "public, max-age=31536000, immutable";
|
|
'';
|
|
|
|
locations."/api" = {
|
|
proxyPass = "http://localhost:3000";
|
|
};
|
|
|
|
locations."/socket" = {
|
|
proxyPass = "http://localhost:3001";
|
|
proxyWebsockets = true;
|
|
};
|
|
};
|
|
};
|
|
|
|
# Note on file access: nginx runs as its own user and needs read access to the
|
|
# web root, with +x on every parent directory. Serving from /var/www/ss is what
|
|
# makes that a non-issue -- the one-time `chmod 755 /var/www /var/www/ss` in
|
|
# deploy.sh is the whole of it. This is the reason the root is not the repo
|
|
# clone: a clone under /home/mab would require loosening the permissions on the
|
|
# home directory itself.
|
|
#
|
|
# Uploads are NOT here. Express serves them from REPO_PATH/staticFiles at
|
|
# /api/static via the proxy below, so they are untouched by deploys.
|