Built with Chinaski

Static Hosting with nginx

nginx serves the built static tree and forwards two URL families to the CMS daemon. The repo ships two example vhosts; this page covers both and the deploy-time root sync.

The two example files

  • deploy/chinaski.nginx.example — the minimal static vhost: document root, /forms/ and /documents/ proxy blocks, cache policies, and security headers.
  • deploy/chinaski.nginx.conf.example — the fuller per-instance example (port 80 by default; add TLS via certbot --nginx -d YOUR_DOMAIN after enabling the vhost).
  • Symlink into sites-enabled/, run nginx -t, then reload (systemctl reload nginx) after configuration.

The document root

Point root at the built output:

  • /var/www/chinaski<N>/output/<lang> — for path-based multilingual (individual language vhosts; e.g. one per language site).
  • /var/www/chinaski<N>/output — for monolingual sites (the none URL mode).

The deploy script auto-corrects the nginx root for you: on every deploy, deploy.sh rewrites the root directive in any nginx config referencing that install directory to match the current language mode (only output for none; else output/<default language>), runs nginx -t, and reloads — with a warning if the config test fails so you know to review manually.

Proxy blocks you need

  • location ^~ /forms/ proxies to http://127.0.0.1:CMS_PORT — required when any form on the site publishes submissions (or renders any form at all). Without it: “every form submit returns 404”.
  • location ^~ /documents/ — required when the site uses the documents feature; documents’ download tracking and publish state can’t be embedded in a static build.

Other static paths need nothing beyond try_files $uri $uri/index.html =404 (plus per-asset cache directives and security headers).

Cache headers the examples set

  • HTML — short maximum (5-minute revalidate), so published content is timely.
  • Service worker — no-cache (sw.js).
  • Fonts — 1-year immutable.
  • Other assets — 1 day.
  • Security headers — as belt-and-braces: the app sets them too; the proxy adds a layer for responses before the app gets a chance.

Loopback proxying (and why it requires no extra config)

The examples proxy from 127.0.0.1 — loopback, trusted by default in the app. If your real environment proxies to the CMS from a non-loopback address (a container bridge, for example), add that network to CHINASKI_TRUSTED_PROXIES so real client IPs are logged and rate limiting works per visitor.