mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-02 02:07:25 +08:00
## 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 '<lan-ip>' 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 '<lan-ip>' 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
45 lines
1.9 KiB
YAML
45 lines
1.9 KiB
YAML
# Quickstart: single-container Paperclip with embedded database.
|
|
# Copy this file and set the required env vars before running.
|
|
#
|
|
# cd docker
|
|
# export BETTER_AUTH_SECRET="$(openssl rand -hex 32)"
|
|
# export ANTHROPIC_API_KEY="sk-ant-..."
|
|
# docker compose -f docker-compose.quickstart.yml up --build
|
|
#
|
|
services:
|
|
paperclip:
|
|
build:
|
|
context: ..
|
|
dockerfile: Dockerfile
|
|
# Ceiling on processes. The image makes tini PID 1 so orphaned agent
|
|
# descendants are reaped instead of piling up as zombies; this is the
|
|
# backstop if something leaks anyway — the container hits its own limit and
|
|
# dies visibly rather than starving the host of pids.
|
|
pids_limit: 2048
|
|
ports:
|
|
- "${PAPERCLIP_PORT:-3100}:3100"
|
|
environment:
|
|
HOST: "0.0.0.0"
|
|
PAPERCLIP_HOME: "/paperclip"
|
|
|
|
# ── LLM provider keys (at least one is needed for agents to work) ──
|
|
OPENAI_API_KEY: "${OPENAI_API_KEY:-}"
|
|
ANTHROPIC_API_KEY: "${ANTHROPIC_API_KEY:-}"
|
|
|
|
# ── Deployment settings ──
|
|
# "authenticated" requires login, "local_trusted" skips auth
|
|
PAPERCLIP_DEPLOYMENT_MODE: "authenticated"
|
|
# "private" = LAN only, "public" = internet-facing (use with TLS)
|
|
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}"
|
|
volumes:
|
|
# Persistent data directory (database, agent workspaces, uploads)
|
|
- "${PAPERCLIP_DATA_DIR:-../data/docker-paperclip}:/paperclip"
|