diff --git a/Containerfile b/Containerfile index bde16b2..4287bee 100644 --- a/Containerfile +++ b/Containerfile @@ -193,7 +193,7 @@ LABEL org.opencontainers.image.title="Papra" \ org.opencontainers.image.authors="daemonless" \ io.daemonless.category="Productivity" \ io.daemonless.port="1221" \ - io.daemonless.volumes="/app-data" \ + io.daemonless.volumes="/app_data" \ io.daemonless.arch="${FREEBSD_ARCH}" \ io.daemonless.upstream-url="${UPSTREAM_URL}" \ io.daemonless.upstream-jq="${UPSTREAM_JQ}" \ @@ -205,7 +205,7 @@ LABEL org.opencontainers.image.title="Papra" \ RUN sed -i '' -e 's,/quarterly,/latest,' /etc/pkg/FreeBSD.conf && \ pkg update && \ pkg install -y ${PACKAGES} && \ - mkdir -p /app /app/public /app-data/db /app-data/documents /ingestion \ + mkdir -p /app /app/public /app_data/db /app_data/documents /ingestion \ /var/log/nginx /var/run /var/tmp/nginx && \ pkg clean -ay && \ rm -rf /var/cache/pkg/* /var/db/pkg/repos/* @@ -217,7 +217,7 @@ COPY --from=builder --chown=bsd:bsd /build/apps/papra-client/dist /app/public # Ownership — /app and /app/public must be world-readable so the nginx worker # (www user) can serve the static client files. -RUN chown -R bsd:bsd /app /app-data /ingestion && \ +RUN chown -R bsd:bsd /app /app_data /ingestion && \ chmod o+x /app && \ chmod -R o+rX /app/public @@ -236,9 +236,9 @@ ENV NODE_ENV=production \ PORT=1222 \ SERVER_HOSTNAME=127.0.0.1 \ SERVER_SERVE_PUBLIC_DIR=false \ - DATABASE_URL=file:/app-data/db/db.sqlite \ - DOCUMENT_STORAGE_FILESYSTEM_ROOT=/app-data/documents \ - PAPRA_CONFIG_DIR=/app-data \ + DATABASE_URL=file:/app_data/db/db.sqlite \ + DOCUMENT_STORAGE_FILESYSTEM_ROOT=/app_data/documents \ + PAPRA_CONFIG_DIR=/app_data \ INGESTION_FOLDER_ROOT=/ingestion \ EMAILS_DRY_RUN=true \ BETTER_AUTH_TELEMETRY=0 \ @@ -246,4 +246,4 @@ ENV NODE_ENV=production \ EXPOSE 1221 -VOLUME /app-data \ No newline at end of file +VOLUME /app_data \ No newline at end of file diff --git a/Containerfile.j2 b/Containerfile.j2 index 01bfeba..65c379b 100644 --- a/Containerfile.j2 +++ b/Containerfile.j2 @@ -187,7 +187,7 @@ LABEL org.opencontainers.image.title="Papra" \ org.opencontainers.image.authors="daemonless" \ io.daemonless.category="Productivity" \ io.daemonless.port="1221" \ - io.daemonless.volumes="/app-data" \ + io.daemonless.volumes="/app_data" \ io.daemonless.arch="${FREEBSD_ARCH}" \ io.daemonless.upstream-url="${UPSTREAM_URL}" \ io.daemonless.upstream-jq="${UPSTREAM_JQ}" \ @@ -199,7 +199,7 @@ LABEL org.opencontainers.image.title="Papra" \ RUN sed -i '' -e 's,/quarterly,/latest,' /etc/pkg/FreeBSD.conf && \ pkg update && \ pkg install -y ${PACKAGES} && \ - mkdir -p /app /app/public /app-data/db /app-data/documents /ingestion \ + mkdir -p /app /app/public /app_data/db /app_data/documents /ingestion \ /var/log/nginx /var/run /var/tmp/nginx && \ pkg clean -ay && \ rm -rf /var/cache/pkg/* /var/db/pkg/repos/* @@ -211,7 +211,7 @@ COPY --from=builder --chown=bsd:bsd /build/apps/papra-client/dist /app/public # Ownership — /app and /app/public must be world-readable so the nginx worker # (www user) can serve the static client files. -RUN chown -R bsd:bsd /app /app-data /ingestion && \ +RUN chown -R bsd:bsd /app /app_data /ingestion && \ chmod o+x /app && \ chmod -R o+rX /app/public @@ -230,9 +230,9 @@ ENV NODE_ENV=production \ PORT=1222 \ SERVER_HOSTNAME=127.0.0.1 \ SERVER_SERVE_PUBLIC_DIR=false \ - DATABASE_URL=file:/app-data/db/db.sqlite \ - DOCUMENT_STORAGE_FILESYSTEM_ROOT=/app-data/documents \ - PAPRA_CONFIG_DIR=/app-data \ + DATABASE_URL=file:/app_data/db/db.sqlite \ + DOCUMENT_STORAGE_FILESYSTEM_ROOT=/app_data/documents \ + PAPRA_CONFIG_DIR=/app_data \ INGESTION_FOLDER_ROOT=/ingestion \ EMAILS_DRY_RUN=true \ BETTER_AUTH_TELEMETRY=0 \ @@ -240,4 +240,4 @@ ENV NODE_ENV=production \ EXPOSE 1221 -VOLUME /app-data +VOLUME /app_data diff --git a/README.md b/README.md index 649ee00..1e38aee 100644 --- a/README.md +++ b/README.md @@ -43,16 +43,16 @@ services: - PORT=1222 # Internal node backend port (nginx proxies to it); leave as 1222 - SERVER_HOSTNAME=127.0.0.1 # Internal bind address for the node backend; leave as 127.0.0.1 - SERVER_SERVE_PUBLIC_DIR=false # Whether the node backend serves the SPA itself; 'false' (nginx serves it) - - DATABASE_URL=file:/app-data/db/db.sqlite # SQLite database URL (file:/app-data/db/db.sqlite) - - DOCUMENT_STORAGE_FILESYSTEM_ROOT=/app-data/documents # Filesystem path where uploaded documents are stored (under the /app-data volume) - - PAPRA_CONFIG_DIR=/app-data # Directory Papra reads its config from (under the /app-data volume) + - DATABASE_URL=file:/app_data/db/db.sqlite # SQLite database URL (file:/app_data/db/db.sqlite) + - DOCUMENT_STORAGE_FILESYSTEM_ROOT=/app_data/documents # Filesystem path where uploaded documents are stored (under the /app_data volume) + - PAPRA_CONFIG_DIR=/app_data # Directory Papra reads its config from (under the /app_data volume) - INGESTION_FOLDER_ROOT=/ingestion # Watched folder for drop-in document ingestion - EMAILS_DRY_RUN=true # If 'true', emails are logged instead of sent (no SMTP configured by default) - BETTER_AUTH_TELEMETRY=0 # better-auth telemetry; '0' disables it - - AUTH_SECRET=${PAPRA_AUTH_SECRET} # better-auth session signing secret, >=32 chars. Optional: if unset, the container generates a strong secret on first boot and persists it under /app-data. Set one you control with `openssl rand -hex 48` to manage it yourself. + - AUTH_SECRET=${PAPRA_AUTH_SECRET} # better-auth session signing secret, >=32 chars. Optional: if unset, the container generates a strong secret on first boot and persists it under /app_data. Set one you control with `openssl rand -hex 48` to manage it yourself. - AUTH_IS_REGISTRATION_ENABLED=true # Set to false after creating your account to lock down signups volumes: - - "/path/to/containers/papra/app-data:/app-data" + - "/path/to/containers/papra/app_data:/app_data" restart: unless-stopped ``` @@ -69,9 +69,9 @@ NODE_ENV=production PORT=1222 SERVER_HOSTNAME=127.0.0.1 SERVER_SERVE_PUBLIC_DIR=false -DATABASE_URL=file:/app-data/db/db.sqlite -DOCUMENT_STORAGE_FILESYSTEM_ROOT=/app-data/documents -PAPRA_CONFIG_DIR=/app-data +DATABASE_URL=file:/app_data/db/db.sqlite +DOCUMENT_STORAGE_FILESYSTEM_ROOT=/app_data/documents +PAPRA_CONFIG_DIR=/app_data INGESTION_FOLDER_ROOT=/ingestion EMAILS_DRY_RUN=true BETTER_AUTH_TELEMETRY=0 @@ -109,10 +109,10 @@ services: - AUTH_SECRET: !ENV '${AUTH_SECRET}' - AUTH_IS_REGISTRATION_ENABLED: !ENV '${AUTH_IS_REGISTRATION_ENABLED}' volumes: - - papra_app-data: /app-data + - papra_app_data: /app_data volumes: - papra_app-data: - device: '/path/to/containers/papra/app-data' + papra_app_data: + device: '/path/to/containers/papra/app_data' ``` **Makejail**: @@ -135,15 +135,15 @@ podman run -d --name papra \ -e PORT=1222 \ -e SERVER_HOSTNAME=127.0.0.1 \ -e SERVER_SERVE_PUBLIC_DIR=false \ - -e DATABASE_URL=file:/app-data/db/db.sqlite \ - -e DOCUMENT_STORAGE_FILESYSTEM_ROOT=/app-data/documents \ - -e PAPRA_CONFIG_DIR=/app-data \ + -e DATABASE_URL=file:/app_data/db/db.sqlite \ + -e DOCUMENT_STORAGE_FILESYSTEM_ROOT=/app_data/documents \ + -e PAPRA_CONFIG_DIR=/app_data \ -e INGESTION_FOLDER_ROOT=/ingestion \ -e EMAILS_DRY_RUN=true \ -e BETTER_AUTH_TELEMETRY=0 \ -e AUTH_SECRET=${PAPRA_AUTH_SECRET} \ -e AUTH_IS_REGISTRATION_ENABLED=true \ - -v /path/to/containers/papra/app-data:/app-data \ + -v /path/to/containers/papra/app_data:/app_data \ ghcr.io/daemonless/papra:latest ``` @@ -164,16 +164,16 @@ podman run -d --name papra \ PORT: "1222" SERVER_HOSTNAME: "127.0.0.1" SERVER_SERVE_PUBLIC_DIR: "false" - DATABASE_URL: "file:/app-data/db/db.sqlite" - DOCUMENT_STORAGE_FILESYSTEM_ROOT: "/app-data/documents" - PAPRA_CONFIG_DIR: "/app-data" + DATABASE_URL: "file:/app_data/db/db.sqlite" + DOCUMENT_STORAGE_FILESYSTEM_ROOT: "/app_data/documents" + PAPRA_CONFIG_DIR: "/app_data" INGESTION_FOLDER_ROOT: "/ingestion" EMAILS_DRY_RUN: "true" BETTER_AUTH_TELEMETRY: "0" AUTH_SECRET: "${PAPRA_AUTH_SECRET}" AUTH_IS_REGISTRATION_ENABLED: "true" volumes: - - "/path/to/containers/papra/app-data:/app-data" + - "/path/to/containers/papra/app_data:/app_data" ``` ## Parameters @@ -189,20 +189,20 @@ podman run -d --name papra \ | `PORT` | `1222` | Internal node backend port (nginx proxies to it); leave as 1222 | | `SERVER_HOSTNAME` | `127.0.0.1` | Internal bind address for the node backend; leave as 127.0.0.1 | | `SERVER_SERVE_PUBLIC_DIR` | `false` | Whether the node backend serves the SPA itself; 'false' (nginx serves it) | -| `DATABASE_URL` | `file:/app-data/db/db.sqlite` | SQLite database URL (file:/app-data/db/db.sqlite) | -| `DOCUMENT_STORAGE_FILESYSTEM_ROOT` | `/app-data/documents` | Filesystem path where uploaded documents are stored (under the /app-data volume) | -| `PAPRA_CONFIG_DIR` | `/app-data` | Directory Papra reads its config from (under the /app-data volume) | +| `DATABASE_URL` | `file:/app_data/db/db.sqlite` | SQLite database URL (file:/app_data/db/db.sqlite) | +| `DOCUMENT_STORAGE_FILESYSTEM_ROOT` | `/app_data/documents` | Filesystem path where uploaded documents are stored (under the /app_data volume) | +| `PAPRA_CONFIG_DIR` | `/app_data` | Directory Papra reads its config from (under the /app_data volume) | | `INGESTION_FOLDER_ROOT` | `/ingestion` | Watched folder for drop-in document ingestion | | `EMAILS_DRY_RUN` | `true` | If 'true', emails are logged instead of sent (no SMTP configured by default) | | `BETTER_AUTH_TELEMETRY` | `0` | better-auth telemetry; '0' disables it | -| `AUTH_SECRET` | `${PAPRA_AUTH_SECRET}` | better-auth session signing secret, >=32 chars. Optional: if unset, the container generates a strong secret on first boot and persists it under /app-data. Set one you control with `openssl rand -hex 48` to manage it yourself. | +| `AUTH_SECRET` | `${PAPRA_AUTH_SECRET}` | better-auth session signing secret, >=32 chars. Optional: if unset, the container generates a strong secret on first boot and persists it under /app_data. Set one you control with `openssl rand -hex 48` to manage it yourself. | | `AUTH_IS_REGISTRATION_ENABLED` | `true` | Set to false after creating your account to lock down signups | ### Volumes | Path | Description | |------|-------------| -| `/app-data` | Application data — SQLite database, stored documents, and config | +| `/app_data` | Application data — SQLite database, stored documents, and config | **Architectures:** amd64 **User:** `bsd` (UID/GID via PUID/PGID, defaults to 1000:1000) diff --git a/compose.yaml b/compose.yaml index 74ddf39..7862559 100644 --- a/compose.yaml +++ b/compose.yaml @@ -17,20 +17,20 @@ x-daemonless: PUID: "User ID for the application process" PGID: "Group ID for the application process" TZ: "Timezone for the container" - AUTH_SECRET: "better-auth session signing secret, >=32 chars. Optional: if unset, the container generates a strong secret on first boot and persists it under /app-data. Set one you control with `openssl rand -hex 48` to manage it yourself." - DATABASE_URL: "SQLite database URL (file:/app-data/db/db.sqlite)" + AUTH_SECRET: "better-auth session signing secret, >=32 chars. Optional: if unset, the container generates a strong secret on first boot and persists it under /app_data. Set one you control with `openssl rand -hex 48` to manage it yourself." + DATABASE_URL: "SQLite database URL (file:/app_data/db/db.sqlite)" AUTH_IS_REGISTRATION_ENABLED: "Set to false after creating your account to lock down signups" NODE_ENV: "Node runtime mode; leave as 'production'" PORT: "Internal node backend port (nginx proxies to it); leave as 1222" SERVER_HOSTNAME: "Internal bind address for the node backend; leave as 127.0.0.1" SERVER_SERVE_PUBLIC_DIR: "Whether the node backend serves the SPA itself; 'false' (nginx serves it)" - DOCUMENT_STORAGE_FILESYSTEM_ROOT: "Filesystem path where uploaded documents are stored (under the /app-data volume)" - PAPRA_CONFIG_DIR: "Directory Papra reads its config from (under the /app-data volume)" + DOCUMENT_STORAGE_FILESYSTEM_ROOT: "Filesystem path where uploaded documents are stored (under the /app_data volume)" + PAPRA_CONFIG_DIR: "Directory Papra reads its config from (under the /app_data volume)" INGESTION_FOLDER_ROOT: "Watched folder for drop-in document ingestion" EMAILS_DRY_RUN: "If 'true', emails are logged instead of sent (no SMTP configured by default)" BETTER_AUTH_TELEMETRY: "better-auth telemetry; '0' disables it" volumes: - /app-data: "Application data — SQLite database, stored documents, and config" + /app_data: "Application data — SQLite database, stored documents, and config" ports: 1221: "Web UI (nginx serving the SPA + reverse-proxying /api/ to the node backend)" @@ -50,17 +50,17 @@ services: - PORT=1222 - SERVER_HOSTNAME=127.0.0.1 - SERVER_SERVE_PUBLIC_DIR=false - - DATABASE_URL=file:/app-data/db/db.sqlite - - DOCUMENT_STORAGE_FILESYSTEM_ROOT=/app-data/documents - - PAPRA_CONFIG_DIR=/app-data + - DATABASE_URL=file:/app_data/db/db.sqlite + - DOCUMENT_STORAGE_FILESYSTEM_ROOT=/app_data/documents + - PAPRA_CONFIG_DIR=/app_data - INGESTION_FOLDER_ROOT=/ingestion - EMAILS_DRY_RUN=true - BETTER_AUTH_TELEMETRY=0 # Optional: a secret you control (>=32 chars). If omitted, the container - # generates one on first boot and persists it under /app-data (secure-by-default). + # generates one on first boot and persists it under /app_data (secure-by-default). - AUTH_SECRET=${PAPRA_AUTH_SECRET} # Lock down registration after you create the first (admin) account. - AUTH_IS_REGISTRATION_ENABLED=true volumes: - - ./app-data:/app-data + - ./app_data:/app_data diff --git a/root/etc/cont-init.d/20-papra b/root/etc/cont-init.d/20-papra index 2b93fdf..461ba7c 100755 --- a/root/etc/cont-init.d/20-papra +++ b/root/etc/cont-init.d/20-papra @@ -1,7 +1,7 @@ #!/bin/sh echo "[init] Initializing Papra..." -mkdir -p /app-data/db /app-data/documents /ingestion -chown -R bsd:bsd /app-data /ingestion +mkdir -p /app_data/db /app_data/documents /ingestion +chown -R bsd:bsd /app_data /ingestion echo "[init] Done" diff --git a/root/etc/services.d/papra-server/run b/root/etc/services.d/papra-server/run index e253e8d..04ff591 100755 --- a/root/etc/services.d/papra-server/run +++ b/root/etc/services.d/papra-server/run @@ -22,10 +22,10 @@ NODE_FLAGS="--import temporal-polyfill/global" # Otherwise generate a strong random secret ONCE and persist it under the data volume # so sessions survive restarts — keeps the image secure-by-default and bootable # standalone (no hardcoded secret shipped; also lets CIT run the bare image). -SECRET_FILE=/app-data/.auth_secret +SECRET_FILE=/app_data/.auth_secret if [ -z "${AUTH_SECRET:-}" ]; then if [ ! -s "$SECRET_FILE" ]; then - mkdir -p /app-data + mkdir -p /app_data $NODE -e 'process.stdout.write(require("crypto").randomBytes(48).toString("hex"))' > "$SECRET_FILE" chmod 600 "$SECRET_FILE" chown bsd:bsd "$SECRET_FILE" 2>/dev/null || true