Runs aeman behind Caddy, which terminates TLS with an automatic Let's Encrypt certificate. Each visitor signs in with GitHub and acts with their own token.
browser ──HTTPS──► Caddy (:443, auto-TLS) ──http──► aeman:8765
GitHub → Settings → Developer settings → OAuth Apps → New OAuth App:
- Homepage URL:
https://aeman.example.com - Authorization callback URL:
https://aeman.example.com/auth/callback
Generate a client secret. Keep the Client ID and Client secret.
- Add a DNS A record:
aeman.example.com→ your server IP (DNS-only / not proxied, so Caddy can solve the ACME challenge). - Open inbound TCP 80 and 443 on the server.
git clone https://github.com/aenix-io/aeman.git
cd aeman
cp .env.example .env
# fill AEMAN_GITHUB_CLIENT_ID / _SECRET, AEMAN_BASE_URL, AEMAN_DOMAIN
docker compose up -d --buildCaddy issues the certificate on first start (needs DNS + ports 80/443 already in place). Open https://aeman.example.com, click Sign in with GitHub, and you're in.
To pin every visitor to a single project and hide the board picker, set in .env:
AEMAN_OWNER=acme
AEMAN_BOARD=37
AEMAN_LOCK_BOARD=trueA user whose token can't read that board sees an access-denied screen rather than the board.
- Sessions & the session store.
AEMAN_SESSION_FILE(on theaeman_sessionsvolume) always persists the dynamic MCP client registry. Sessions — the GitHub tokens — are written there only whenAEMAN_SESSION_KEYis set, encrypted with it (AES-256-GCM); then restarts and redeploys keep users signed in and MCP tokens live. Without the key, sessions stay in memory and a restart signs everyone out — no plaintext token ever touches disk either way. Keep the key stable (changing or losing it just signs everyone out) and store it outside the session volume so a leak of that volume alone exposes nothing. Classic OAuth App tokens don't expire, so a session simply lasts up to 14 days. - Scopes:
AEMAN_SCOPESdefaults torepo project(Projects v2 + issues). - Cert storage: the
caddy_datavolume persists issued certificates across restarts. - Local gh mode is unchanged: without the
AEMAN_GITHUB_*env vars the binary still runs as a single-user local tool usinggh auth token. - Behind Cloudflare Tunnel instead of Caddy? Drop the
caddyservice, add acloudflaredservice with your tunnel token, and route the public hostname tohttp://aeman:8765; keepAEMAN_BASE_URLpointed at the public HTTPS URL.