Archived
deploy: Dockerfile, entrypoint, standalone output, dockerignore
This commit is contained in:
@@ -0,0 +1,15 @@
|
|||||||
|
node_modules
|
||||||
|
.next
|
||||||
|
.git
|
||||||
|
.gitignore
|
||||||
|
env.d.ts
|
||||||
|
env.example
|
||||||
|
prisma/dev.db
|
||||||
|
prisma/fresh.db*
|
||||||
|
prisma/dev.db-journal
|
||||||
|
prisma/dev.db-shm
|
||||||
|
prisma/dev.db-wal
|
||||||
|
*.tar.gz
|
||||||
|
*.log
|
||||||
|
Dockerfile
|
||||||
|
.dockerignore
|
||||||
+66
@@ -0,0 +1,66 @@
|
|||||||
|
# MapleBrief — production image
|
||||||
|
# Multi-stage: deps -> build -> minimal runner
|
||||||
|
# (Debian base: Prisma engines need glibc; Alpine breaks the schema/query engine.)
|
||||||
|
#
|
||||||
|
# Build args / secrets:
|
||||||
|
# NEXT_PUBLIC_ADSENSE_CLIENT_ID — AdSense client id baked into the build
|
||||||
|
# (empty -> ads hidden, app still works)
|
||||||
|
# Runtime env:
|
||||||
|
# ADMIN_API_KEY — admin/auth key (fail-closed 401 if empty)
|
||||||
|
# OLLAMA_BASE / provider — LLM endpoints (or configure in admin UI)
|
||||||
|
# DATABASE_URL defaults to file:/data/dev.db (volume-mounted)
|
||||||
|
|
||||||
|
# Optional: bake the real AdSense client id at build time (empty -> ads hidden)
|
||||||
|
ARG NEXT_PUBLIC_ADSENSE_CLIENT_ID=""
|
||||||
|
|
||||||
|
FROM node:22-slim AS deps
|
||||||
|
WORKDIR /app
|
||||||
|
RUN apt-get update -qq && apt-get install -yq --no-install-recommends openssl ca-certificates > /dev/null && rm -rf /var/lib/apt/lists/*
|
||||||
|
COPY package.json package-lock.json ./
|
||||||
|
RUN npm ci --no-audit --no-fund
|
||||||
|
|
||||||
|
FROM node:22-slim AS build
|
||||||
|
WORKDIR /app
|
||||||
|
# inherit the global value (set via --build-arg); empty -> placeholder ads
|
||||||
|
ARG NEXT_PUBLIC_ADSENSE_CLIENT_ID
|
||||||
|
RUN apt-get update -qq && apt-get install -yq --no-install-recommends openssl ca-certificates > /dev/null && rm -rf /var/lib/apt/lists/*
|
||||||
|
# Absolute path avoids Prisma resolving relative SQLite URLs against the
|
||||||
|
# schema dir (which would double up into prisma/prisma/...).
|
||||||
|
ENV DATABASE_URL="file:/app/fresh.db"
|
||||||
|
COPY --from=deps /app/node_modules ./node_modules
|
||||||
|
COPY . .
|
||||||
|
# Verify migrations apply to a fresh DB, then stage the migrated empty DB at
|
||||||
|
# the exact path the runner copies.
|
||||||
|
RUN npx prisma generate \
|
||||||
|
&& npx prisma migrate deploy \
|
||||||
|
&& cp /app/fresh.db prisma/fresh.db \
|
||||||
|
&& NEXT_PUBLIC_SITE_URL="https://news.krisforbes.ca" \
|
||||||
|
NEXT_PUBLIC_SITE_NAME="MapleBrief" \
|
||||||
|
NEXT_PUBLIC_SITE_DESCRIPTION="Synthesized Canadian news briefings" \
|
||||||
|
NEXT_PUBLIC_ADSENSE_CLIENT_ID="${NEXT_PUBLIC_ADSENSE_CLIENT_ID}" \
|
||||||
|
NEXT_PUBLIC_SHOW_SIDEBAR_ADS="false" \
|
||||||
|
npm run build \
|
||||||
|
&& rm -f /app/fresh.db prisma/fresh.db-journal prisma/fresh.db-shm
|
||||||
|
# (prisma/fresh.db kept above for the runner stage copy)
|
||||||
|
|
||||||
|
FROM node:22-slim AS runner
|
||||||
|
WORKDIR /app
|
||||||
|
RUN apt-get update -qq && apt-get install -yq --no-install-recommends curl > /dev/null && rm -rf /var/lib/apt/lists/*
|
||||||
|
# runtime user (guard: node slim images don't always ship one)
|
||||||
|
RUN id app 2>/dev/null || useradd -m -s /bin/sh app
|
||||||
|
# pre-create the data dir (volume replaces it at runtime) with app ownership
|
||||||
|
RUN mkdir -p /data && chown -R app:app /data
|
||||||
|
USER app
|
||||||
|
# Next standalone server
|
||||||
|
COPY --chown=app:app --from=build /app/.next/standalone ./
|
||||||
|
# static chunks + public assets (standalone does not auto-copy these)
|
||||||
|
COPY --chown=app:app --from=build /app/.next/static ./.next/static
|
||||||
|
COPY --chown=app:app --from=build /app/public ./public
|
||||||
|
# pre-migrated clean database snapshot (entrypoint copies it to /data on first boot)
|
||||||
|
COPY --chown=app:app --from=build /app/prisma/fresh.db ./seed-dev.db
|
||||||
|
COPY --chown=app:app entrypoint.sh ./entrypoint.sh
|
||||||
|
RUN chmod +x entrypoint.sh
|
||||||
|
ENV PORT=3000
|
||||||
|
ENV DATABASE_URL="file:/data/dev.db"
|
||||||
|
EXPOSE 3000
|
||||||
|
ENTRYPOINT ["./entrypoint.sh"]
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# MapleBrief entrypoint
|
||||||
|
# 1) First boot: seed /data with the clean migrated DB + write privileged key if provided
|
||||||
|
# 2) Start Next standalone server
|
||||||
|
set -e
|
||||||
|
cd /app
|
||||||
|
|
||||||
|
DB="${DATABASE_URL#file:}"
|
||||||
|
[ -n "$DB" ] || DB=/data/dev.db
|
||||||
|
|
||||||
|
# Export an absolute DATABASE_URL for the Node/Prisma process (relative
|
||||||
|
# paths resolve against the schema dir and can point at the wrong file).
|
||||||
|
case "$DB" in
|
||||||
|
/*) ;;
|
||||||
|
*) DB="/$DB" ;;
|
||||||
|
esac
|
||||||
|
export DATABASE_URL="file:$DB"
|
||||||
|
|
||||||
|
if [ ! -f "$DB" ]; then
|
||||||
|
# create parent dir (volume may be fresh)
|
||||||
|
DIR="$(dirname "$DB")"
|
||||||
|
mkdir -p "$DIR"
|
||||||
|
cp ./seed-dev.db "$DB"
|
||||||
|
echo "[entrypoint] initialized $DB from seed snapshot"
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec node server.js
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
/** @type {import('next').NextConfig} */
|
/** @type {import('next').NextConfig} */
|
||||||
const nextConfig = {
|
const nextConfig = {
|
||||||
reactStrictMode: true,
|
reactStrictMode: true,
|
||||||
|
// Minimal Docker image: the runner stage copies .next/standalone.
|
||||||
|
output: 'standalone',
|
||||||
// RSS/Google AdSense scripts are injected safely by our own client
|
// RSS/Google AdSense scripts are injected safely by our own client
|
||||||
// components (see src/components/ads). Keep lint from failing the build
|
// components (see src/components/ads). Keep lint from failing the build
|
||||||
// on un-stulated style warnings while keeping full type checking on.
|
// on un-stulated style warnings while keeping full type checking on.
|
||||||
|
|||||||
Reference in New Issue
Block a user