Skip to content

Configuration (.env)

Optional: every setting already has a default in docker-compose.yml, so the stack comes up with no .env at all. In practice it holds three groups:

  • Always relevant — OPENCODE_SERVER_PASSWORD (shared by the opencode server and openchamber's client; opencode v2 401s without it), CODE_SERVER_PASSWORD or argon2 CODE_SERVER_HASHED_PASSWORD, OPENCHAMBER_UI_PASSWORD.
  • Only when you select that service — TTYD_CREDENTIALS (user:password; optional: without it the terminal service starts anonymous and warns in its logs), OBSIDIAN_USER + OBSIDIAN_PASSWORD (the obsidian image has no auth without them), PORT_TTYD / PORT_OBSIDIAN / PORT_T3CODE (t3code takes no secret — clients pair with a one-time link from its logs).
  • Only with --tunnel — DOMAIN (base domain for the routes, e.g. example.com), TUNNEL_TOKEN, and optionally COMPOSE_PROFILES=tunnel.
  • AINV_SERVICES — comma-separated list that pre-fills the chooser checkboxes, defaulting to code-server. It is not what runs: setup.sh re-asks each time and turns your answer into --profile flags.

See .env.example for the full list; it also carries the PORT_* overrides (PORT_CODE_SERVER, PORT_OPENCODE, PORT_OPENCHAMBER, PORT_TTYD, PORT_OBSIDIAN, PORT_T3CODE).

Leave both code-server password vars empty and it generates one on first boot:

docker compose exec code-server cat /home/dev/.config/code-server/config.yaml

Generate values with:

openssl rand -base64 24

Hygiene note: secrets are no longer passed as CLI flags, which in nanocode.sh leaked them into shell history, the resume unit and ps aux. The tunnel token now arrives as a container env var — anyone with docker access can still read it via docker inspect, so keep that group small.

Next: Storage — what is mounted where.