Running a host

One unprivileged process behind your reverse proxy, serving many sites by domain.

The shape of a deployment

            public traffic
                 |
        reverse proxy  (owns public TLS, catch-all vhost)
                 |  HTTP, original authority forwarded
                 v
        crisptastic host   --bind 127.0.0.1:6174
          |         |
   public plane   management plane (mTLS)  --management-bind 127.0.0.1:7443
                    ^
                    |  crisptastic notify / deploy --peer
              your deploy machine

The public application listener is never exposed to the internet directly. The proxy owns public TLS and should use a catch-all configuration so adding a domain never needs a proxy edit. Only the management plane is reachable from outside the box, and only over mutual TLS.

Operator setup

  1. A dedicated, unprivileged OS account. The host refuses to run as UID 0.
  2. One binary. No language runtime, no process manager, no per-site unit files.
  3. An absolute host root owned by that account and not group/world-writable. It holds deployment directories, the capsule store and a lock file.
  4. The host's identity key (--identity, age X25519) and the trusted deployment signer (--trusted-signer, release.pub).
  5. Management TLS (--management-cert, --management-key, --management-client-ca) on a listener separate from the public one.
  6. Proxy trust matching your reverse proxy.
crisptastic host \
  --identity /etc/crisptastic/server.agekey \
  --trusted-signer /etc/crisptastic/release.pub \
  --host-root /var/lib/crisptastic \
  --store-dir /var/lib/crisptastic/capsule-store \
  --bind 127.0.0.1:6174 \
  --management-bind 0.0.0.0:7443 \
  --management-cert /etc/crisptastic/mgmt.crt \
  --management-key  /etc/crisptastic/mgmt.key \
  --management-client-ca /etc/crisptastic/deploy-ca.crt \
  --proxy-mode x-forwarded --trusted-cidr 10.0.0.0/8 --trusted-hops 1

--deployments-root defaults to <host-root>/deployments.

The production process baseline

crisptastic host selects the production profile automatically unless you pass --development-process-profile. Before it reads a Capsule, starts a runtime or opens a listener, it runs an ordered, fail-closed preflight:

  • refuses effective UID 0; sets umask 077;
  • requires every configured path to be absolute;
  • creates and canonicalizes the host root; requires correct ownership and permissions;
  • requires the deployments root to be a strict child of the host root, with no symlink escape;
  • rejects overlapping public / management / Fabric listener addresses;
  • closes every inherited file descriptor numbered 3 or higher;
  • takes an exclusive lock on <host-root>/.crisptastic-host.lock;
  • applies the dump-protection and locked-secret-memory checks (--locked-secret-memory-bytes, default 64 MiB).

Any failure aborts startup before a socket is opened.

Proxy trust

--proxy-mode none          # ignore all forwarding headers (default, loopback)
--proxy-mode forwarded     # RFC 7239 Forwarded, trusted peers only
--proxy-mode x-forwarded   # X-Forwarded-* , trusted peers only
--trusted-cidr <CIDR>      # who is allowed to set those headers
--trusted-hops <N>         # exact hop to read (default 1)

Untrusted peers can never influence which site serves a request. In production, tenant routing additionally requires complete trusted-proxy metadata with public scheme https; the proxy-to-host hop itself stays plain HTTP.

Activation, health, rollback

  • A staged deployment is validated (digest, length, signature, schema, domains, secret-name set) and health-checked before any domain points at it.
  • Activation is atomic: a request runs entirely against the old or the new deployment, never a mix.
  • A failed deployment never disturbs the active one.
  • Deployment history is retained; rollback is activating a previous digest.
  • Status and logs are reported without exposing secret values.

Secrets and restarts

Secret values live only in process memory. They are never written to the deployments root, logs, telemetry, the capsule store or swap. Restarting a single-node host loses volatile secret state — the site is not routable again until its Capsule is re-activated (which carries the encrypted secrets) or a Fabric supplies them from another node.

Upgrades

Replace the binary and restart the process. Capsules are versioned artifacts; a host rejects a schema it does not support rather than guessing. Run the new binary against a staging host first.

What a host does not do

No arbitrary native code or language runtimes, no container orchestration, no DNS management, no public TLS termination, no general secret store, no build-time shell hooks. It is deliberately one job: run declared Capsules safely.