diff --git a/.env.example b/.env.example index 32fe362..21f718b 100644 --- a/.env.example +++ b/.env.example @@ -3,8 +3,12 @@ # OpenRouter (recommended default provider for this stack) OPENROUTER_API_KEY=sk-or-v1-replace-me +# Match host user that owns the workspace mount (boka: id -u / id -g → 1002) +PUID=1002 +PGID=1002 + # Host directory mounted at /workspaces inside the containers. -# On boka, point at the projects Pi should see, e.g.: -# WORKSPACE_HOST_PATH=/home/frank -# For local smoke tests, leave unset to use ./workspaces -WORKSPACE_HOST_PATH=./workspaces +# On boka: +WORKSPACE_HOST_PATH=/home/frank +# For local smoke tests without /home/frank projects: +# WORKSPACE_HOST_PATH=./workspaces diff --git a/DEPLOY.md b/DEPLOY.md index f88327c..1715cf5 100644 --- a/DEPLOY.md +++ b/DEPLOY.md @@ -19,15 +19,18 @@ cd /home/frank/pi.schwenk.online cp .env.example .env # edit OPENROUTER_API_KEY -# set WORKSPACE_HOST_PATH to the host dirs Pi should edit, e.g. /home/frank +# PUID/PGID = host user (frank on boka: 1002) — must match `id -u` / `id -g` +# WORKSPACE_HOST_PATH=/home/frank -mkdir -p data/pi-web data/pi-agent workspaces -# Container runs as uid 1000 (node); fix ownership if needed: -sudo chown -R 1000:1000 data workspaces +mkdir -p data/pi-web data/pi-agent +chown -R "$(id -u):$(id -g)" data docker compose build docker compose up -d docker compose logs -f --tail=100 + +# smoke: should list your projects, not Permission denied +docker compose exec web ls /workspaces/eselhoefe.de ``` ## Verify @@ -56,3 +59,4 @@ docker compose build --no-cache && docker compose up -d - No host port publish; only Traefik on network `traefik` reaches `:8504` - Middleware is referenced only (`authelia@docker`); ForwardAuth is defined on Authelia - `pi-coding-agent` pinned to `0.82.1` for current `pi-web` peer range +- Container runs as `PUID`/`PGID` (default 1002) so bind mounts under `/home/frank` are readable diff --git a/Dockerfile b/Dockerfile index 24c8655..dff6ac5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,14 @@ # Pi Coding Agent + PI WEB (Plain Docker) # Peer pin: pi-web requires pi-coding-agent >=0.82.1 <0.83 +# Run as host UID/GID so bind-mounted /home/frank (etc.) is readable. +ARG PUID=1002 +ARG PGID=1002 + FROM node:24-bookworm-slim +ARG PUID=1002 +ARG PGID=1002 + RUN apt-get update \ && apt-get install -y --no-install-recommends \ bash \ @@ -19,28 +26,26 @@ RUN npm install -g --ignore-scripts @earendil-works/pi-coding-agent@0.82.1 \ && npm install -g @jmfederico/pi-web@1.202607.3 --allow-scripts=node-pty \ && npm cache clean --force -# Drop build toolchain from runtime image layer weight is optional; keep for native package installs -# Re-install without g++ would break future pi packages needing compile — leave tools in. +RUN groupadd -g "${PGID}" pi \ + && useradd -u "${PUID}" -g "${PGID}" -m -d /home/pi -s /bin/bash pi \ + && mkdir -p /data/pi-web /workspaces /home/pi/.pi/agent /home/pi/.config/pi-web \ + && chown -R pi:pi /data /workspaces /home/pi -RUN mkdir -p /data/pi-web /workspaces /home/node/.pi/agent /home/node/.config/pi-web \ - && chown -R node:node /data /workspaces /home/node/.pi /home/node/.config +COPY --chown=pi:pi config/pi-web.config.json /etc/pi-web/config.json -COPY --chown=node:node config/pi-web.config.json /etc/pi-web/config.json - -ENV HOME=/home/node \ +ENV HOME=/home/pi \ PI_WEB_CONFIG=/etc/pi-web/config.json \ PI_WEB_DATA_DIR=/data/pi-web \ - PI_CODING_AGENT_DIR=/home/node/.pi/agent \ + PI_CODING_AGENT_DIR=/home/pi/.pi/agent \ PI_WEB_SESSIOND_SOCKET=/data/pi-web/sessiond.sock \ PI_WEB_HOST=0.0.0.0 \ PI_WEB_PORT=8504 \ PI_WEB_ALLOWED_HOSTS=pi.schwenk.online \ PATH="/usr/local/bin:${PATH}" -USER node +USER pi WORKDIR /workspaces EXPOSE 8504 -# Default overridden per-service in compose.yml CMD ["pi-web-server"] diff --git a/NOTES.md b/NOTES.md index 49598a9..54a0da4 100644 --- a/NOTES.md +++ b/NOTES.md @@ -13,7 +13,9 @@ Implemented Compose stack for PI WEB + Pi behind Traefik/Authelia. See [DEPLOY.m - `web` HTTP `200` on `:8504`; `pi --version` → `0.82.1` - Full Authelia/DNS/TOTP path: only on boka after DNS + `.env` key -Stack stopped locally after smoke (`docker compose down`). +## UID fix (2026-08-01) + +Container must run as host `frank` (1002:1002), not image `node` (1000). Rebuild with `PUID`/`PGID` after pull. ## Authelia handoff (locked) diff --git a/SOUL.md b/SOUL.md index 2a4d5e5..fdb5747 100644 --- a/SOUL.md +++ b/SOUL.md @@ -46,8 +46,9 @@ Fränky — single trusted user; remote control surface for agent work under `/h - **Compose:** `compose.yml` — services `sessiond` + `web`, image built from `Dockerfile` - **Networks:** external `traefik` - **Auth:** Authelia portal `https://auth.schwenk.online`; middleware `authelia@docker`; ACL `two_factor` for this host -- **Data:** `./data/pi-web` (PI WEB state + sessiond socket), `./data/pi-agent` → `~/.pi/agent` (sessions, packages, auth) +- **Data:** `./data/pi-web` (PI WEB state + sessiond socket), `./data/pi-agent` → `/home/pi/.pi/agent` (sessions, packages, auth) - **Workspaces:** host path via `WORKSPACE_HOST_PATH` → container `/workspaces` +- **UID:** `PUID`/`PGID` in `.env` must match host owner of the mount (boka frank = 1002) - **Secrets:** `OPENROUTER_API_KEY` in `.env` (see `.env.example`) ### Authelia handoff (consumed) diff --git a/compose.yml b/compose.yml index b227405..500db54 100644 --- a/compose.yml +++ b/compose.yml @@ -1,54 +1,65 @@ # PI WEB + Pi Coding Agent behind Traefik + Authelia (external) # Deploy: /home/frank/pi.schwenk.online → https://pi.schwenk.online +# +# PUID/PGID must match the host user that owns WORKSPACE_HOST_PATH (boka: frank=1002). services: sessiond: - build: . + build: + context: . + args: + PUID: ${PUID:-1002} + PGID: ${PGID:-1002} image: pidevremote-pi:local container_name: pi-sessiond restart: unless-stopped + user: "${PUID:-1002}:${PGID:-1002}" command: ["pi-web-sessiond"] env_file: - .env environment: - HOME: /home/node + HOME: /home/pi PI_WEB_CONFIG: /etc/pi-web/config.json PI_WEB_DATA_DIR: /data/pi-web PI_WEB_SESSIOND_SOCKET: /data/pi-web/sessiond.sock - PI_CODING_AGENT_DIR: /home/node/.pi/agent + PI_CODING_AGENT_DIR: /home/pi/.pi/agent OPENROUTER_API_KEY: ${OPENROUTER_API_KEY:-} volumes: - ./data/pi-web:/data/pi-web - - ./data/pi-agent:/home/node/.pi/agent + - ./data/pi-agent:/home/pi/.pi/agent - ${WORKSPACE_HOST_PATH:-./workspaces}:/workspaces networks: - internal web: - build: . + build: + context: . + args: + PUID: ${PUID:-1002} + PGID: ${PGID:-1002} image: pidevremote-pi:local container_name: pi-web restart: unless-stopped + user: "${PUID:-1002}:${PGID:-1002}" command: ["pi-web-server"] depends_on: - sessiond env_file: - .env environment: - HOME: /home/node + HOME: /home/pi PI_WEB_CONFIG: /etc/pi-web/config.json PI_WEB_DATA_DIR: /data/pi-web PI_WEB_SESSIOND_SOCKET: /data/pi-web/sessiond.sock PI_WEB_HOST: "0.0.0.0" PI_WEB_PORT: "8504" PI_WEB_ALLOWED_HOSTS: pi.schwenk.online - PI_CODING_AGENT_DIR: /home/node/.pi/agent + PI_CODING_AGENT_DIR: /home/pi/.pi/agent OPENROUTER_API_KEY: ${OPENROUTER_API_KEY:-} volumes: - ./data/pi-web:/data/pi-web - - ./data/pi-agent:/home/node/.pi/agent + - ./data/pi-agent:/home/pi/.pi/agent - ${WORKSPACE_HOST_PATH:-./workspaces}:/workspaces - # No host port publish — Traefik reaches the container on the traefik network expose: - "8504" networks: