diff --git a/Dockerfile b/Dockerfile index a4620f8..bba592e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,6 +9,10 @@ RUN npm run build # Final runtime image FROM node:24-alpine WORKDIR /app + +# ensure su-exec present to drop privileges later +RUN apk add --no-cache ca-certificates su-exec + # copy package manifests and install deps (leverage Docker cache) COPY backend/package*.json backend/package-lock*.json ./backend/ RUN cd backend && npm ci --silent diff --git a/README.md b/README.md index 9df8695..e8ca1e6 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,31 @@ -Here is example usage of `docker-compose.yml`: +# Tally Counter + +Run the app with Docker Compose (recommended). The container startup/entrypoint will create the runtime folders and apply migrations; pass numeric PUID/PGID via environment to run as a non-root user. + ```yaml -service +services: tally-counter: image: gitea.kanawave.net/sebastas/tally-counter:latest #this image container_name: tally-counter - user: 2000:2000 #uid:gid restart: unless-stopped networks: - - proxy # traefik proxy network + - proxy # connect any proxy networks (for traefik) + environment: + - PUID=1000 # host uid forwarded to container + - PGID=1000 # host gid forwarded to container + ports: + - "3000:3000" # Set whatever port you want on the left side (host) volumes: - - ./tally-counter:/data # for persistant storage (db + uploads) + - ./tally-counter:/data # persistent DB + uploads (bind mount) ``` -Quick and dirty setup! +Add any `labels` for traefik + +### Notes & tips + +The entrypoint will: +- ensure `$DATA_DIR` exists, +- create `sqlite.db` if missing, +- run `prisma migrate deploy` (if CLI available and migrations exist), +- then drop privileges to the provided `PUID:PGID` and exec the app. diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh index 5477176..3ee37e9 100644 --- a/docker/entrypoint.sh +++ b/docker/entrypoint.sh @@ -3,27 +3,50 @@ set -eu DATA_DIR="${DATA_DIR:-/data}" SCHEMA_PATH="./prisma/schema.prisma" +PUID="${PUID:-}" +PGID="${PGID:-$PUID}" -# ensure data dir exists and is writable mkdir -p "$DATA_DIR" chmod 0775 "$DATA_DIR" || true -# ensure DATABASE_URL is set to the runtime DATA_DIR : "${DATABASE_URL:=file:${DATA_DIR}/sqlite.db}" export DATABASE_URL -# create sqlite file if missing SQLITE_DB_PATH="${DATA_DIR}/sqlite.db" if [ ! -f "$SQLITE_DB_PATH" ]; then touch "$SQLITE_DB_PATH" chmod 0664 "$SQLITE_DB_PATH" || true fi -# run non-interactive migrations if CLI available +# run migrations if prisma CLI available if command -v npx >/dev/null 2>&1 && [ -f "$SCHEMA_PATH" ]; then echo "Running prisma migrate deploy..." npx prisma migrate deploy --schema="$SCHEMA_PATH" || echo "prisma migrate deploy failed or no migrations to apply" fi -# exec main process +# If root and numeric PUID supplied, create/reuse group by GID then create user and chown +if [ "$(id -u)" = "0" ] && [ -n "$PUID" ]; then + # try find an existing group with this GID + existing_group="$(getent group | awk -F: -v gid="$PGID" '$3==gid{print $1; exit}')" + if [ -n "$existing_group" ]; then + grp="$existing_group" + else + grp="appgroup" + addgroup -g "${PGID}" "$grp" 2>/dev/null || true + fi + + if ! id -u app >/dev/null 2>&1; then + adduser -D -u "${PUID}" -G "$grp" -s /bin/sh app 2>/dev/null || true + fi + + # ensure runtime paths writable by numeric ids + chown -R "${PUID}:${PGID}" "$DATA_DIR" /app/backend /app/frontend/dist 2>/dev/null || true + + # drop privileges and run command + echo "Running as user: "${PUID}"" + echo "Running as group: "${PGID}"" + exec su-exec "${PUID}:${PGID}" "$@" +fi + +# otherwise run as current user exec "$@" \ No newline at end of file