Self-hosting Clank Deploy

Clank Deploy is one Node control plane process plus one supervised process or container per active project.

5 min read1,051 wordsClank 0.7.0

Clank Deploy is one Node control-plane process plus one supervised process or container per active project.

Requirements

  • Node 22.16+;
  • persistent local storage;
  • HTTPS proxy outside loopback;
  • Docker for mutually untrusted deployers;
  • external master key and off-host backups for production.

Environment

VariableDefaultPurpose
PORT4200Control-plane port
HOST127.0.0.1Listener address
CLANK_PLATFORM_URLloopback URLExact public console origin
CLANK_PLATFORM_DATA.clank-platformPersistent root
CLANK_PLATFORM_MASTER_KEYgenerated fileBase64/base64url 32-byte key
CLANK_SIGNUPbootstrapbootstrap, public, or disabled
CLANK_RUNNERprocessprocess or docker
CLANK_DOCKER_IMAGENode imagePin by digest in production
CLANK_APP_MEMORY512mContainer memory
CLANK_APP_CPUS1Container CPUs
CLANK_APP_PIDS128Container PID limit
CLANK_APP_PORT_START4300Port-range start
CLANK_APP_PORT_END4999Port-range end
CLANK_APP_URL_TEMPLATEloopback with {port}Public app URL pattern
CLANK_MAX_ARTIFACT_BYTES104857600Artifact limit
CLANK_INGRESSinferred from base domainEnable managed exact-host ingress
CLANK_INGRESS_BASE_DOMAINnoneBuilt-in slug.<base> site namespace
CLANK_CUSTOM_DOMAIN_TARGETbase domainCNAME target displayed to customers
CLANK_CUSTOM_DOMAIN_ADDRESSESnoneComma-separated edge A/AAAA values accepted for apex routing
CLANK_TLS_ASK_TOKENnoneSecret for the private Caddy certificate permission check
CLANK_INGRESS_MAX_BODY_BYTES26214400Per-request managed-ingress body limit
CLANK_DOMAIN_RECHECK_INTERVAL_MS300000Background custom-domain routing interval; 0 disables it
CLANK_DOMAIN_RECHECK_BATCH_SIZE25Maximum domains durably claimed by one routing pass
CLANK_DOMAIN_RECHECK_TIMEOUT_MS10000Per-domain DNS lookup deadline
CLANK_BACKUP_INTERVAL_MS86400000Verified encrypted-backup cadence; 0 disables automatic runs
CLANK_BACKUP_BATCH_SIZE5Maximum projects durably claimed by one backup pass
CLANK_BACKUP_MAX_COUNT30Maximum retained backups per project
CLANK_BACKUP_MAX_AGE_MS7776000000Maximum retained backup age
CLANK_BACKUP_MAX_DATABASE_BYTES10737418240Maximum source database size accepted by backup creation
CLANK_MAX_ORGANIZATIONS_PER_ACCOUNT5Transactionally enforced account organization limit
CLANK_MAX_PROJECTS_PER_ACCOUNT10Transactionally enforced account-wide site limit
CLANK_MAX_PROJECTS_PER_ORGANIZATION10Transactionally enforced site limit
CLANK_MAX_DOMAINS_PER_PROJECT5Transactionally enforced custom-domain limit
CLANK_METRICS_RETENTION_DAYS30Ingress metric retention, 1–365 days
CLANK_MAX_RELEASES_PER_PROJECT50Retained runtime-artifact count per site
CLANK_MAX_RELEASE_STORAGE_BYTES_PER_PROJECT21474836480Uncompressed release files plus pre-deploy snapshots retained per site
CLANK_ALLOW_UNSAFE_MIGRATIONS0Operator approval for unrestricted SQL
ALLOWED_HOSTSloopbackExact host allowlist
TRUST_PROXY0Trust forwarded client/protocol

bootstrap permits one initial account and then closes ordinary registration. Its SQLite claim is shared by control-plane processes using the same data directory. disabled blocks ordinary registration immediately. In both modes, an owner/admin-issued invitation can still create only its bound email account through Use invitation; revoke outstanding invitations before disabling all intended onboarding.

Production start

