Built with Chinaski

systemd Services

Chinaski runs as standard systemd services on Linux. Because they’re template units, one set of files runs any number of sites on the same host. This page covers the three shipped unit families: the CMS itself, the daily backup, the optional AI-assistant adapter, and how to work with them day to day.

The main service: chinaski@<instance>

Each CMS instance runs under its own systemd unit. Enable and start a new one with its instance name:

systemctl enable --now chinaski@1

(2, prod, staging, anything alphanumeric, work the same way.) What the unit takes care of:

  • Runs the CMS as a dedicated, non-login chinaski user from that instance’s directory.
  • Sets the database and output paths automatically from the instance name; you normally don’t configure those.
  • Reads a per-instance env file, /etc/chinaski<instance>/env, that you create before starting. It must contain CHINASKI_SECRET and LISTEN_URL (bind to loopback, e.g. http://127.0.0.1:3001, when a reverse proxy fronts the site; the example file’s comments explain why that matters).
  • Restarts on failure with a short delay, limited to five tries per minute so a broken config can’t loop forever.
  • Stops with a drained grace period (330 s) for in-flight requests; note a running build’s own wall-clock limit is 30 minutes, so a build mid-shutdown is cancelled rather than waited out; the published site is unaffected either way.
  • Runs boxed in: read-only filesystem except its own directory, no new privileges, private /tmp, memory capped at 1 GB, CPU at 200%.

Every instance is the same unit with a different name, and each has its own database, output, and environment: see Instances for the whole model.

Events and logs

Everything lands in journald, tagged chinaski-<instance>:

journalctl -u chinaski@<instance>       # follow with -f
systemctl status chinaski@<instance>

If the service fails to start, the journal shows why; the installer points there automatically when a first start fails.

The daily backup: chinaski-backup@

Each instance gets a matching oneshot unit and a timer:

  • The service snapshots the instance’s database and mirrors its media, running with a read-only view of the site directory and write access only to the backup directory.
  • The timer fires daily at 03:17 local time (deliberately odd minute so multiple instances on one host don’t back up at the same instant), with a small random delay, and catches up if the host was powered off when it was due.
  • Check it’s registered with systemctl list-timers chinaski-backup@<instance>.timer; after editing a schedule, do check, because systemd skips silently on a typo’d calendar string.
  • Bound to run under 10 minutes; even a 1 GB database finishes in well under a minute on local disk.

The optional adapter: chinaski-mcp@

If you use AI assistants against a site’s API, that adapter has its own per-instance unit:

  • Ordered after the CMS unit of the same instance (so the CMS exists first).
  • Reads its API URL and API key from /etc/chinaski<instance>/mcp-env (also permission-locked).
  • Smaller resource envelope than the CMS (half the memory and CPU), with the same sandbox hardening and auto-restart.

Enable one with systemctl enable --now chinaski-mcp@<instance> after the matching CMS instance exists.

Day-to-day commands

systemctl status chinaski@<instance>     # is it running?
systemctl restart chinaski@<instance>    # after manual file changes (e.g. admin assets)
journalctl -u chinaski@<instance> -f     # follow the log
systemctl list-timers 'chinaski-backup@*'   # confirm every backup schedule

Deploys don’t change the unit: the deploy script handles the restart after a verified build. If you later adopt the Manager, it drives these same units by name (start/stop/restart), so instances can move under its control without being re-installed.

Safeguards, summarized

  • Auto-restart on failure (with a backoff cap against crash loops).
  • Graceful stops: requests and builds drain before the process exits.
  • Memory/CPU ceilings per unit, tightened so a runaway builder can’t starve the host.
  • One sandbox per instance: no instance can read or write another’s files.
  • Journald captures everything: no separate logging daemon to manage.
Read this site in