chore(docker): consolidate runtime paths under unified /opt/pabawi tree#40
chore(docker): consolidate runtime paths under unified /opt/pabawi tree#40
Conversation
alvagante
commented
Apr 12, 2026
- Standardize all container paths to use /opt/pabawi as root directory for data, projects, and certificates
- Update .env.docker with new unified paths for database, Bolt, Hiera, Ansible, SSH, and Proxmox configurations
- Consolidate Dockerfile, Dockerfile.alpine, and Dockerfile.ubuntu to create /opt/pabawi subdirectories in single RUN command
- Set default environment variables in all Dockerfiles to match new unified path structure
- Update docker-compose.yml volume mappings to reference consolidated /opt/pabawi paths
- Revise docker-entrypoint.sh and setup.sh scripts to work with new directory layout
- Update docker-deployment.md documentation to reflect unified path conventions
- Improves maintainability and reduces path configuration complexity across deployment variants
- Standardize all container paths to use /opt/pabawi as root directory for data, projects, and certificates - Update .env.docker with new unified paths for database, Bolt, Hiera, Ansible, SSH, and Proxmox configurations - Consolidate Dockerfile, Dockerfile.alpine, and Dockerfile.ubuntu to create /opt/pabawi subdirectories in single RUN command - Set default environment variables in all Dockerfiles to match new unified path structure - Update docker-compose.yml volume mappings to reference consolidated /opt/pabawi paths - Revise docker-entrypoint.sh and setup.sh scripts to work with new directory layout - Update docker-deployment.md documentation to reflect unified path conventions - Improves maintainability and reduces path configuration complexity across deployment variants
There was a problem hiding this comment.
Pull request overview
Standardizes Docker runtime and configuration paths by consolidating all container-mounted data (database, Bolt project, control repo, certs, SSH, etc.) under a unified /opt/pabawi directory tree.
Changes:
- Updates Dockerfiles,
docker-compose.yml, and.env.dockerto use/opt/pabawi/...paths consistently. - Revises container entrypoint to create/check
/opt/pabawi/dataand default DB pathing accordingly. - Expands
scripts/setup.shto offer Docker vs npm install flows and updates Docker deployment docs for the new layout.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| scripts/setup.sh | Adds Docker detection + Docker/npx install choice; copies env and starts compose/run using /opt/pabawi mounts. |
| scripts/docker-entrypoint.sh | Switches data/db initialization from /data to ${PABAWI_BASE}/data (default /opt/pabawi/data). |
| docs/docker-deployment.md | Updates examples and guidance to mount volumes and configure env vars under /opt/pabawi. |
| Dockerfile | Creates /opt/pabawi subtree and updates default env vars to /opt/pabawi/... paths. |
| Dockerfile.alpine | Same /opt/pabawi subtree + env var updates for Alpine image. |
| Dockerfile.ubuntu | Same /opt/pabawi subtree + env var updates for Ubuntu image. |
| docker-compose.yml | Updates volume mounts to map host dirs into /opt/pabawi/... paths. |
| .env.docker | Updates default paths for database, Bolt, Hiera, Ansible, SSH, certs to /opt/pabawi/.... |
| # Ensure .env exists at project root for docker-compose env_file | ||
| DOCKER_ENV_FILE="$PROJECT_ROOT/.env" | ||
| if [[ -f "$ENV_FILE" ]]; then | ||
| cp "$ENV_FILE" "$DOCKER_ENV_FILE" | ||
| success "Copied backend/.env to project root .env for Docker" | ||
| else | ||
| warn "No backend/.env found — Docker will use .env.docker defaults" | ||
| if [[ -f "$PROJECT_ROOT/.env.docker" ]]; then | ||
| cp "$PROJECT_ROOT/.env.docker" "$DOCKER_ENV_FILE" | ||
| success "Copied .env.docker to .env" | ||
| fi | ||
| fi |
There was a problem hiding this comment.
In Docker install mode you copy backend/.env to the project-root .env, but backend/.env is generated for local npm runs (e.g. DATABASE_PATH=./data/pabawi.db, BOLT_PROJECT_PATH=./samples/...). Those paths won’t exist in the container and will cause the container to fail on startup (entrypoint will try to touch a DB path under ./data). For Docker, prefer using .env.docker as the base (or rewrite path vars like DATABASE_PATH, BOLT_PROJECT_PATH, HIERA_CONTROL_REPO_PATH, etc. to /opt/pabawi/... after copying).
| # Create data directory for volume mount | ||
| mkdir -p "$PROJECT_ROOT/data" | ||
|
|
||
| # Trap to cleanly stop backend when the script is interrupted | ||
| cleanup() { | ||
| if [[ -n "$DOCKER_COMPOSE_CMD" ]]; then | ||
| info "Starting Pabawi with ${DOCKER_COMPOSE_CMD}…" | ||
| echo "" | ||
| info "Pabawi will be available at http://localhost:${PORT:-3000}" | ||
| echo "" | ||
| echo " Start: ${BOLD}${DOCKER_COMPOSE_CMD} up -d${RESET}" | ||
| echo " Logs: ${BOLD}${DOCKER_COMPOSE_CMD} logs -f${RESET}" | ||
| echo " Stop: ${BOLD}${DOCKER_COMPOSE_CMD} down${RESET}" | ||
| echo "" | ||
| info "Shutting down…" | ||
| kill "$BACKEND_PID" 2>/dev/null || true | ||
| wait "$BACKEND_PID" 2>/dev/null || true | ||
| success "Servers stopped." | ||
| } | ||
| trap cleanup EXIT INT TERM | ||
|
|
||
| npm run dev:frontend | ||
| ask_yn START_DOCKER "Start the container now?" "y" | ||
| if [[ "$START_DOCKER" == "true" ]]; then | ||
| cd "$PROJECT_ROOT" | ||
| $DOCKER_COMPOSE_CMD up -d | ||
| success "Pabawi container started" | ||
| info "View logs: ${BOLD}${DOCKER_COMPOSE_CMD} logs -f${RESET}" | ||
| else | ||
| success "Setup complete!" | ||
| info "Run ${BOLD}${DOCKER_COMPOSE_CMD} up -d${RESET} to start Pabawi." | ||
| fi | ||
| else | ||
| info "Docker Compose not available — using docker run." | ||
| echo "" | ||
| info "Pabawi will be available at http://localhost:${PORT:-3000}" | ||
| echo "" | ||
| ask_yn START_DOCKER "Start the container now?" "y" | ||
| if [[ "$START_DOCKER" == "true" ]]; then | ||
| docker run -d \ | ||
| --name pabawi \ | ||
| --env-file "$DOCKER_ENV_FILE" \ | ||
| -p "${PORT:-3000}:3000" \ | ||
| -v "$PROJECT_ROOT/data:/opt/pabawi/data" \ | ||
| -v "$PROJECT_ROOT/bolt-project:/opt/pabawi/bolt-project:ro" \ | ||
| --restart unless-stopped \ | ||
| example42/pabawi:latest |
There was a problem hiding this comment.
The Docker setup creates ./data for the volume mount, but doesn’t create ./bolt-project. With the current docker run command, Docker will create an empty host directory (often root-owned) and Bolt won’t have any project content, likely breaking inventory/commands. Consider creating "$PROJECT_ROOT/bolt-project" (and optionally seeding it from samples/integrations/bolt) or prompting the user for the host bolt-project path before starting the container.
| success "Setup complete!" | ||
| echo "" | ||
| info "Run manually:" | ||
| echo " ${BOLD}docker run -d --name pabawi --env-file .env -p ${PORT:-3000}:3000 -v ./data:/opt/pabawi/data example42/pabawi:latest${RESET}" |
There was a problem hiding this comment.
The printed “Run manually” docker run example omits the required Bolt project volume mount (and uses host ./data only). As written, users who choose not to start immediately will copy/paste a command that starts a container without a Bolt project mounted.
| echo " ${BOLD}docker run -d --name pabawi --env-file .env -p ${PORT:-3000}:3000 -v ./data:/opt/pabawi/data example42/pabawi:latest${RESET}" | |
| echo " ${BOLD}docker run -d --name pabawi --env-file .env -p ${PORT:-3000}:3000 -v ./data:/opt/pabawi/data -v ./bolt-project:/opt/pabawi/bolt-project:ro example42/pabawi:latest${RESET}" |
| if [[ -n "$DOCKER_COMPOSE_CMD" ]]; then | ||
| info "Starting Pabawi with ${DOCKER_COMPOSE_CMD}…" | ||
| echo "" | ||
| info "Pabawi will be available at http://localhost:${PORT:-3000}" | ||
| echo "" | ||
| echo " Start: ${BOLD}${DOCKER_COMPOSE_CMD} up -d${RESET}" | ||
| echo " Logs: ${BOLD}${DOCKER_COMPOSE_CMD} logs -f${RESET}" | ||
| echo " Stop: ${BOLD}${DOCKER_COMPOSE_CMD} down${RESET}" | ||
| echo "" | ||
| info "Shutting down…" | ||
| kill "$BACKEND_PID" 2>/dev/null || true | ||
| wait "$BACKEND_PID" 2>/dev/null || true | ||
| success "Servers stopped." | ||
| } | ||
| trap cleanup EXIT INT TERM | ||
|
|
||
| npm run dev:frontend | ||
| ask_yn START_DOCKER "Start the container now?" "y" | ||
| if [[ "$START_DOCKER" == "true" ]]; then | ||
| cd "$PROJECT_ROOT" | ||
| $DOCKER_COMPOSE_CMD up -d | ||
| success "Pabawi container started" |
There was a problem hiding this comment.
DOCKER_COMPOSE_CMD is set to the string "docker compose" and later executed as $DOCKER_COMPOSE_CMD up -d. This relies on word-splitting and will trip shellcheck (SC2086) and is easy to break if the command ever changes. Prefer storing the command as an array (e.g. (docker compose) vs (docker-compose)) and executing it via "${DOCKER_COMPOSE_CMD[@]}" up -d (same for logs/down).
| # Create database file if it doesn't exist | ||
| if [ ! -f /data/pabawi.db ]; then | ||
| touch /data/pabawi.db | ||
| DB_FILE="${DATABASE_PATH:-${DATA_DIR}/pabawi.db}" | ||
| if [ ! -f "${DB_FILE}" ]; then | ||
| touch "${DB_FILE}" | ||
| fi |
There was a problem hiding this comment.
The entrypoint creates ${DATA_DIR} but then touches ${DB_FILE} without ensuring the parent directory of ${DB_FILE} exists. If DATABASE_PATH is overridden to a different directory (or a relative path), the container will fail before starting. Consider mkdir -p "$(dirname "$DB_FILE")" before touch, and then ensure that directory is writable (not just ${DATA_DIR}).
| All Pabawi data lives under `/opt/pabawi/` both inside the container and on the host (for npm installs). This unified layout means the same paths work everywhere — no mental translation between host and container paths. | ||
|
|
||
| ```text | ||
| /opt/pabawi/ | ||
| ├── app/ # Application code (npm install only; Docker uses /app) | ||
| ├── data/ # SQLite database (pabawi.db) |
There was a problem hiding this comment.
The “Directory Structure” section claims the same /opt/pabawi/ layout is used “on the host (for npm installs)”, and even lists /opt/pabawi/app/. The local npm setup in scripts/setup.sh uses paths under the repo (e.g. ./backend/data / DATABASE_PATH=./data/pabawi.db), so this statement is misleading. Recommend describing /opt/pabawi as the in-container layout only (and optionally showing the host layout used by the setup script separately).
| if [ ! -w "${DATA_DIR}" ]; then | ||
| echo "Error: ${DATA_DIR} directory is not writable by user $(id -u)" | ||
| echo "Please ensure the mounted volume has correct permissions:" | ||
| echo " sudo chown -R 1001:1001 /path/to/data" | ||
| echo " sudo chown -R 1001:1001 ${DATA_DIR}" | ||
| exit 1 |
There was a problem hiding this comment.
The permissions error message suggests running sudo chown -R 1001:1001 ${DATA_DIR}. ${DATA_DIR} is the container path (/opt/pabawi/data by default), but the user needs to chown the host directory that’s mounted there. Consider changing the message to refer to the host path (or make it explicit that this command must be run on the host against the mounted directory).