sh
export CLANK_PLATFORM_URL=https://deploy.example.com
export CLANK_PLATFORM_DATA=/var/lib/clank
export CLANK_PLATFORM_MASTER_KEY="$(your-secret-manager read clank-master-key)"
export CLANK_RUNNER=docker
export CLANK_DOCKER_IMAGE=node@sha256:<approved-digest>
export CLANK_APP_URL_TEMPLATE='https://{slug}.apps.example.com'
export CLANK_INGRESS=1
export CLANK_INGRESS_BASE_DOMAIN=apps.example.com
export CLANK_CUSTOM_DOMAIN_TARGET=edge.apps.example.com
export CLANK_CUSTOM_DOMAIN_ADDRESSES=192.0.2.10,2001:db8::10
export CLANK_TLS_ASK_TOKEN="$(your-secret-manager read clank-tls-ask-token)"
export HOST=127.0.0.1
export PORT=4200
export ALLOWED_HOSTS=deploy.example.com,127.0.0.1,localhost
export TRUST_PROXY=1

clank-platform

Proxy the console and application hosts to port 4200. Clank performs exact-host project routing; the edge performs public DNS, TLS, WAF/rate limiting, and DDoS controls. The recommended Caddy On-Demand TLS configuration and DNS records are in Deployment dashboard, quotas, and domains.

Use /livez only to determine whether the process can answer HTTP. Use /healthz or /readyz for control-host readiness. Hosted load balancers that send a different Host header should use /_clank/readyz, which is evaluated before application-host ingress. These readiness endpoints execute a control-database probe and return 503 when the platform cannot safely accept work. SIGINT and SIGTERM stop new HTTP work, drain an active scheduled backup, close supervised applications and platform storage, and fail the process if shutdown cannot finish within 30 seconds.

Tailscale

sh
CLANK_PLATFORM_URL=https://host.tailnet-name.ts.net:8447 \
HOST=127.0.0.1 PORT=4200 TRUST_PROXY=1 \
ALLOWED_HOSTS=host.tailnet-name.ts.net,localhost,127.0.0.1 \
clank-platform

tailscale serve --https=8447 http://127.0.0.1:4200

Expose app ports separately or place a wildcard-capable proxy in front.

Railway

The checked-in production image, health/restart policy, persistent-volume topology, DNS setup, and operator runbook are in Railway production deployment.

Storage

text
control.sqlite
master.key
projects/<id>/
  data/app.sqlite
  releases/<release-id>/
  backups/<release-id>.sqlite
  recovery/<backup-id>/
    database.enc
    manifest.json

Use a local filesystem with correct SQLite locking/rename semantics. The platform sets umask 0077.

Clank automatically creates authenticated, AES-256-GCM encrypted recovery points under recovery/. Durable control-database claims prevent duplicate scheduled work when multiple control-plane processes share the store. Release count and byte ceilings separately bound retained extracted runtime files and pre-deploy rollback snapshots. Back up the control database, completed recovery directories, recoverable artifacts/source, and master key through separate paths. Pre-release snapshots remain rollback material, not part of the recovery retention policy. See Backup and disaster recovery.

Permanent site deletion removes the complete matching projects/<id>/ tree after symlink-safe validation, then removes its control rows and revokes project tokens. It does not reach copied/off-host backups, external databases, artifact mirrors, or Caddy certificate storage. Include those systems in tenant-retention and erasure runbooks, and preserve the control database if deletion audit history must remain available.

Audit rows live in control.sqlite, retain organization attribution after project removal, and upgrade in place from earlier schemas. The public API does not mutate them, but SQLite administrators can. Export them to a separate append-only audit system when control-plane operator tampering or longer retention is in scope.

Authentication and CLI device-start rate-limit windows also live in control.sqlite. Their client/account keys are HMAC pseudonyms under the platform master key, expire automatically, and remain effective when requests move between control-plane processes or the process restarts. The table is bounded, so keep the console behind production edge rate limiting and DDoS controls.

Upgrades

  1. Back up data and key.
  2. Stop new deploys and the platform.
  3. Install and verify the new Clank build.
  4. Start the selected active supervisor/worker topology.
  5. Verify browser login, CLI login, organization and scoped-token access, project status, ingress/domain state, app health, test deploy, backup verification, rollback, and a disposable-site deletion.

Durable distributed locks, authenticated nodes, desired generations, operations/fencing, wildcard base-domain routing, ownership and routing verification, Caddy certificate eligibility, ingress metrics, enforced account/organization/site/domain limits, organization RBAC, scheduled encrypted backups, and external database drivers are implemented. The included child-process supervisor remains single-leader and artifacts/backups are local by default; a hosted multi-region service still needs leader/remote-runner integration, external object storage, globally transactional control storage, shared metric storage, and a multi-region edge service.