AiMANAC Backend Setup — paste this page into your AI assistant.
You probably landed here because you asked Claude or ChatGPT to help you deploy
your AiMANAC backend, and it told you to read this page. It's right.
This page exists so your AI assistant doesn't guess — every value it needs to write
your nginx /
docker-compose.yml lives below,
machine-readable and dated.
What to do: copy the prompt in panel 01,
paste it into your AI assistant along with this page's URL, and follow what it gives you.
That's it.
Audience · HumanAudience · AI Assistant
Audience · Search Indexer
01
Copy This Prompt
Primary · ~10 lines
Copy the text below and paste it into Claude, ChatGPT, or whichever AI you're using.
It tells the model where to find ground-truth values, what to generate, and what to refuse to guess.
PROMPT · plain text
I'm deploying the AiMANAC self-hosted backend on my own server. Help me write
the configs and walk me through it step by step.
Canonical setup data lives at:
https://aimanac.llmtech.net/setup/llm/
Before you answer:
1. Fetch that page (or read the JSON inside its <script id="aimanac-deploy-spec"> tag).
2. Use ONLY the values from that spec — image tag, internal port, env vars, required services,
build commands (spec key "build"), port mapping (spec key "port_mapping").
3. If the spec's "released_at" is older than its "freshness_window_days", stop and tell me.
4. Do NOT recall AiMANAC values from your training data. They will be wrong.
5. Read the "anti_hallucination" array on that page and treat each item as a hard constraint.
6. Confirm the Docker daemon is running BEFORE producing any docker build command
(spec key "prereq.docker_daemon").
My environment:
- OS: {{ubuntu 24.04 / debian 12 / macos / other}}
- Public host: {{my-aimanac.example.com}}
- TLS: {{letsencrypt / cloudflare / other}}
- I want: {{docker-compose on a single VPS / kubernetes / bare metal}}
- Build host arch: {{linux/amd64 / linux/arm64 / apple-silicon-mac-targeting-amd64}}
Now produce: (a) the two docker build commands for aimanac-server + mailsloth-server
(using the Dockerfile paths from spec.build.images), (b) my docker-compose.yml with
correct host:container port mapping per spec.port_mapping, (c) my nginx server block
including the /ihp-ws location, (d) the .env file, (e) the curl commands I should run
to verify. Show your sources by quoting the JSON keys you used.
If I am also deploying sibling apps (BROILR / Archimedes / FL33T / etc.), read
spec.sibling_deploys and pick option A (Railway per sibling), B (single VM co-hosted),
or C (Railway multi-service in one project) based on my preference. Per-sibling
authoritative env vars live in each sibling repo's railway.toml.
TIP
Most assistants will not actually fetch the URL unless you paste the page contents too.
If yours refuses, copy the JSON from panel 02 into the chat as well.
02
Deploy Spec · Machine-Readable
JSON-LD · #aimanac-deploy-spec
This is the canonical source of truth. The visible block below is the same JSON
embedded in <script type="application/json" id="aimanac-deploy-spec">
for scrapers and indexers. Values in amber mustaches are filled in at release time.
SPEC · application/ld+json
03
Build Order & Prerequisites
Pre-Deploy · Captured From XZA's Reference Deploy
The deploy spec above tells your AI what the running stack looks like. This panel tells your AI how
to get there. Every fact below was captured during an end-to-end deploy of aimanac-rs
on the maintainer's reference host. Each item closed a customer-visible footgun on the way.
Step 0 · Docker daemon must be running.
Before any docker command works, the daemon has to be up. On macOS that's
open -a Docker (or open -a OrbStack); on Linux that's
systemctl start docker. Wait until docker ps returns without
Cannot connect to the Docker daemon. Skipping this is the most common first-fault
we see — every docker build below assumes the daemon is live.
Step 1 · Pull the two server images from GHCR (customer path).
Pin the tag from the JSON spec block at the bottom of this page (currently
rust-cutover-20260520-ghcr-pipeline). No aimanac-rs git clone. After Everplay
flips each package to Public on GitHub Packages, docker pull works without login.
Step 1b · Maintainer path — build from aimanac-rs (optional).
Only when publishing a new tag or air-gapped. The aimanac-server Dockerfile is at the repo root;
mailsloth-server uses infrastructure/docker/mailsloth-server.Dockerfile with repo-root
context. See aimanac-rs/infrastructure/ghcr-publish/PUBLISH.md.
Step 2 · Compose uses image:, not build:.
Fleet and co-hosted YAML on this page reference ghcr.io/everplay-tech/<service>:${TAG}.
Set TAG in your env file or export before docker compose pull && docker compose up -d.
Step 3 · Cross-architecture path (only if you must build on Apple Silicon for an x86 host).
Mac builds default to linux/arm64; most cloud hosts (Hetzner / DigitalOcean / Linode general
compute) are linux/amd64. A foreign-arch image loads on disk but fails at runtime with
exec format error — no compile-time signal. If you must build on Mac, force the platform:
SHELL · cross-arch build (Apple Silicon → x86 host)
NOTE
QEMU-emulated Rust builds on Apple Silicon take ~30–60 min. Native amd64 build on the target host
takes ~5–10 min. The native-target path is faster and avoids the arch trap. Prefer it.
Step 4 · Port mapping — host:container is 3002:3000, not 3002:3002.
The aimanac-server binary listens on container-internal port 3000. If you
front it with nginx terminating TLS at the public address, the nginx proxy_pass contract
uses host port 3002. The correct docker run -p mapping is
-p 127.0.0.1:3002:3000 (host:container). An inverted -p 3002:3002 mapping
starts cleanly but yields HTTP 502 from nginx — silent until you curl /health.
Verify with docker inspect <container> --format '{{.NetworkSettings.Ports}}'.
04
Sibling-Server Deploys
BROILR · Archimedes · FL33T · ...
AiMANAC ships with sibling apps — each a $1 standalone iOS app (BROILR, Archimedes,
FL33T, Bombadil, PSL, DeepDive, MailSloth, Satcheli, etc.) backed by its own Rust server binary in
its own repo. The siblings reuse the AiMANAC backend rules (one Postgres, JWT secrets, IHP transport)
and each has its own Railway-friendly Dockerfile + railway.toml. Per-sibling deploy hubs
live at /apps/.
Three deploy options. The same image works in all three; pick the one that matches your
cost / ops complexity preference.
A · A la carte (Railway, one project per sibling)
3 commands per sibling · easiest scaling
One Railway project per sibling. Each project gets its own Postgres add-on, env vars, and public
domain. Customer's bill scales linearly. Project name should match the binary / service name
(broilr-server, fl33t-server) — not the repo name (FL33T-rs).
SHELL · per sibling
cd broilr-rs/ # or archimedes-server/, FL33T-rs/, etc.
railway init --name broilr-server # creates new Railway project
railway up --detach # uploads source; Dockerfile build
railway status # confirms link
railway logs # tail build + runtime
B · Co-hosted (single VM, N docker containers)
docker-compose.yml on one Hetzner / VPS / Mac mini
One box, four (or more) docker processes. Customer pays for one VM. Each sibling binary stays
a distinct process — preserves the family's loose-coupling design. Each sibling can share one
Postgres (own schema) or have its own DB container. Standard docker-compose up -d.
YAML · docker-compose.yml skeleton
# TAG=rust-cutover-20260521-satchel-migration-fix (aimanac; pin from JSON spec below)
services:
aimanac-server:
image: ghcr.io/everplay-tech/aimanac-server:${TAG}
ports: ["127.0.0.1:3002:3000"] # host:container — NOT 3002:3002
environment:
REDIS_URL: redis://redis:6379/0
env_file: aimanac.env
depends_on: [postgres, redis]
mailsloth-server:
image: ghcr.io/everplay-tech/mailsloth-server:${TAG}
ports: ["127.0.0.1:3010:3010"]
env_file: mailsloth.env
depends_on: [postgres]
broilr-server:
image: ghcr.io/everplay-tech/broilr-server:${TAG}
ports: ["127.0.0.1:3030:3010"] # image listens on 3010 inside container
env_file: broilr.env
depends_on: [postgres]
archimedes-server:
image: ghcr.io/everplay-tech/archimedes-server:${TAG}
ports: ["127.0.0.1:3020:3020"]
env_file: archimedes.env
depends_on: [postgres]
fl33t-server:
image: ghcr.io/everplay-tech/fl33t-server:${TAG}
ports: ["127.0.0.1:3000:3000"]
env_file: fl33t.env
depends_on: [postgres]
postgres:
image: pgvector/pgvector:pg16
# each sibling can use its own schema in one DB
redis:
image: redis:7-alpine
C · Railway single-project multi-service.
One Railway project with N services (one per sibling). Saves a bit on project-overhead pricing;
loses per-sibling project isolation. Use railway service add from inside one project
and assign each sibling repo to its own service. Same Dockerfile builds; same env-var pattern.
What customers don't see in this story (yet).
Per-sibling env vars — every sibling needs DATABASE_URL, JWT secrets,
and an APPLE_CLIENT_ID matching its bundle id. The authoritative list per sibling lives
in that sibling's railway.toml + per-app Railway hub at
/apps/<sibling>/setup/railway/. (Cipher's note 2026-05-19: a unified per-sibling
env_required manifest is pending.)
Custom domain attach — Railway hands out auto-domains like
<service>-production-XXXX.up.railway.app. Production needs DNS CNAME +
Railway dashboard "Add Domain" step. Customer-facing per-sibling note.
iOS app → sibling backend wiring — once the sibling backend is up, the iOS app
(BROILR-iOS, FL33T-iOS, etc.) needs the backend URL pasted into its first-boot setup. See the
per-sibling manual at /apps/<sibling>/.
Per-sibling provider OAuth — siblings that connect to upstream providers
(Gmail / Outlook for MailSloth; future connectors for other siblings) need the deployer to
register their own OAuth apps with each provider. MailSloth's walkthrough is live at
/apps/mailsloth/setup/oauth/
— Google Cloud + Microsoft Entra, four+three chunks, apply-to-backend pattern, eight named anti-patterns.
Other siblings' OAuth pages land under /apps/<sibling>/setup/oauth/ when they ship.
NOTE
A single-binary consolidated backend is not on offer. The siblings are intentionally
separate Rust binaries in separate workspaces; consolidating would require a multi-process container
(Docker anti-pattern) or a merged binary refactor. Options A / B / C above are the supported shapes.
05
If Your AI Suggests These, Ignore It
Anti-Hallucination Facts
These are the failure modes we keep seeing customer LLMs invent. They usually come from outdated
blog posts in the training data. None of them produce an error — your deploy will look fine and
silently misbehave. Show this list to your assistant if it tries any of them.
NO
Skipping the /ihp-ws nginx location block
The iOS client uses a WebSocket transport at /ihp-ws. Without an explicit
location that forwards Upgrade + Connection headers,
the app silently falls back to long-polling. No error, just mystery latency.
NO
Leaving proxy_buffering on for /ihp-ws
Buffering stalls WebSocket frames mid-flight. The connection appears up,
but messages arrive in clumps. Set proxy_buffering off on that route.
NO
Using HTTP/1.0 for proxy_pass
WebSocket upgrades require proxy_http_version 1.1;. Without it,
the 101 handshake never completes and nginx returns 502 — or worse, the client
falls back transparently.
NO
Substituting postgres:16 for pgvector/pgvector:pg16
AiMANAC needs the vector extension at boot. Vanilla Postgres will
start, accept connections, then crash on first index build. Use the pgvector image.
NO
Recalling the Docker image tag from memory
Image tags are bumped weekly. The only safe source is the image.tag
field in panel 02. If your assistant types a tag
without quoting that field, reject the output.
NO
Forgetting App Groups on the iOS side
The iOS app needs an App Group entitlement matching app_groups.id in
the spec for the share extension to read the backend URL. Missing it = blank pasteboard,
no error.
NO
Running docker build without starting the daemon first
Customer LLMs often skip the prerequisite. docker version must return both
Client and Server lines before any build will work. On macOS that's
open -a Docker (or open -a OrbStack); on Linux
systemctl start docker. Cannot connect to the Docker daemon = daemon
isn't up.
NO
Looking for mailsloth-server.Dockerfile at the repo root
Customer-facing tip: it lives at
infrastructure/docker/mailsloth-server.Dockerfile, not at the repo root and
not under crates/mailsloth-server/. Build context is still the repo root,
so invoke docker build -f infrastructure/docker/mailsloth-server.Dockerfile ... .
from the repo root.
NO
Building on Apple Silicon without --platform linux/amd64
Docker Desktop on M-series Macs builds linux/arm64 by default. Foreign-arch
images load on amd64 cloud hosts (Hetzner / DigitalOcean / Linode) and then crash at runtime
with exec format error — no compile-time signal. Either build on the target host
natively (recommended) or pass --platform linux/amd64 --load to docker buildx.
NO
Mapping host:container as 3002:3002 instead of 3002:3000
aimanac-server listens on container-internal port 3000. With nginx fronting it,
the public-facing host port is 3002. The correct mapping is
-p 127.0.0.1:3002:3000. Inverting it (:3002:3002) starts the container
cleanly but returns HTTP 502 from nginx — looks like a healthy container, fails every request.
06
Reference Assets
Copy / Paste / Download
Two starter files. Replace every {{MUSTACHE}} with
the corresponding value from panel 02 — don't let your AI fill them
from memory.
Run these against your deploy. Replace your-host
with the public hostname you set in AIMANAC_PUBLIC_HOST.
Both should pass — if the second one returns anything other than 101,
your /ihp-ws route is wrong even if the first one is green.
A · Health Check
SHELL
curl -sS https://your-host/health
EXPECT ·
HTTP 200 ·
body {"status":"ok","version":"…"}