Skip to content

Commit c790e6a

Browse files
committed
fix(docker): run as root so Railway-mounted volumes are writable
Railway (and other managed PaaS platforms) mount fresh volumes as root-owned at runtime, shadowing the image-baked /data directory we chowned to `app:app` at build time. Result: EACCES on first write to /data/memory or /data/sessions. Drop the non-root user. For a single-tenant personal bot on a sandboxed PaaS, the hardening is marginal compared to the volume-permission friction it creates. The alternative — root entrypoint + su-exec drop — adds dependencies and complexity without meaningful security benefit in this deployment model.
1 parent 810f0ec commit c790e6a

2 files changed

Lines changed: 2 additions & 6 deletions

File tree

Dockerfile

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,6 @@ COPY --from=builder /app/dist ./dist
2525
COPY SOUL.md ./SOUL.md
2626
COPY skills ./skills
2727

28-
RUN addgroup -S app && adduser -S -G app app \
29-
&& mkdir -p /data \
30-
&& chown -R app:app /data /app
31-
32-
USER app
28+
RUN mkdir -p /data
3329

3430
CMD ["node", "dist/index.js"]

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ docker run -d --name cycling-coach \
309309

310310
Use `--env-file` rather than inline `-e KEY=value` flags — inline values land in shell history and are visible to other users via `ps`. Your `.env` should contain `ANTHROPIC_API_KEY` (or `OPENAI_API_KEY` / `GOOGLE_GENERATIVE_AI_API_KEY`), `INTERVALS_API_KEY`, `INTERVALS_ATHLETE_ID`, and `TELEGRAM_BOT_TOKEN`.
311311

312-
The image runs as a non-root user, mounts `/data` for state, and reads `/data/config.yaml` if present. With the `-e` env vars above, no `config.yaml` is required — the legacy env-var fallback (`ANTHROPIC_API_KEY` etc.) covers the three secret fields.
312+
The image mounts `/data` for state and reads `/data/config.yaml` if present. The container runs as root — managed PaaS platforms (Railway, Fly) typically mount fresh volumes as root-owned, and dropping privileges inside a single-tenant container adds little practical hardening on top of the platform's own isolation. With the `-e` env vars above, no `config.yaml` is required — the legacy env-var fallback (`ANTHROPIC_API_KEY` etc.) covers the three secret fields.
313313

314314
For finer control (custom model, idle timeout, etc.) drop a `config.yaml` into the volume:
315315

0 commit comments

Comments
 (0)