Operations: Hetzner + Cloudflare
Status: staging-operated, fixture only. Live staging on
46.225.87.105(gestalt-evo) bound to127.0.0.1:3011with SurrealDB-remote storage. No public Cloudflare DNS/TLS/access mutation has been performed. Production admission is disabled. Customer data is forbidden. Authoritative source: thedeploy/hetzner-cloudflare/README.mdlog.
Co-tenancy boundary
Section titled “Co-tenancy boundary”The Hetzner host runs sibling Gestalt services from the upstream
project — gestalt, gestalt-server, gestalt-images — out of
/opt/gestalt, /opt/gestalt-evo, and /opt/gestalt-evo-src. The
Aion fixture deploy must never touch any of those.
The Aion deploy is scoped strictly to:
service: gestalt-fixturepath: /opt/gestalt-fixturebind: 127.0.0.1:3011Any operation that reaches outside that scope is a violation. Do not
invoke the sibling repo’s deploy scripts. Do not systemctl the
sibling services. Do not rm outside /opt/gestalt-fixture.
This rule exists because the sibling project owns the host’s user-
facing presence. A wipe of /opt/gestalt would destroy a live system
the Aion runtime has no business managing.
What the staging fixture has proved
Section titled “What the staging fixture has proved”Per deploy/hetzner-cloudflare/README.md:
host: 46.225.87.105 (gestalt-evo)service: gestalt-fixture (active, enabled)binary: gestalt-cloud --fixture --no-root-key --storage-profile surreal-remotebind: 127.0.0.1:3011remote dir: /opt/gestalt-fixturestorage: SurrealDB remote profile at 127.0.0.1:8000 (gestalt_aion_cloud / staging)runtime snapshot: cloud_runtime_snapshot:fixture_hosted_operatordurable commits: cloud_atom_commit (signed atom rows with signer/storage provenance)root signing: disabled; hosted operator rehydrates from durable grant atomremote smoke: /health /ready /version /metrics /v1/membrane/contract → 200 /v1/auth/session/exchange, /v1/tenant/self, /v1/authority/resolve-context, /v1/shop/prepare, /v1/shop/commit, /v1/commits/recent, /v1/receipts/verify, /v1/proofs/request → 200 signed commit response includes hosted-operator signer provenance and surreal-remote storage profile before and after service restart; recent commit journal keeps the pre-restart atom after restart /v1/raw-db → 404non-wipe smoke: GESTALT_SKIP_WIPE=1 passed against the running remote statepublic edge: no Cloudflare DNS/TLS/access mutation performedproduction admission: disabledcustomer data: forbiddenCross-compile from macOS
Section titled “Cross-compile from macOS”The Hetzner host is Linux x86_64; local dev is macOS. The deploy
defaults to target/release/gestalt, which on macOS produces a
Mach-O binary that fails on the server with Exec format error.
Cross-compile a static musl binary:
# one-timerustup target add x86_64-unknown-linux-muslbrew install zigcargo install cargo-zigbuild
# buildcargo zigbuild --release --target x86_64-unknown-linux-musl -p gestalt-cloudThen deploy with GESTALT_BINARY pointing at the musl binary:
GESTALT_LIVE_HETZNER_COMMIT=YES_DEPLOY_GESTALT_AION_FIXTURE_TO_HETZNER \GESTALT_DRY_RUN=0 \GESTALT_STORAGE_PROFILE=surreal-remote \GESTALT_NO_ROOT_KEY=1 \GESTALT_SURREAL_REMOTE_ENDPOINT=ws://127.0.0.1:8000 \GESTALT_SURREAL_REMOTE_NAMESPACE=gestalt_aion_cloud \GESTALT_SURREAL_REMOTE_DATABASE=staging \GESTALT_SURREAL_REMOTE_TLS_REQUIRED=false \GESTALT_SURREAL_REMOTE_USERNAME=<root-user> \GESTALT_SURREAL_REMOTE_PASSWORD=<root-password> \GESTALT_BINARY="$PWD/target/x86_64-unknown-linux-musl/release/gestalt-cloud" \ ./deploy/hetzner-cloudflare/commit-hetzner-fixture.shGESTALT_NO_ROOT_KEY=1 is correct only when the staged world
has a durable hosted-operator grant. Otherwise signed fixture
commits use the explicit in-process root signer boundary.
Deploy variants
Section titled “Deploy variants”Wipe + redeploy
Section titled “Wipe + redeploy”The default commit-hetzner-fixture.sh invocation above wipes the
remote /opt/gestalt-fixture directory before deploying. Use this
when you’ve shipped new binary or configuration.
Smoke without wiping
Section titled “Smoke without wiping”GESTALT_SKIP_WIPE=1 ./deploy/hetzner-cloudflare/commit-hetzner-fixture.shThis path checks the live service, commits through the hosted
delegate, verifies /v1/commits/recent, restarts the service, and
verifies the pre-restart atom is still present. Use this to prove
durability without disturbing state.
Dry-run staging wipe
Section titled “Dry-run staging wipe”GESTALT_DEPLOY_TARGET=staging GESTALT_HOST=staging.example.invalid \ GESTALT_ALLOW_WIPE=YES_WIPE_DISPOSABLE_STAGING \ ./deploy/hetzner-cloudflare/wipe-staging.shDefaults are dry-run. Real destructive staging wipe requires:
GESTALT_DEPLOY_TARGET=stagingGESTALT_HOST=<host>GESTALT_ALLOW_WIPE=YES_WIPE_DISPOSABLE_STAGINGGESTALT_DRY_RUN=0Remote trials
Section titled “Remote trials”All M-trial scripts can target the remote staging through an SSH localhost tunnel. The standard pattern:
# in one terminal, open the tunnelssh -i ~/.ssh/gestalt_deploy -L 13011:127.0.0.1:3011 root@46.225.87.105
# in another terminal, run trials against http://127.0.0.1:13011GESTALT_BASE_URL=http://127.0.0.1:13011 \GESTALT_TRIAL_OUT_DIR=target/gestalt-m12-trial-remote \ deploy/hetzner-cloudflare/m12-worldline-runtime-trial.shThe full set of remote-tested M-trials is recorded in
deploy/hetzner-cloudflare/README.md:
M6, M7, M8, M9, M10/M11, M12, M13, M14.
Edge / Cloudflare
Section titled “Edge / Cloudflare”There is no Cloudflare DNS/TLS/access mutation today. The fixture
service binds to 127.0.0.1:3011 only. Public edge access is gated;
see workflow 018
finding 5.
When a public edge lands, it will:
- be a confirmed staging hostname (e.g.
staging.gestalt.example), - sit behind explicit Cloudflare Access or Caddy reverse proxy,
- block raw DB paths (
/v1/raw-db→ 404 already), - log remote smoke evidence with date and hostname.
Operating constraints
Section titled “Operating constraints”- No customer data. Real customer information must not enter the fixture deploy.
- No production legal claims. Receipts emitted by the staging fixture must not be presented as real proof to any third party.
- Don’t restart unless safe. Some trials assume the in-process hosted operator state has been seeded by a prior trial. Restart patterns are documented per trial.
- Don’t enable runtime overlay enforcement on remote. M13
lifecycle mutation routes (session revoke, key rotate) must run
with
enforce_runtime_overlay: falseon remote staging so the no-wipe smoke continues to work afterward.
Where to read next
Section titled “Where to read next”- Local fixture
- Observability
deploy/hetzner-cloudflare/README.md— operator log- Memory note: Hetzner co-tenancy with upstream gestalt services
(referenced in
MEMORY.mdat the project root for AI sessions)