Dockerfile
Rama main · réplica de lectura del repositorio original.
# Debian-based (not alpine) — argon2 and sharp ship native bindings that are
# more reliably prebuilt for glibc than musl, and image size isn't a priority
# for a self-hosted single-instance app.
#
# Postgres runs inside this same image/container (not a separate one) so a
# self-hoster only has one thing to install and manage — appropriate for a
# single-user appliance-style app, even though it trades away the usual
# one-process-per-container Docker convention.
FROM node:22-bookworm-slim AS base
# Ties the published image back to this repo, which is what makes it show up
# under the repository's Packages on GitHub.
LABEL org.opencontainers.image.source="https://github.com/TimmyAmant/marquee" \
org.opencontainers.image.description="Self-hosted media dashboard for Plex/Jellyfin/Sonarr/Radarr, with a native macOS client." \
org.opencontainers.image.licenses="MIT"
# Pinned to a specific major version (rather than the bare "postgresql"
# package, whose version tracks whatever Debian bookworm currently
# defaults to) so a future rebuild never silently ends up with a server
# version that can't read data directories from earlier installs — bump
# this deliberately, alongside a documented migration path, not by accident.
#
# gosu is how entrypoint.sh drops from root (which it needs to run Postgres
# as the postgres user) to the unprivileged `node` user for the app itself.
RUN apt-get update && apt-get install -y --no-install-recommends postgresql-15 gosu \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
# Install dependencies separately so this layer is cached across rebuilds
# that only change application code.
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
# `next build` imports every route module (including lib/db/client.ts, which
# requires DATABASE_URL to be set) to collect page data, but never actually
# queries the database during that step — postgres-js connects lazily on
# first query. This placeholder only needs to exist, never to be reachable;
# the real DATABASE_URL is built at container startup by entrypoint.sh.
ENV DATABASE_URL="postgres://build:build@build-time-placeholder:5432/build"
# The app runs as `node`, and Next.js writes to .next at runtime (the image
# optimizer's and fetch() caches) — so .next is the one part of the app it
# owns. Chowned in the same layer as the build so it isn't stored twice.
RUN npm run build && chown -R node:node .next
ENV NODE_ENV=production
EXPOSE 3000
# Settings › Logs keeps a rolling copy of the server's log here
# (lib/logs/capture.ts), so a restart doesn't lose it. Mount a folder on it
# (Unraid's template and docker-compose.yml do) and it survives the container
# being recreated too; without one it lasts as long as the container.
ENV MARQUEE_LOG_DIR=/var/log/marquee
RUN mkdir -p /var/log/marquee && chown node:node /var/log/marquee
COPY entrypoint.sh /app/entrypoint.sh
RUN chmod +x /app/entrypoint.sh
ENTRYPOINT ["/app/entrypoint.sh"]
CMD ["npm", "run", "start"]