Use this after the tutorials or the manual setup guides, before opening access to a team.
1. Choose the topology
| Need | Deployment |
|---|---|
| One shared project service | Auth + one storage instance |
| Several storage instances behind one address | Auth + storage instances + gateway |
| Manage services on one host | Add ctl, or manage each service with the host's service manager (by hand) |
Choose stable DNS names and ports. Use matching client and service revisions.
2. Set ownership and storage paths
- Use unprivileged service accounts with access only to their own resources.
- Give each instance distinct data and runtime roots; keep logs separate.
- Keep secrets (credential files, TLS keys, the password pepper, the auth revision witness) outside data roots and readable only by their consumers. On Unix, Scribe refuses a credential file, device key, pepper, or witness that grants any access to group or other accounts, or whose directory they can write. On Windows it refuses one whose access list allows any account other than its owner, SYSTEM and Administrators more than reading its attributes, or whose directory lets another account delete its entries.
- Keep runtime directories private: services refuse one that group or other accounts can write.
- Keep the CA signing key offline. Clients receive public trust material and their own device keys and certificates, never service keys or administrator credentials.
Ctl runs its children under its account. For separate service identities, supervise each service independently.
Check storage durability assumptions and capacity needs, including retained history, uploads, backups, and client recovery files.
3. Expose only the required connections
| Connection | Purpose |
|---|---|
| Clients → storage or gateway | Repository operations over mutual TLS |
| Clients → auth | Login, logout, and access-certificate renewal over TLS |
| Storage → auth | Identity and permission checks with the server's credential |
| Gateway → storage | Requests and inventory over mutual TLS |
| Gateway → auth | Access CAs and access certificates with the gateway's credential |
| Operator tools → auth | Administration with an administrator credential |
Every Scribe endpoint requires TLS 1.3 with the hybrid post-quantum key
exchange X25519MLKEM768. Load balancers and proxies in these paths must pass
TLS through: one that terminates TLS cannot present the client's certificate
and usually cannot offer that key exchange. Restrict listeners with host/network rules. Behind a gateway, allow backend
access only where needed by the gateway and operators. Keep runtime files private.
Use certificates for real connection names and establish verified trust first. Review roles and schedule credential renewal.
4. Provision once, then configure automatic startup
Complete initialization and a client round trip first. Then configure the host service manager to run ctl in the foreground, using your absolute paths:
/opt/scribe/bin/scribe-ctl --config /etc/scribe/cluster.toml --cluster production up --foregroundA service definition meets these requirements:
| Setting | Requirement |
|---|---|
| Executable/configuration | Absolute paths; matching service binaries beside ctl or configured explicitly |
| Account | The prepared service account, with access to required files |
| Startup | After required storage mounts and network availability |
| Readiness | Check service state and, for a gateway, fresh backend inventory |
| Shutdown | Deliver graceful termination and allow started durable work to finish; avoid a short forced-kill deadline |
| Restart | An explicit operator-selected policy; investigate repeated failures before retrying indefinitely |
Ctl daemon mode alone does not start at boot. Give each process one supervisor. See lifecycle behavior.
systemd
For a native ctl cluster, one unit runs the supervisor. SIGTERM makes ctl
drain the services in order (gateway, storage, auth); KillMode=mixed sends
it to ctl alone, so the services are not signalled all at once, and the long
stop timeout lets started durable work finish:
# /etc/systemd/system/scribe.service
[Unit]
Description=Scribe cluster
Wants=network-online.target
After=network-online.target local-fs.target
[Service]
Type=simple
User=scribe
Group=scribe
UMask=0077
ExecStart=/opt/scribe/bin/scribe-ctl --config /etc/scribe/cluster.toml --cluster production up --foreground
KillSignal=SIGTERM
KillMode=mixed
TimeoutStopSec=15min
Restart=on-failure
RestartSec=30s
[Install]
WantedBy=multi-user.targetWithout ctl (bare metal), give each service a unit of its own and order them: auth → storage → gateway at start, and systemd stops them in reverse. For storage A of the bare-metal layout:
# /etc/systemd/system/scribe-storage-a.service
[Unit]
Description=Scribe storage A
Wants=network-online.target scribe-auth.service
After=network-online.target scribe-auth.service
[Service]
Type=simple
User=scribe
Group=scribe
UMask=0077
WorkingDirectory=/srv/scribe
ExecStart=/opt/scribe/bin/scribe-server serve --config /srv/scribe/storage-a.toml --runtime-dir /srv/scribe/run/storage-a --log-dir /srv/scribe/logs/storage-a
KillSignal=SIGTERM
TimeoutStopSec=15min
Restart=on-failure
RestartSec=30s
[Install]
WantedBy=multi-user.targetscribe-auth.service runs the scribe-auth serve command of stage
2, and
scribe-gateway.service runs scribe-gateway --config /srv/scribe/scribe-gateway.toml serve --runtime-dir /srv/scribe/run/gateway
with After= and Wants= naming every storage unit. Enable them with
systemctl enable --now scribe-auth scribe-storage-a scribe-gateway. Every
service treats SIGTERM as a graceful stop (shutdown).
Windows
scribe-server, scribe-auth, scribe-gateway and scribe-ctl have no
Windows service entry (only scribe-runner
does), so sc.exe cannot run them directly, and Scribe documents no service
wrapper for them. Run them in a signed-in session or through a wrapper of
your choice, and stop each one gracefully with its shutdown-request file
rather than by killing the process.
Docker
A Compose project, one you wrote (Docker
Compose) or a Docker-runtime
ctl cluster, comes back after a reboot through restart: unless-stopped once
the Docker engine starts at boot (systemctl enable docker); do not also run
scribe-ctl up --foreground from a service manager, which would stop the
project whenever it stops (up). A project
stopped with docker compose stop or scribe-ctl down stays stopped.
5. Assign monitoring and backup responsibilities
| Area | Operational check |
|---|---|
| Availability | Service exits, failed logins, backend health, stale inventory |
| Capacity | Free disk space and growth of history, logs, and recovery files |
| Credentials | Server TLS certificate and machine credential expiries; protected access to the original pepper and revision witness |
| Logs | Set service retention; plan separate retention for ctl/supervisor logs, which ctl does not rotate |
| Integrity | Schedule offline doctor checks, particularly before backup and after unclean shutdown |
Back up everything what to back up
lists: each storage root, the stopped auth database, the stopped gateway
ledger and, with the web interface, its database, object store and secrets. Keep the matching pepper in a separate
protected backup, and keep the revision witness out of the auth data backup.
Outside an upgrade rollback,
restore auth only with scribe-auth restore
(auth backup and restore):
storage servers refuse an auth copied back from an older backup. Preserve
configuration, credentials/keys, and ctl provisioning state.
Use independent backup storage and rehearse recovery. Schedule maintenance windows for offline checks and copies; rotate ctl log files during a planned stop.
6. Verify before opening access
- A writer can log in, create a working copy, submit, and sync through the intended endpoint.
- A reader can sync but cannot submit; an ungranted user cannot discover the repository.
- A graceful stop/start preserves repository IDs, history, and access.
- Gateway inventory is healthy and existing repositories keep their assignments.
- Backups, expiry monitoring, log retention, and an operator owner are in place.
Use troubleshooting for failed checks.