Documentation/Run your server
Server setup6 min read

Server usage - scribe-server

On this page
text
scribe-server [logging options] <command> [options]

Logging options on every command: --log-level off|error|warn|info|debug|trace, --log-filter 'warn,scribe_server=info', --log-format text|json, -v, -vv, -q. SCRIBE_LOG holds a filter. Default level info. Precedence: flag, SCRIBE_LOG, [logging].filter in the configuration, default.

Every command except serve and restore accepts either --config FILE or --data-dir DIR to find the data root. All maintenance commands take the same exclusive lock as serve, so they refuse to run beside a live server.

init

sh
scribe-server init --data-dir ./server-data --config-out ./server.toml [--listen tcp://127.0.0.1:7447] [--force]

Creates an empty data root (descriptor, catalog, repos/, lock file) and writes a configuration whose paths are relative to the configuration file. Refuses a non-empty data directory, and refuses to overwrite an existing configuration without --force.

serve

sh
scribe-server serve --config ./server.toml \
  [--data-dir DIR] [--log-dir DIR] [--runtime-dir DIR] [--listen tcp://HOST:PORT] [--allow-non-loopback] \
  [--auth HOST:PORT --auth-namespace NS --auth-ca ca.pem --auth-token-file server.token --tls-cert server.pem --tls-key server-key.pem]

SCRIBE_SERVER_CONFIG may name the configuration file; flags override it, and flag paths are relative to the current directory. Startup opens the descriptor, refuses unknown or newer formats, takes the lock, opens the catalog and every ready repository (discarding interrupted creations), logs every resolved path and limit, binds, writes <runtime-dir>/scribe-server.pid and <runtime-dir>/listen (the bound address, useful with port 0), then accepts connections.

Two modes:

  • Plaintext TCP (no --auth options). Anyone who can reach the port can act as anyone. The server refuses a non-loopback listen address unless --allow-non-loopback or allow_non_loopback = true is set, and logs server.plaintext_exposed when it is.
  • TLS with shared authentication. All six auth settings are required together, and the data root must have been prepared with auth-init. The socket then serves TLS 1.3 only, listen reports tls://host:port, and every request is authorized per repository. Setup is in auth.md.

Stop with SIGINT, SIGTERM, or touch <runtime-dir>/shutdown-request. Admission stops and idle connections close. In-flight requests get up to drain_timeout_secs for network I/O; after that, sockets are interrupted and started storage jobs finish before exit. A stalled disk can extend shutdown. A forced kill is safe: acknowledged work is durable and the next start cleans staging and unreferenced pack tails.

Configuration file

toml
[server]
data_dir = "server-data"        # relative to this file
log_dir = "logs"                # omit for stderr
runtime_dir = "run"             # default <data_dir>/run
listen = "tcp://127.0.0.1:7447"
allow_non_loopback = false      # plaintext mode only; read docs/operations.md first

[logging]
filter = "info"                 # or "warn,scribe_server=info,scribe_objects=debug"
format = "text"                 # or "json" (newline-delimited)
keep_files = 14                 # daily files retained in log_dir

[limits]
max_connections = 256
storage_workers = 16          # blocking mutations/transfers; >=2
query_workers = 4             # reserved read queries; >0; total workers <=1024
transfer_workers = 8          # >0 and <storage_workers; reserves control capacity
staging_budget_mib = 512        # bytes admitted into quarantine across all connections
inactivity_timeout_secs = 300
handshake_timeout_secs = 10
drain_timeout_secs = 30
small_object_threshold = 262144 # envelopes at or below this go to packs
pack_seal_mib = 256

[auth]                          # optional; all six keys together
endpoint = "127.0.0.1:7443"
namespace = "studio"
ca = "ca.pem"
token_file = "storage-a.token"
tls_cert = "server.pem"
tls_key = "server-key.pem"

certs

sh
scribe-server certs init-ca --out ./studio-ca [--days 3650]
scribe-server certs issue --ca ./studio-ca --out ./storage-tls --dns vcs.example [--dns ...] [--ip ...] [--days 365]

Creates a private CA, or issues a server certificate and key signed by it, using an OpenSSL 3 executable (--openssl PATH to choose one). Output directories must be new. scribe-auth certs is the same tool. Lifetimes, renewal, and what to keep offline are in auth.md.

auth-init, users, permissions

sh
scribe-server auth-init --data-dir ./server-data --namespace studio
scribe-server users       --auth HOST:PORT --auth-ca ca.pem --admin-token-file admin.token  add|list|disable|enable ...
scribe-server permissions --auth HOST:PORT --auth-ca ca.pem --admin-token-file admin.token  set|revoke|list ...

auth-init runs offline once per data root: it marks the root with a required feature so older binaries refuse it, and creates auth-state.redb, which records workspace and operation ownership. A marked root can no longer be served in plaintext mode.

users and permissions are conveniences that talk to the auth service with an administrator token; they are the same commands as scribe-auth users and scribe-auth grants. The storage server's own service token cannot administer users.

Maintenance

sh
scribe-server doctor --data-dir DIR [--quick] [--threads N] [--repo NAME] [--json]   # alias: scan
scribe-server usage  --data-dir DIR [--repo NAME] [--json]                            # alias: df
scribe-server verify --data-dir DIR [--full] [--repo NAME] [--json]
scribe-server backup --data-dir DIR --to EMPTY_DIR
scribe-server restore --from BACKUP_DIR --to EMPTY_DIR
scribe-server export-metadata --data-dir DIR --repo NAME --to FILE.scmx
scribe-server import-metadata --data-dir DIR --repo NAME --from FILE.scmx
scribe-server migrate --data-dir DIR [--dry-run] [--branches | --rollback]
  • doctor is the routine health check. Read-only, exit 0 healthy, 1 problems found, 2 could not run (for example the root is in use). By default it re-hashes every object across all cores; --quick checks headers and lengths and hashes only manifests, change sets, and commits. It also checks the commit chain, operation records, every live path's manifest and chunks, every historical manifest, both collision indexes, change_paths against history, and every pack end to end, and reports interrupted-publication leftovers as warnings. Nothing is ever modified. Run it after any unclean shutdown and before every backup.
  • usage is the inventory: one line per repository with head change, live paths, branches, indexed objects, loose/packed/metadata sizes, total size, and last commit; then the data-root total and the filesystem's free space. It reads only directory metadata and table lengths, so it finishes in milliseconds. Interrupted creations, missing or unreadable repositories, directories the catalog does not know, and staging leftovers get their own line. --json adds history rows, workspaces, locks, operations, and pack counts.
  • verify is the single-threaded structural check, kept for scripts; --full re-hashes every object. doctor supersedes it for routine use.
  • backup copies every durable file with a verified checksum manifest into an empty directory. restore verifies the backup, copies it, assigns new incarnations, and runs structural verification; clients reconcile fully on their next sync.
  • export-metadata and import-metadata move one repository's tables through an engine-neutral checksummed container; import requires the repository directory to have its objects but no metadata.redb.
  • migrate upgrades older repository schemas generation by generation with checkpoints. --branches converts schema 1 or 2 repositories to schema 3, which serving requires. --rollback returns a schema-0-to-1 migration to its retained previous generation only if nothing was accepted since. --dry-run reports without writing.

Procedures and file layouts: migration-backup-restore.md.

Operating notes

  • Keep data, logs, and runtime directories separate; only the data directory needs backup, and it includes auth-state.redb when auth is enabled.
  • Run one server per data root; a second process fails on the lock.
  • Watch submit.committed, submit.rejected, objects.published, and server.stopped (which reports dropped diagnostic events) in the logs. Logs are never needed for recovery.
  • Test builds only: SCRIBE_FAULT=<point>=crash|fail arms fault injection when the binary was built with --features fault-injection.

For TOML-based local cluster startup, pepper provisioning, and idempotent user bootstrap, see the cluster guide.

An optional scribe-gateway can provide one client endpoint for several existing storage instances. Standalone operation remains supported.

Source docs/server-usage.mdSnapshot 93d02b17