From 82ee0a68d470d2c88cec2367bf379aa07942a921 Mon Sep 17 00:00:00 2001 From: Ross Sclafani Date: Thu, 3 Sep 2026 22:22:33 -0500 Subject: [PATCH] chore(docker): pass PAPERCLIP_ALLOWED_HOSTNAMES through to quickstart (#6846) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Thinking Path > - Operators run Paperclip in many places: localhost dev, LAN servers, Tailscale meshes, cloud VMs > - The server already supports a `PAPERCLIP_ALLOWED_HOSTNAMES` env var for hostname allow-listing (`server/src/config.ts`) > - But `docker/docker-compose.quickstart.yml` did not forward that env var from the host to the container > - So an operator running quickstart on a LAN gets "Hostname '' is not allowed for this Paperclip instance" with no env-only escape hatch — they're forced to run the CLI inside the container to write `config.json` > - This PR adds a one-line passthrough so the existing env var works end-to-end with the quickstart compose file > - The benefit is parity with the server's documented config surface: anything settable via env on a bare-metal run is now settable via env on a quickstart docker run ## Linked Issues or Issue Description **What happened?** Running the quickstart compose file on a LAN host and opening the UI by the machine's LAN address fails with "Hostname '' is not allowed for this Paperclip instance". The server supports `PAPERCLIP_ALLOWED_HOSTNAMES` for exactly this case and `doc/DOCKER.md` tells operators to set it, but `docker/docker-compose.quickstart.yml` never forwards the variable into the container, so setting it on the host has no effect. **Expected behavior** Setting `PAPERCLIP_ALLOWED_HOSTNAMES` on the host before `docker compose up` reaches the server, the same way `PAPERCLIP_PUBLIC_URL` and the provider keys do. **Steps to reproduce** 1. `export PAPERCLIP_ALLOWED_HOSTNAMES=my-lan-host` alongside the other quickstart variables. 2. `docker compose -f docker-compose.quickstart.yml up --build`. 3. Open `http://my-lan-host:3100` and observe the hostname rejection. **Paperclip version or commit** `master` when this PR was opened (May 2026); the quickstart file on current `master` still has no passthrough. The branch is rebased onto current `master`. **Deployment mode** Docker quickstart (`docker-compose.quickstart.yml`), authenticated and private. ## What Changed - `docker/docker-compose.quickstart.yml`: forward `PAPERCLIP_ALLOWED_HOSTNAMES` from the host environment with an empty default, matching the existing pattern used for `PAPERCLIP_PUBLIC_URL`, `OPENAI_API_KEY`, etc. ## Verification ```sh # 1. Set the env var echo \"PAPERCLIP_ALLOWED_HOSTNAMES=localhost,my-lan-ip\" >> .env # 2. Bring up the quickstart docker compose --env-file .env -f docker/docker-compose.quickstart.yml up -d # 3. Confirm the value reached the container docker compose -f docker/docker-compose.quickstart.yml exec paperclip \\ sh -c 'echo \"\$PAPERCLIP_ALLOWED_HOSTNAMES\"' # → localhost,my-lan-ip # 4. Confirm boot-time trusted-origins log includes the LAN host docker compose -f docker/docker-compose.quickstart.yml logs paperclip | grep trustedOrigins # 5. Confirm a request from the LAN host returns 401 (auth required), not the hostname rejection curl -i -H \"Host: my-lan-ip:3100\" http://localhost:3100/api/auth/get-session # → HTTP/1.1 401 Unauthorized ``` Tested locally on Linux with an authenticated/private deployment, migrated DB from another paperclip instance, and a LAN host reaching the container. The image was rebuilt with \`--no-cache\` from a clean checkout of this branch's tip (no other unmerged work in the build context) to confirm the change is self-contained. ## Risks Low risk. - Default value is empty string — behavior identical to before for any operator who doesn't set the var. - Env var name and semantics already implemented and documented on the server side (\`server/src/config.ts\`); this PR only routes the value through compose. - One-line yaml change, no code touched, no tests affected. ## Model Used - Claude (Anthropic) — Opus 4.7 (1M context). Used for the bug isolation, the env-var-vs-config-file choice, and the PR write-up. Authored alongside Ross Sclafani who tested end-to-end against a migrated LAN deployment. ## Checklist - [x] Thinking path traces from project context to this change - [x] Model used specified (with version + capability details) - [x] Checked ROADMAP.md — not a feature, no overlap with planned work - [x] Ran tests locally (\`pnpm install --frozen-lockfile\`, \`pnpm build\` clean; container rebuilt \`--no-cache\` from this branch tip and verified end-to-end) - Added or updated tests — N/A (compose env passthrough; no executable code path) - UI change screenshots — N/A (no UI) - [x] No documentation updates needed (env var already documented server-side) - [x] Considered risks (above) - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] Will address all Greptile/reviewer comments before requesting merge --- docker/docker-compose.quickstart.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docker/docker-compose.quickstart.yml b/docker/docker-compose.quickstart.yml index 41a674916f..f750bda19b 100644 --- a/docker/docker-compose.quickstart.yml +++ b/docker/docker-compose.quickstart.yml @@ -33,6 +33,9 @@ services: PAPERCLIP_DEPLOYMENT_EXPOSURE: "private" # Base URL users will access the UI at PAPERCLIP_PUBLIC_URL: "${PAPERCLIP_PUBLIC_URL:-http://localhost:3100}" + # Extra hostnames the instance accepts beyond the public URL host + # (LAN or Tailscale aliases), comma-separated; empty means none + PAPERCLIP_ALLOWED_HOSTNAMES: "${PAPERCLIP_ALLOWED_HOSTNAMES:-}" # ── Required secret for session signing (generate with: openssl rand -hex 32) ── BETTER_AUTH_SECRET: "${BETTER_AUTH_SECRET:?BETTER_AUTH_SECRET must be set}"