Deploy to nginx
A production recipe for putting a Chinaski-built site behind nginx: serve the static output, proxy the few dynamic routes back to the CMS daemon, add TLS, and let deploys keep everything in sync.
Prerequisites
- A running CMS instance (the
chinaski@<N>unit) with the daemon bound to loopback. - A built output directory at
/var/www/chinaski<N>/output/<lang>(oroutput/for a monolingual site with no language prefix). - The repo’s example vhost (
deploy/chinaski.nginx.examplefor a minimal static site;chinaski.nginx.conf.examplefor the fuller per-instance pattern).
The three values to replace
In the copied vhost, set:
- YOUR_DOMAIN: the site’s public hostname.
- OUTPUT_PATH: the per-language output directory from above.
- CMS_PORT: the port matching
LISTEN_URLin/etc/chinaski<N>/env(3001 for instance 1 by default).
Activation:
ln -s /etc/nginx/sites-available/YOUR_DOMAIN /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginxThen add TLS:
certbot --nginx -d YOUR_DOMAINThe two proxy blocks you must not omit
A “static” Chinaski site has exactly two URL families that have to reach the CMS daemon:
/forms/: form placeholders embed into built pages, but submissions POST back to the CMS. Without this block every form submission returns 404./documents/: document downloads are served by the CMS (tracked download counts, publish windows). Without this block every document URL returns 404.
Both blocks forward the standard headers (Host, X-Real-IP, X-Forwarded-For, X-Forwarded-Proto) so the CMS sees the real client, needed for its rate limiting and logging to work per visitor.
Denote admin traffic separately: the admin interface lives on its own vhost (or the CMS’s own loopback port if you don’t expose it publicly). The checklist pattern proxying from loopback keeps the CMS’s trusted-proxy logic simple: no extra CHINASKI_TRUSTED_PROXIES setting is needed because the connection comes from loopback. If your architecture makes nginx reach the daemon from a non-loopback address (e.g. a container bridge), add that network to CHINASKI_TRUSTED_PROXIES.
Caching and headers
The example vhost sets cache lifetimes tuned to Chinaski’s publish rhythm:
- HTML: short cache (revalidate quickly after each build).
- sw.js: no-cache, must-revalidate.
- Fonts: year-long immutable caching.
- Other assets: one-day cache.
- Security headers (X-Frame-Options, nosniff, Referrer-Policy, Permissions-Policy, HSTS 1y), belt-and-braces alongside the headers the app already sets.
Language vhosts
For multilingual sites, duplicate the server block per language: each language’s subdomain or path vhead serves its own output directory (e.g. es.example.com → /var/www/chinaski1/output/es), each with its own /forms/ block pointed at the same upstream.
The deploy-time root sync
deploy/deploy.sh sweeps nginx configs after each deploy: it finds the root directives that point at this instance’s output tree and rewrites them to whatever the current language mode requires (output/ for monolingual sites, output/<default language>/ otherwise), runs nginx -t, and reloads on success, with a warning (no reload) when the config test fails so the error can be fixed by hand. If you are following the example layout, much of nginx upkeep becomes zero-touch on each deploy.