Skip to content

Run a gateway

The gateway accepts hash submissions, persists jobs in SQLite, collects and verifies witness signatures, and exposes attestations and proofs. It is the public-facing component and should be treated as an untrusted network boundary around the witness services.

Build and start

Build from the workspace root:

cargo build --release -p witness-gateway

The gateway's relevant flags are:

Flag Default Purpose
--config network.json Network configuration
--host 127.0.0.1 Listen interface
--port 8080 HTTP listen port
--database gateway.db SQLite path
--admin-ui disabled Enable /admin
--admin-api-key environment Admin credential
--ws-auth-token environment WebSocket credential
--metrics-token environment Metrics credential
--behind-proxy disabled Trust forwarded client IPs

Example with persistent local storage:

target/release/witness-gateway \
  --config /etc/witness/network.json \
  --host 127.0.0.1 \
  --port 8080 \
  --database /var/lib/witness/gateway.db

The gateway speaks plain HTTP. For an internet-exposed service, terminate TLS at a trusted reverse proxy or load balancer, restrict operational routes there, and set WITNESS_BEHIND_PROXY=true (or --behind-proxy) only when the proxy is authoritative for X-Forwarded-For.

Network and witness configuration

network.json defines the network ID, signature scheme, threshold, witness public keys and endpoints, and optional federation/anchor settings. Every witness entry must have a non-empty auth_token; startup aborts otherwise. Treat the file as a secret because the operational form contains bearer tokens. The public verification configuration is a different, secret-free artifact.

Witnesses should be reachable only over trusted/private network paths. Keep their signing endpoints out of the public route unless the deployment has an explicit, reviewed boundary for them.

Public routes and admission

New requests arrive at POST /v1/attestations; clients retrieve jobs and proofs through the documented /v1/... routes. Job creation is asynchronous, and a confirmed result has passed the gateway's threshold verification before being persisted. The gateway has a 30 requests/minute/IP admission limit, but this is only defense in depth. See abuse and rate limiting.

The timestamp is reserved once, at job creation, and is not refreshed on retry. If an outage lasts beyond the witnesses' max_clock_skew window (300 seconds by default), the old reservation cannot be signed when services return. Treat that retry as terminal in effect; do not expect the gateway to create a new timestamp for the same canonical job.

Configure admin, metrics, WebSocket, and federation authentication before exposure. With no WebSocket token, /ws/events is unauthenticated and immediately broadcasts the lowercase digest and reservation timestamp for each new reservation, before confirmation. The hardened outbound client is used for witness, federation, Freebird, and Internet Archive requests; Trillian and DNS use unrestricted reqwest, and Ethereum has URL preflight validation only. Review every configured outbound URL and treat provider-specific SSRF exposure as an operational risk.

Use a persistent local filesystem for SQLite. Do not place the database on a network filesystem or run multiple gateway processes against one database.