diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..97d8ef1 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,19 @@ +node_modules +.next +.git +.gitignore +.env +.env.local +.env.*.local +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.DS_Store +README.md +Dockerfile +.dockerignore +docker-compose.yml +docker-compose.*.yml +memory +request.json +*.log diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..ac6e80a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,37 @@ +## syntax=docker/dockerfile:1.7 + +# ---- deps ---- +FROM node:22-alpine AS deps +RUN apk add --no-cache libc6-compat +WORKDIR /app +COPY package.json package-lock.json* ./ +RUN npm ci --no-audit --no-fund + +# ---- build ---- +FROM node:22-alpine AS builder +WORKDIR /app +COPY --from=deps /app/node_modules ./node_modules +COPY . . +ENV NEXT_TELEMETRY_DISABLED=1 +RUN npm run build + +# ---- runner ---- +FROM node:22-alpine AS runner +WORKDIR /app +ENV NODE_ENV=production +ENV NEXT_TELEMETRY_DISABLED=1 +ENV PORT=3000 +ENV HOSTNAME=0.0.0.0 + +RUN addgroup --system --gid 1001 nodejs \ + && adduser --system --uid 1001 nextjs + +# Standalone output copies only what's needed at runtime. +COPY --from=builder /app/public ./public +COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ +COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static + +USER nextjs +EXPOSE 3000 + +CMD ["node", "server.js"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..83a8977 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,58 @@ +## Portainer stack for dndextended. +## Env vars come from Portainer stack env or a .env file in the same dir. +## +## Required env: +## MONGODB_URI - mongodb://mongo:27017/dndextended (or external cluster) +## AUTH_SECRET - openssl rand -base64 32 +## AUTH_URL - public URL (https://dnd.example.com) +## AUTH_TRUST_HOST - true (behind Traefik/nginx/Pinggy) +## +## Optional: +## MONGO_ROOT_USER, MONGO_ROOT_PASSWORD - if you want mongo auth (recommended in prod) + +services: + app: + build: + context: . + dockerfile: Dockerfile + image: dndextended:latest + container_name: dndextended-app + restart: unless-stopped + ports: + - "${APP_PORT:-3000}:3000" + environment: + NODE_ENV: production + MONGODB_URI: ${MONGODB_URI:-mongodb://mongo:27017/dndextended} + AUTH_SECRET: ${AUTH_SECRET} + AUTH_URL: ${AUTH_URL} + AUTH_TRUST_HOST: ${AUTH_TRUST_HOST:-true} + depends_on: + mongo: + condition: service_healthy + networks: + - dnd + + mongo: + image: mongo:7 + container_name: dndextended-mongo + restart: unless-stopped + volumes: + - mongo_data:/data/db + environment: + MONGO_INITDB_ROOT_USERNAME: ${MONGO_ROOT_USER:-} + MONGO_INITDB_ROOT_PASSWORD: ${MONGO_ROOT_PASSWORD:-} + healthcheck: + test: ["CMD", "mongosh", "--quiet", "--eval", "db.adminCommand('ping').ok"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 20s + networks: + - dnd + +volumes: + mongo_data: + +networks: + dnd: + driver: bridge diff --git a/next.config.ts b/next.config.ts index bd7c7c9..ead555b 100644 --- a/next.config.ts +++ b/next.config.ts @@ -1,8 +1,8 @@ import type { NextConfig } from "next"; const nextConfig: NextConfig = { - /* config options here */ - devIndicators: false + devIndicators: false, + output: "standalone", }; export default nextConfig;