Docker & Docker Compose
Nuxt-Apps containerisieren und mit Services orchestrieren
Warum Docker?
Docker sorgt dafür, dass deine Nuxt-App überall gleich läuft — auf deinem Laptop, im CI/CD und in Produktion. Keine "Funktioniert bei mir"-Probleme mehr.
Rails-Vergleich
Wenn du Rails mit Docker deployest, kennst du das Pattern bereits: Multi-Stage Build, Produktions-Image mit minimaler Größe, Docker Compose für App + Datenbank. Das Vorgehen für Nuxt ist sehr ähnlich — nur ohne Datenbank-Container (es sei denn, du brauchst einen).
Dockerfile für Nuxt SSR
# ============================================
# Stage 1: Dependencies installieren
# ============================================
FROM node:20-alpine AS deps
WORKDIR /app
# Nur Package-Dateien kopieren (Cache-optimiert)
COPY package.json package-lock.json ./
# Dependencies installieren
RUN npm ci
# ============================================
# Stage 2: Build
# ============================================
FROM node:20-alpine AS builder
WORKDIR /app
# Dependencies aus Stage 1 übernehmen
COPY --from=deps /app/node_modules ./node_modules
COPY . .
# Nuxt-App bauen
RUN npm run build
# ============================================
# Stage 3: Produktions-Image
# ============================================
FROM node:20-alpine AS runner
WORKDIR /app
# Nur den Build-Output kopieren
COPY --from=builder /app/.output ./.output
# Nicht als Root laufen
RUN addgroup --system --gid 1001 nuxt && \\
adduser --system --uid 1001 nuxt
USER nuxt
# Port und Host setzen
ENV HOST=0.0.0.0
ENV PORT=3000
EXPOSE 3000
# Health-Check
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s \\
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/api/health || exit 1
# Server starten
CMD ["node", ".output/server/index.mjs"]Multi-Stage Build Vorteile
- Kleineres Image — nur der Build-Output wird kopiert (~100 MB statt ~800 MB)
- Besseres Caching — Dependencies werden separat gecacht
- Sicherheit — keine Dev-Dependencies im Produktions-Image
.dockerignore
Verhindere, dass unnötige Dateien in den Build-Kontext kopiert werden:
node_modules
.output
.nuxt
dist
.git
.gitignore
*.md
.env
.env.*
docker-compose*.yml
Dockerfile*Docker Compose: Nuxt + json-server
Für eine vollständige Entwicklungs- und Produktionsumgebung orchestrierst du Nuxt und json-server mit Docker Compose:
services:
# ─── Nuxt App ───────────────────────────
nuxt:
build:
context: .
dockerfile: Dockerfile
ports:
- '3000:3000'
environment:
- NODE_ENV=production
- NUXT_PUBLIC_API_BASE=http://json-server:3001
depends_on:
json-server:
condition: service_healthy
restart: unless-stopped
healthcheck:
test: ['CMD', 'wget', '--spider', '-q', 'http://localhost:3000']
interval: 30s
timeout: 5s
retries: 3
start_period: 15s
# ─── json-server (Mock-Backend) ─────────
json-server:
image: node:20-alpine
working_dir: /data
command: >
sh -c 'npm install -g json-server &&
json-server --watch db.json --port 3001 --host 0.0.0.0'
ports:
- '3001:3001'
volumes:
- ./db.json:/data/db.json
restart: unless-stopped
healthcheck:
test: ['CMD', 'wget', '--spider', '-q', 'http://localhost:3001']
interval: 10s
timeout: 3s
retries: 5
start_period: 20s# Alles starten
docker compose up -d
# Logs anschauen
docker compose logs -f nuxt
# Nur json-server neu starten
docker compose restart json-server
# Alles stoppen und aufräumen
docker compose downUmgebungsvariablen in Docker
# Nuxt Runtime-Konfiguration
NUXT_PUBLIC_API_BASE=http://localhost:3001
NUXT_PUBLIC_APP_NAME=Kontakte-Manager
# Server-seitige Secrets
NUXT_JWT_SECRET=mein-geheimer-schluessel-hier
NUXT_SESSION_SECRET=noch-ein-geheimes-secretexport default defineNuxtConfig({
runtimeConfig: {
// Server-seitig (nicht im Client sichtbar!)
jwtSecret: process.env.NUXT_JWT_SECRET || 'dev-fallback',
sessionSecret: process.env.NUXT_SESSION_SECRET || 'dev-fallback',
public: {
// Im Client und Server verfügbar
apiBase: process.env.NUXT_PUBLIC_API_BASE || 'http://localhost:3001',
appName: process.env.NUXT_PUBLIC_APP_NAME || 'Meine App'
}
}
})Secrets in Docker
- Nutze .env-Dateien nur lokal — nicht ins Git-Repo!
- In Produktion: Secrets über die Hosting-Platform setzen
- Variablen ohne
NUXT_PUBLIC_sind nur serverseitig - Docker Compose:
env_file: .envoder direktenvironment:
Health Checks
Ein Health-Check-Endpunkt zeigt, ob deine App korrekt läuft. Docker und Orchestratoren nutzen ihn zum Monitoring:
export default defineEventHandler(() => {
return {
status: 'ok',
timestamp: new Date().toISOString(),
uptime: process.uptime(),
version: process.env.npm_package_version || 'unknown',
environment: "production" || 'development'
}
})# Im Dockerfile:
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s \\
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/api/health || exit 1
# Docker prüft regelmäßig:
# - interval: Alle 30 Sekunden
# - timeout: Maximal 3 Sekunden warten
# - start-period: 10 Sekunden Wartezeit nach Container-Start
# - retries: 3 (Standard) fehlgeschlagene Versuche = unhealthyHealth-Check Status
- starting — Container startet gerade (start-period)
- healthy — Health-Check erfolgreich
- unhealthy — Mehrere fehlgeschlagene Checks
Mit docker ps siehst du den Health-Status aller Container. depends_on: condition: service_healthy wartet auf einen gesunden Container, bevor abhängige Services starten.
Zusammenfassung
Docker-Checkliste
- Multi-Stage Build — Deps → Build → Runner (kleines Image)
- .dockerignore — node_modules, .output, .git ausschließen
- Docker Compose — Nuxt + json-server orchestrieren
- Umgebungsvariablen — NUXT_PUBLIC_ für Client, NUXT_ für Server
- Health Checks —
/api/healthEndpunkt + HEALTHCHECK - Non-Root User — Sicherheit: nicht als Root laufen