diff --git a/.env.example b/.env.example index 8d84a1b..94ecea8 100644 --- a/.env.example +++ b/.env.example @@ -30,4 +30,11 @@ TELEGRAM_DEFAULT_PROJECT_ID= APP_BIND_HOST=127.0.0.1 APP_PORT=3000 +# Optional Docker runtime cache/temp paths (inside container). +# Defaults are defined in docker-compose.yml and usually do not need overrides. +# APP_TMP_DIR=/app/data/tmp +# PLAYWRIGHT_BROWSERS_PATH=/app/data/ms-playwright +# NPM_CONFIG_CACHE=/app/data/npm-cache +# XDG_CACHE_HOME=/app/data/.cache + APP_BASE_URL=http://localhost:3000 diff --git a/Dockerfile b/Dockerfile index 2534a36..6324e09 100644 --- a/Dockerfile +++ b/Dockerfile @@ -19,6 +19,10 @@ ENV PYTHON_VENV=/opt/eggent-python ENV PATH="${PYTHON_VENV}/bin:${PATH}" ENV PIP_DISABLE_PIP_VERSION_CHECK=1 ENV PIP_NO_CACHE_DIR=1 +ENV TMPDIR=/app/data/tmp +ENV PLAYWRIGHT_BROWSERS_PATH=/app/data/ms-playwright +ENV npm_config_cache=/app/data/npm-cache +ENV XDG_CACHE_HOME=/app/data/.cache RUN apt-get update \ && apt-get install -y --no-install-recommends \ @@ -46,7 +50,8 @@ COPY --from=builder /app/.next ./.next COPY --from=builder /app/next.config.mjs ./next.config.mjs COPY --from=builder /app/bundled-skills ./bundled-skills -RUN mkdir -p /app/data && chown -R node:node /app "${PYTHON_VENV}" +RUN mkdir -p /app/data/tmp /app/data/ms-playwright /app/data/npm-cache /app/data/.cache \ + && chown -R node:node /app "${PYTHON_VENV}" USER node EXPOSE 3000 diff --git a/README.md b/README.md index 2f51deb..4f7e3ed 100644 --- a/README.md +++ b/README.md @@ -160,11 +160,16 @@ Main environment variables: | `APP_BASE_URL` | Recommended | Public app URL used by integrations | | `APP_BIND_HOST` | No | Docker port bind host (default: `127.0.0.1`; set `0.0.0.0` for public access) | | `APP_PORT` | No | Published app port (default: `3000`) | +| `APP_TMP_DIR` | No | Docker temp directory passed as `TMPDIR` (default: `/app/data/tmp`) | +| `PLAYWRIGHT_BROWSERS_PATH` | No | Browser install/cache path for Playwright (default: `/app/data/ms-playwright`) | +| `NPM_CONFIG_CACHE` | No | npm cache directory for runtime installs (default: `/app/data/npm-cache`) | +| `XDG_CACHE_HOME` | No | Generic CLI cache directory (default: `/app/data/.cache`) | ## Data Persistence - Runtime state lives in `./data` - Docker mounts `./data` into `/app/data` +- Runtime temp/cache paths are persisted under `./data` (for example: `tmp/`, `ms-playwright/`, `npm-cache/`, `.cache/`) - Keep backups of `data/` and `.env` for disaster recovery ## Security Defaults @@ -172,7 +177,6 @@ Main environment variables: Docker defaults are security-oriented: - compose default bind: `127.0.0.1:${APP_PORT:-3000}:3000` (`APP_BIND_HOST=0.0.0.0` exposes publicly) - non-root container user (`node`) -- tmpfs for `/tmp` - `node` user has passwordless `sudo` in container to allow AI-driven package installation ## Health Check @@ -208,7 +212,15 @@ Try with `sudo docker ...` or add your user to the `docker` group. 4. Build fails after dependency changes Run `npm install` and retry `npm run build`. -5. `Process error: spawn python3 ENOENT` in Code Execution +5. Large downloads fail with `No space left on device` despite free server disk +This usually means temp/cache paths are constrained in the runtime environment. Rebuild and restart with current compose defaults, then verify inside container: +```bash +docker compose build --no-cache app +docker compose up -d app +docker compose exec app sh -lc 'df -h /tmp /app/data && echo "TMPDIR=$TMPDIR" && echo "PLAYWRIGHT_BROWSERS_PATH=$PLAYWRIGHT_BROWSERS_PATH"' +``` + +6. `Process error: spawn python3 ENOENT` in Code Execution `python3` is missing in runtime environment. For Docker deploys: @@ -224,7 +236,7 @@ sudo apt-get update && sudo apt-get install -y python3 python3 --version ``` -6. `sh: 1: curl: not found` in Code Execution (terminal runtime) +7. `sh: 1: curl: not found` in Code Execution (terminal runtime) `curl` is missing in runtime environment. For Docker deploys: @@ -240,13 +252,13 @@ sudo apt-get update && sudo apt-get install -y curl curl --version ``` -7. `command not found` for common terminal/skill commands (`git`, `jq`, `rg`) +8. `command not found` for common terminal/skill commands (`git`, `jq`, `rg`) Install recommended CLI utilities: ```bash sudo apt-get update && sudo apt-get install -y git jq ripgrep ``` -8. `ModuleNotFoundError: No module named 'requests'` in Python Code Execution +9. `ModuleNotFoundError: No module named 'requests'` in Python Code Execution `requests` is missing in runtime environment. For Docker deploys: @@ -262,7 +274,7 @@ sudo apt-get update && sudo apt-get install -y python3-requests python3 -c "import requests; print(requests.__version__)" ``` -9. `/usr/bin/python3: No module named pip` when trying to install Python packages +10. `/usr/bin/python3: No module named pip` when trying to install Python packages `pip` is missing in runtime environment. For Docker deploys: @@ -278,7 +290,7 @@ sudo apt-get update && sudo apt-get install -y python3-pip python3 -m pip --version ``` -10. `apt-get install ...` fails in Code Execution with `Permission denied` +11. `apt-get install ...` fails in Code Execution with `Permission denied` Use sudo in terminal runtime: ```bash sudo apt-get update && sudo apt-get install -y ffmpeg diff --git a/docker-compose.yml b/docker-compose.yml index 41bf529..7bafe89 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -15,12 +15,14 @@ services: NEXT_TELEMETRY_DISABLED: "1" HOSTNAME: 0.0.0.0 PORT: "3000" + TMPDIR: ${APP_TMP_DIR:-/app/data/tmp} + PLAYWRIGHT_BROWSERS_PATH: ${PLAYWRIGHT_BROWSERS_PATH:-/app/data/ms-playwright} + npm_config_cache: ${NPM_CONFIG_CACHE:-/app/data/npm-cache} + XDG_CACHE_HOME: ${XDG_CACHE_HOME:-/app/data/.cache} ports: - "${APP_BIND_HOST:-127.0.0.1}:${APP_PORT:-3000}:3000" volumes: - ./data:/app/data - tmpfs: - - /tmp:rw,noexec,nosuid,size=64m healthcheck: test: [ diff --git a/scripts/install-docker.sh b/scripts/install-docker.sh index 767760b..89b7cf5 100755 --- a/scripts/install-docker.sh +++ b/scripts/install-docker.sh @@ -103,6 +103,7 @@ docker_cmd() { prepare_data_dir() { local data_dir="$ROOT_DIR/data" mkdir -p "$data_dir" + mkdir -p "$data_dir/tmp" "$data_dir/ms-playwright" "$data_dir/npm-cache" "$data_dir/.cache" # The runtime container runs as user "node" (uid/gid 1000). # If setup is executed as root, fix bind-mount ownership to avoid EACCES at runtime. @@ -120,7 +121,7 @@ ensure_data_dir_writable_for_runtime() { local data_dir="$ROOT_DIR/data" if docker_cmd run --rm --user 1000:1000 -v "$data_dir:/target" eggent:local \ - sh -lc "test -w /target" >/dev/null 2>&1; then + sh -lc "mkdir -p /target/tmp /target/ms-playwright /target/npm-cache /target/.cache && test -w /target && test -w /target/tmp && test -w /target/ms-playwright && test -w /target/npm-cache && test -w /target/.cache" >/dev/null 2>&1; then return 0 fi @@ -128,11 +129,11 @@ ensure_data_dir_writable_for_runtime() { sh -lc "chown -R 1000:1000 /target" >/dev/null 2>&1 || true if docker_cmd run --rm --user 1000:1000 -v "$data_dir:/target" eggent:local \ - sh -lc "test -w /target" >/dev/null 2>&1; then + sh -lc "mkdir -p /target/tmp /target/ms-playwright /target/npm-cache /target/.cache && test -w /target && test -w /target/tmp && test -w /target/ms-playwright && test -w /target/npm-cache && test -w /target/.cache" >/dev/null 2>&1; then return 0 fi - echo "ERROR: data directory is not writable for runtime user (uid 1000)." >&2 + echo "ERROR: data directory/cache paths are not writable for runtime user (uid 1000)." >&2 echo "Fix and rerun:" >&2 echo " sudo chown -R 1000:1000 $data_dir" >&2 exit 1