Deployment

One binary, a reverse proxy for TLS, and the flags that matter.

Updated 2 min read

cataract build produces one binary under dist/. Deployment is copying that binary and the directories it reads at run time.

TLS terminates in front

Cataract does not implement TLS. Run it behind a proxy that terminates HTTPS and forwards over the loopback interface:

client --TLS--> proxy :443 --plain--> cataract :8443

The proxy must set X-Forwarded-Proto, because that is how the runtime decides whether to send HSTS, and it must overwrite X-Forwarded-For rather than appending to a client-supplied value.

What to configure

./dist/cataract-wiki \
  --host=127.0.0.1 \
  --port=8443 \
  --staticRoot=/srv/wiki/public \
  --logLevel=info

--staticRoot is the one that surprises people: its built-in value is the path the asset directory had at build time, so a binary moved to another machine needs it set, or needs to be run from the build root.

If your application reads its own data at start-up, give it the same treatment. This wiki declares --contentRoot for exactly that reason.

Environments

An application that hides draft content in production needs to know which it is in. This wiki reads CATARACT_ENV, defaults to production when the variable is unset, and only renders drafts when it is explicitly told it is not in production:

CATARACT_ENV=development cataract dev

Defaulting to the safe answer means a forgotten environment variable hides drafts rather than publishing them.

Shutdown

SIGINT and SIGTERM set a flag; the handler does nothing else. The accept loop polls it, stops accepting, and drains outstanding connections up to drainSeconds before returning. Connections in flight finish their current request; keep-alive is not renewed once shutdown is requested.

That makes a rolling restart behind a proxy uneventful: stop accepting, finish what is in flight, exit.

Operational limits worth setting

SettingWhy
max_concurrencyTurns a connection flood into backpressure instead of unbounded tasks
max_body_bytesCaps the allocation a single request can request
request_timeout_msDisconnects a client that drips bytes to hold a task open
allowed_originsNames the origins allowed to make mutating cross-origin requests