Keep cover volume aligned with configured path

This commit is contained in:
2026-08-09 23:53:33 +07:00
parent 7cddd4a563
commit ee5825b21c
5 changed files with 15 additions and 11 deletions
+1 -2
View File
@@ -26,8 +26,7 @@ POSTGRES_PASSWORD=changeme-generate-a-long-random-password
# DATABASE_URL=postgres://user:pass@host:5432/bookmarks?sslmode=require
# Directory inside bookmark-api for immutable, content-addressed Cover bytes.
# Compose seeds and mounts its named volume at /covers, so keep this value
# /covers in this deployment. Standalone backend runs may choose another path.
# Compose builds the image and mounts its named volume at this path.
COVER_DIR=/covers
# --- Prod override (Traefik) only ---
+2 -2
View File
@@ -53,8 +53,8 @@ POSTGRES_PASSWORD=<paste output of: openssl rand -hex 24>
# not run; it then replaces the URL built from POSTGRES_PASSWORD above.
# DATABASE_URL=postgres://user:pass@host:5432/bookmarks?sslmode=require
# Required path inside bookmark-api. Compose seeds and mounts the named
# cover-data volume at /covers, so keep this value /covers.
# Required path inside bookmark-api. Compose builds the image and mounts the
# named cover-data volume at this path.
COVER_DIR=/covers
# Required for the Traefik override. Both have no fallback — compose refuses
+1 -1
View File
@@ -42,7 +42,7 @@ covers are stored, so the library renders in full with the browser switched off.
| `OWNER_DISCORD_ID` | *(required)* | Discord user ID of the owner: seeded as the first Reader, owns every pre-registration bookmark, and is the only Reader who can revoke another's sessions. |
| `ALLOWED_ORIGINS` | Asura + Demonic + Comix + Kagane origins | Comma-separated CORS allowlist. |
| `DATABASE_URL` | *(required)* | Postgres connection URL, e.g. `postgres://bookmarks:…@postgres:5432/bookmarks?sslmode=disable`. Compose builds it from `POSTGRES_PASSWORD`. |
| `COVER_DIR` | *(required)* | Filesystem volume for immutable, content-addressed Cover bytes. Compose requires `/covers` and mounts `cover-data` there; standalone runs may choose another writable durable path. |
| `COVER_DIR` | *(required)* | Filesystem volume for immutable, content-addressed Cover bytes. Compose builds the image and mounts `cover-data` at this path; standalone runs may choose another writable durable path. |
| `PORT` | `8080` | Plain HTTP; TLS terminated by the proxy. |
| `BROWSER_WS_URL` | empty | CDP endpoint of the remote browser (`ws://<tailnet IP>:9222`), used to poll Kagane/Novelfull past their JS challenge and to fetch uncached Kagane covers. Must be an IP or `localhost` — Chrome's DevTools handler 500s any other Host header, MagicDNS names included. Unset disables both; stored covers still serve. |
| `DISCORD_CLIENT_ID` | *(required)* | Discord application credentials for the browser sign-in (ADR-0002). |
+4 -2
View File
@@ -2,6 +2,7 @@
# --- build stage: compile a static, CGO-free binary ---
FROM golang:1.26-alpine AS build
ARG COVER_DIR=/covers
WORKDIR /src
# Dependencies first for layer caching (changes rarely).
@@ -20,12 +21,13 @@ COPY internal/ ./internal/
RUN CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" -o /out/server .
# Create the source directory; runtime COPY sets ownership for the named volume.
RUN mkdir -p /covers
RUN mkdir -p "$COVER_DIR"
# --- runtime stage: distroless static, non-root ---
FROM gcr.io/distroless/static:nonroot
ARG COVER_DIR=/covers
WORKDIR /
COPY --from=build --chown=65532:65532 /covers /covers
COPY --from=build --chown=65532:65532 ${COVER_DIR} ${COVER_DIR}
COPY --from=build /out/server /server
EXPOSE 8080
USER nonroot:nonroot
+7 -4
View File
@@ -11,7 +11,10 @@
services:
bookmark-api:
build: ./backend
build:
context: ./backend
args:
COVER_DIR: ${COVER_DIR:?set COVER_DIR in .env}
image: bookmarkmanager-backend:latest
container_name: bookmark-api
restart: unless-stopped
@@ -26,8 +29,8 @@ services:
# The bookmarks database. Host is the compose service name; the password
# comes from .env so it is never committed.
DATABASE_URL: ${DATABASE_URL:-postgres://bookmarks:${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env}@postgres:5432/bookmarks?sslmode=disable}
# Required path inside the API. The image seeds ownership at /covers and
# the named volume below mounts there; keep COVER_DIR=/covers in .env.
# Required path inside the API. The build seeds ownership at this path
# and the named volume below mounts there.
COVER_DIR: ${COVER_DIR:?set COVER_DIR in .env}
PORT: "8080"
# Log timestamps only. Go's `log` stamps lines in local time, and this
@@ -84,7 +87,7 @@ services:
# is why a redeploy always ships the repo's script.
- ./userscript:/userscript:ro
# Content-addressed cover bytes survive API restarts and redeploys.
- cover-data:/covers
- cover-data:${COVER_DIR:?set COVER_DIR in .env}
# Bound to loopback only: the proxy (or curl during smoke test) reaches it,
# the public internet does not.
ports: