Weg von Vercel: Der vollständige Leitfaden zur Next.js Docker-Self-Hosting

Ende letzten Monats, wie üblich die Vercel-Abrechnung geöffnet. 47,32 $.
Kurz im Kopf gerechnet: Der Blog-Traffic stieg diesen Monat vielleicht um 20 % – warum verdoppelt sich die Rechnung? In den Details: Serverless-Function-Aufrufe – eine API-Route ohne sauberes Caching lief bei jedem Seiten-Reload dreimal.
Vercels Developer Experience ist wirklich angenehm: git push, automatisches Deployment, globales Edge-Netzwerk, viele Features out of the box. Sobald etwas Traffic kommt, steigen die Kosten sprunghaft. Der Pro-Plan für 20 $ ist nur der Einstieg – teuer werden die nutzungsbasierten Posten.
In dem Moment war klar: Zeit, das Projekt woanders hin zu verlagern.
Dieser Artikel dokumentiert die vollständige Migration eines Next.js-Projekts von Vercel zu Docker-Self-Hosting. Fallstricke, gelesene Docs und getestete Konfigurationen – alles hier zusammen. Wer Self-Hosting erwägt oder schon probiert hat und seltsame Probleme sieht (404 bei statischen Assets, kaputtes Streaming), findet hoffentlich Antworten.
Warum weg von Vercel?
Klarstellung vorweg: Vercel soll hier nicht schlechtgeredet werden. Für viele Szenarien bleibt es die beste Wahl – Enterprise-Projekte, globales Edge-Netzwerk oder Teams ohne Ops-Kapazität. Für persönliche Projekte und kleine Teams sind die Kosten aber spürbar.
Vercels Preismodell
Der Free-Tier wirkt großzügig: 100 GB Bandbreite, 1 Mio. Edge Requests. Für ein Projekt mit etwas Traffic reicht das schnell nicht. Mit Pro (20 $/Monat) beginnt erst der Einstieg:
- Serverless Function-Aufrufe: nach 1 Mio. nutzungsbasiert
- Edge-Function-Laufzeit: nach 1 Mio. GB-s zusätzliche Kosten
- Bildoptimierung: nach 5.000 Aufrufen pro Stück
- Bandbreite: nach 1 TB pro GB
Schwierig ist die Vorhersage. Eine schlecht gecachte API-Route oder aggressive Crawler lassen die Rechnung explodieren.
Wie viel spart Self-Hosting?
Rechenbeispiel: Das Projekt kostete auf Vercel etwa 35–50 $/Monat, trafficabhängig. Nach dem Umzug auf einen DigitalOcean-Server für 12 $/Monat:
- Server: 12 $/Monat (2 vCPU, 4 GB RAM – reicht für zwei bis drei Next.js-Apps)
- Cloudflare CDN: kostenlos (wird ohnehin genutzt)
- Zusatzspeicher: 0 $ (lokale Platte reicht)
Monatlich 25–40 $ Ersparnis, im Jahr 300–500 $. Entscheidend: fixe Kosten – keine Explosion bei Traffic-Spitzen.
Wann passt Self-Hosting?
Nicht für alle. Sinnvoll, wenn:
- ✅ Linux- und Docker-Grundlagen vorhanden
- ✅ Traffic relativ stabil, kein globales Edge-Netzwerk nötig
- ✅ 5–10 Minuten manuelles Deployment akzeptabel
- ✅ Budget knapp (Side Projects, frühe Startup-Phase)
Besser bei Vercel bleiben, wenn:
- ❌ Kein Ops-Know-how und keine Lust darauf
- ❌ Starke Traffic-Schwankungen, Auto-Scaling nötig
- ❌ Vercel Analytics, Edge Config usw. gebraucht werden
- ❌ Budget da, Entwicklungseffizienz wichtiger
Erst abwägen, dann handeln – nicht zum Sparen unnötig leiden.
Next.js Docker – Kernkonfiguration
Drei zentrale Punkte für Next.js mit Docker. Wenn diese sitzen, laufen die meisten Deployments stabil.
1. Standalone-Ausgabemodus
Der wichtigste Schritt. Standardmäßig erzeugt next build viele Dateien inklusive vollem node_modules – im Container riesig und langsam.
In next.config.js eine Zeile ergänzen:
/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'standalone',
}
module.exports = nextConfig
Nach npm run build liegt .next/standalone bereit:
server.js: Startskript- Reduziertes
node_modules: nur Laufzeit-Pakete - Anwendungscode
Wichtig: Standalone kopiert public und .next/static nicht automatisch. Beides muss manuell ins Standalone-Verzeichnis – sonst 404 für alle statischen Assets. Zwei Tage Debugging, bis das klar war.
2. Mehrstufiges Dockerfile
Das produktive Dockerfile mit Kommentaren:
# ============ Phase 1: Abhängigkeiten ============
FROM node:20-alpine AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app
# Nur Manifeste kopieren – Docker-Cache nutzen
COPY package.json package-lock.json ./
RUN npm ci
# ============ Phase 2: App bauen ============
FROM node:20-alpine AS builder
WORKDIR /app
# Abhängigkeiten und Quellcode
COPY --from=deps /app/node_modules ./node_modules
COPY . .
# Build-Umgebungsvariablen (falls nötig)
ENV NEXT_TELEMETRY_DISABLED=1
# Build
RUN npm run build
# ============ Phase 3: Produktion ============
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
# Nicht-Root-Benutzer (Sicherheit)
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
# public (statische Assets)
COPY --from=builder /app/public ./public
# Standalone-Ausgabe
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
# static (CSS/JS-Build-Artefakte)
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"
# Start
CMD ["node", "server.js"]
Kurz erklärt:
- Drei Phasen: Abhängigkeiten, Build, Laufzeit getrennt – finales Image nur mit Laufzeit-Dateien, von 1,5 GB auf 200 MB
COPY --from=builder /app/public: sonst kein favicon, robots.txtCOPY ./.next/static: ohne diese Zeile 404 für JS/CSS- Nicht-Root: Sicherheitsbest Practice – in Produktion nicht als root laufen
3. Fallstricke bei Umgebungsvariablen
Next.js unterscheidet zwei Arten:
- Build-Zeit: Präfix
NEXT_PUBLIC_, wird in den Code eingebaut - Laufzeit: serverseitig, z. B. Datenbank-URL
Im Standalone-Modus funktioniert runtimeConfig nicht. Offiziell empfohlen: App Router:
// app/api/example/route.ts
export async function GET() {
// Direkt aus process.env lesen
const dbUrl = process.env.DATABASE_URL
// ...
}
Umgebungsvariablen beim Docker-Start:
docker run -p 3000:3000 \
-e DATABASE_URL="postgres://..." \
-e API_KEY="xxx" \
your-image-name
Oder mit docker-compose.yml:
version: '3.8'
services:
nextjs:
image: your-image-name
ports:
- "3000:3000"
environment:
DATABASE_URL: "postgres://..."
API_KEY: "xxx"
restart: unless-stopped
Hinweis: NEXT_PUBLIC_* muss beim Build gesetzt sein – zur Laufzeit nicht änderbar. Dynamische Konfiguration nur über serverseitige Variablen.
Reverse Proxy – das Wichtigste
Den Next.js-Container direkt ins Internet stellen – besser nicht. Ungeschützte Node.js-Apps halten bei Angriffen und Slowloris nicht lange durch. Reverse Proxy ist Pflicht, kein Nice-to-have.
Warum ein Reverse Proxy?
- Sicherheit: bösartige Requests filtern, Rate Limiting, DDoS-Schutz
- HTTPS: zentral SSL-Zertifikate verwalten
- Mehrere Apps: eine Maschine, mehrere Projekte per Domain/Pfad
- Static-Cache: Entlastung des App-Servers
Hier: Nginx – stabil. Für einfachere Config: Caddy (automatisches HTTPS, weniger Boilerplate).
Nginx-Beispielkonfiguration
server {
listen 80;
server_name yourdomain.com;
# HTTPS erzwingen (wenn SSL konfiguriert)
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name yourdomain.com;
# SSL (Let's Encrypt)
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
# Reverse Proxy zum Next.js-Container
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
# Erforderliche Header
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Wichtig: Buffering aus – Streaming
proxy_buffering off;
proxy_cache off;
proxy_set_header X-Accel-Buffering no;
# WebSocket (falls nötig)
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# Static-Cache (optional, empfohlen)
location /_next/static/ {
proxy_pass http://localhost:3000;
proxy_cache_valid 200 60m;
add_header Cache-Control "public, max-age=3600, immutable";
}
}
Drei Pflicht-Einstellungen:
proxy_buffering off: sonst hängt StreamingX-Accel-Buffering: no: Nginx soll den Body nicht puffern- WebSocket: bei Socket.io oder Echtzeit –
Upgrade-Header setzen
Caddy – vereinfacht
Wenn Nginx zu viel Config ist:
yourdomain.com {
reverse_proxy localhost:3000 {
# Caddy puffert standardmäßig nicht
}
}
Fertig. Caddy holt und erneuert Let’s-Encrypt-Zertifikate automatisch.
Docker Compose mit Nginx
Nginx containerisieren erleichtert das Management:
version: '3.8'
services:
nextjs:
build: .
restart: unless-stopped
environment:
DATABASE_URL: "postgres://..."
# Nicht auf Host exposen – nur nginx
expose:
- "3000"
networks:
- app-network
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf
- ./certs:/etc/letsencrypt
depends_on:
- nextjs
networks:
- app-network
networks:
app-network:
driver: bridge
Bei nextjs: expose statt ports – nur Container im gleichen Netz erreichen den Dienst, sicherer.
Streaming-Rendering reparieren
Ein ganzer Tag Debugging: Lokal lief der KI-Chat mit Streaming, in Docker kam alles auf einmal oder hing.
Symptome
Typisch:
- OpenAI-/Anthropic-Streaming antwortet nicht
- Server-Sent Events (SSE) ohne Echtzeit-Push
- Seite aktualisiert plötzlich, kein Wort-für-Wort-Output
Lokal mit npm run dev normal – in Produktion kaputt.
Ursachen
Zwei häufige Stellen:
- Reverse-Proxy-Buffering: Nginx puffert standardmäßig, bis der Body vollständig ist
- Next.js Runtime: API-Routen ohne Edge Runtime unterstützen Streaming manchmal nicht
Lösung 1: Nginx
Die drei Zeilen aus dem Reverse-Proxy-Kapitel noch einmal:
proxy_buffering off;
proxy_cache off;
proxy_set_header X-Accel-Buffering no;
In den location /-Block. Danach Nginx neu laden:
nginx -t # Syntax prüfen
nginx -s reload # neu laden
Lösung 2: Edge Runtime
Für Streaming-APIs (z. B. KI-Chat) oben in der Datei:
// app/api/chat/route.ts
export const runtime = 'edge'
export async function POST(req: Request) {
const stream = new ReadableStream({
async start(controller) {
// Streaming-Logik
const response = await openai.chat.completions.create({
model: 'gpt-4',
messages: [...],
stream: true,
})
for await (const chunk of response) {
controller.enqueue(chunk.choices[0]?.delta?.content || '')
}
controller.close()
},
})
return new Response(stream, {
headers: {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
},
})
}
Edge Runtime ist leichtgewichtig und für Streaming optimiert – in Docker oft stabiler.
Verifikation
Mit curl testen – zeilenweise Ausgabe bedeutet Erfolg:
curl -N http://yourdomain.com/api/chat \
-X POST \
-H "Content-Type: application/json" \
-d '{"message": "Hello"}'
-N deaktiviert Buffering – Inhalt sollte schrittweise kommen, nicht plötzlich alles.
Immer noch kaputt?
- Cloudflare-Proxy: orange Wolke puffert – deaktivieren (grau) oder Pro (Streaming)
- Docker-Healthcheck: kann Streaming stören –
healthcheckin docker-compose.yml prüfen - Load Balancer: davor ebenfalls Buffering konfigurieren
Häufige Probleme – Diagnose und Fix
Typische Fallstricke und häufige Fragen – decken etwa 80 % der Deployment-Fehler ab.
Problem 1: Statische Assets 404
Symptom: Seite lädt, Styles fehlen, Konsole voller 404 unter /_next/static/...
Ursache: .next/static im Dockerfile nicht korrekt kopiert.
Fix: Diese Zeilen im Dockerfile:
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/public ./public
Bei weiterhin 404 – Rechte prüfen:
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
Problem 2: Docker-Build schlägt fehl
Symptom: docker build meldet „Could not find a production build in the ‘.next’ directory“
Ursache: .dockerignore falsch oder Build-Reihenfolge.
Fix: .dockerignore anlegen:
.next
node_modules
.git
.env*.local
out
.DS_Store
*.log
.next ausschließen – Build passiert im Container.
Problem 3: Umgebungsvariablen greifen nicht
Symptom: process.env.DATABASE_URL ist undefined
Ursache: falsche Übergabe oder Build vs. Laufzeit verwechselt.
Fix:
-
Laufzeit (DB, API-Keys):
docker run -eoder docker-compose.yml:docker run -e DATABASE_URL="..." your-image -
Build-Zeit (
NEXT_PUBLIC_*): beimdocker build:docker build --build-arg NEXT_PUBLIC_API_URL="https://api.example.com" .Im Dockerfile:
ARG NEXT_PUBLIC_API_URL ENV NEXT_PUBLIC_API_URL=$NEXT_PUBLIC_API_URL
Problem 4: Speicher beim Build
Symptom: Build hängt oder „JavaScript heap out of memory“
Ursache: Node.js-Standardlimit, große Next.js-Projekte brauchen mehr RAM.
Fix: In der builder-Phase:
# builder-Phase
ENV NODE_OPTIONS="--max-old-space-size=4096"
RUN npm run build
Oder BuildKit-Ressourcenlimit:
docker build --memory=8g --memory-swap=8g -t your-image .
Problem 5: Container läuft, Port nicht erreichbar
Symptom: Container healthy, http://localhost:3000 verweigert Verbindung.
Ursache: Next.js lauscht standardmäßig auf 127.0.0.1 – im Container von außen nicht erreichbar.
Fix: Im Dockerfile:
ENV HOSTNAME="0.0.0.0"
ENV PORT=3000
Oder beim Start:
docker run -p 3000:3000 -e HOSTNAME="0.0.0.0" your-image
Schnelle Diagnose
Bei Problemen zuerst:
# 1. Container läuft?
docker ps
# 2. Logs
docker logs <container-id>
# 3. Dateistruktur im Container
docker exec -it <container-id> sh
ls -la .next/
ls -la public/
# 4. Dienst im Container
docker exec -it <container-id> wget -O- http://localhost:3000
# 5. Port-Mapping
docker port <container-id>
Fazit
Migration von Vercel zu Docker-Self-Hosting war weniger schlimm als befürchtet. Anfangs etwas Setup – danach geringer Wartungsaufwand. Aktuell: 12 $/Monat fix, drei Next.js-Projekte, keine Rechnungsüberraschungen.
Die drei Kernpunkte noch einmal:
- Standalone – eine Zeile in
next.config.js,publicund.next/staticmanuell kopieren - Mehrstufiges Dockerfile – drei Phasen, finales Image ~200 MB, schneller Start
- Reverse Proxy – Nginx ohne Buffering (
proxy_buffering off), sonst kein Streaming
Bei Streaming-Problemen: in 99 % der Fälle Reverse-Proxy-Buffering – plus export const runtime = 'edge' löst es meist.
Vercel vs. Self-Hosting
| Dimension | Vercel | Docker Self-Hosting |
|---|---|---|
| Deployment | ⚡️ git push | 🐢 5–10 Min. manuell |
| Developer Experience | 🌟 Preview, Logs, Analytics | 🔧 Monitoring selbst einrichten |
| Kosten | 💸 20 $+/Monat, steigt mit Traffic | 💰 12 $/Monat fix (mehrere Projekte) |
| Skalierung | 📈 Auto-Scaling | 📊 Ressourcen manuell |
| Kontrolle | ⚠️ Plattformregeln | ✅ Volle Kontrolle |
| Szenario | Enterprise, global | Persönlich, kleine Teams, knappes Budget |
Abschließend:
- Mehrere Side Projects als Solo-Entwickler – Self-Hosting spart spürbar
- Kein Ops oder stark schwankender Traffic – Vercel bleibt sinnvoll
- Kein richtig oder falsch – nur passend oder nicht
Vollständige Configs und Details liegen im GitHub-Repository (Platzhalter – bei Nutzung ersetzen). Fragen gern in den Kommentaren – bekannte Fallstricke sollen niemanden zweimal treffen.
Next.js Docker Self-Hosting – vollständiger Deployment-Ablauf
Von der Standalone-Konfiguration bis zum Go-Live – inklusive Reverse Proxy und Streaming-Fix
⏱️ Estimated time: 2 hr
- 1
Step 1: Standalone-Ausgabemodus konfigurieren
Standalone in next.config.js aktivieren:
1. next.config.js öffnen
2. Konfiguration ergänzen: output: 'standalone'
3. Build ausführen: npm run build
4. Ausgabe prüfen: Verzeichnis .next/standalone muss existieren
Wichtig:
• Standalone kopiert public und .next/static nicht automatisch
• Beide Verzeichnisse müssen im Dockerfile manuell kopiert werden
• Sonst liefern statische Assets 404
Beispiel:
```javascript
const nextConfig = {
output: 'standalone',
}
module.exports = nextConfig
``` - 2
Step 2: Mehrstufiges Dockerfile erstellen
Dockerfile mit drei Build-Phasen:
Phase 1 – Abhängigkeiten:
• node:20-alpine als Basis-Image
• Nur package.json und package-lock.json kopieren
• npm ci ausführen (Docker-Cache nutzen)
Phase 2 – App bauen:
• node_modules aus Phase 1 übernehmen
• Gesamten Quellcode kopieren
• npm run build ausführen
Phase 3 – Produktion:
• Nicht-Root-Benutzer anlegen (Sicherheit)
• public kopieren (statische Assets)
• .next/standalone kopieren
• .next/static kopieren (CSS/JS-Build-Artefakte)
• HOSTNAME="0.0.0.0" und PORT=3000 setzen
• Start: node server.js
Wichtig:
• Drei Phasen reduzieren das Image von 1,5 GB auf 200 MB
• public und .next/static müssen kopiert werden, sonst 404
• Nicht als root ausführen – Sicherheitsbest Practice - 3
Step 3: Nginx Reverse Proxy konfigurieren
Nginx Reverse Proxy einrichten und Buffering deaktivieren:
1. Nginx installieren (oder Caddy nutzen)
2. SSL-Zertifikat einrichten (Let's Encrypt)
3. Nginx-Konfigurationsdatei anlegen
Pflicht-Einstellungen:
• proxy_buffering off; (Buffering aus)
• proxy_cache off; (Cache aus)
• proxy_set_header X-Accel-Buffering no; (Nginx explizit kein Buffering)
Erforderliche Header:
• proxy_set_header Host $host;
• proxy_set_header X-Real-IP $remote_addr;
• proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
• proxy_set_header X-Forwarded-Proto $scheme;
WebSocket (falls nötig):
• proxy_set_header Upgrade $http_upgrade;
• proxy_set_header Connection "upgrade";
Konfiguration testen:
```bash
nginx -t # Syntax prüfen
nginx -s reload # neu laden
```
Hinweis: Ohne deaktiviertes Buffering funktioniert Streaming-Rendering nicht - 4
Step 4: Umgebungsvariablen handhaben
Build-Zeit und Laufzeit unterscheiden:
Build-Zeit (Präfix NEXT_PUBLIC_):
• Beim docker build übergeben
• Mit --build-arg
• Im Dockerfile: ARG NEXT_PUBLIC_API_URL
• Als ENV setzen: ENV NEXT_PUBLIC_API_URL=$NEXT_PUBLIC_API_URL
Laufzeit (serverseitig):
• Mit docker run -e übergeben
• Oder in docker-compose.yml konfigurieren
• Im Code aus process.env lesen
Im Standalone-Modus:
• runtimeConfig funktioniert nicht
• App-Router-Methode für Umgebungsvariablen nutzen
• Servercode: const dbUrl = process.env.DATABASE_URL
Beispiel:
```bash
# Build
docker build --build-arg NEXT_PUBLIC_API_URL="https://api.example.com" .
# Laufzeit
docker run -e DATABASE_URL="postgres://..." your-image
``` - 5
Step 5: Streaming-Rendering-Probleme beheben
Streaming-Ausfall beheben (KI-Chat, SSE usw.):
Symptome:
• Kein Streaming – Ausgabe kommt erst spät auf einmal
• Server-Sent Events pushen nicht in Echtzeit
Lösung 1 – Nginx (Pflicht):
• proxy_buffering off gesetzt
• X-Accel-Buffering: no gesetzt
• Nginx neu starten
Lösung 2 – Edge Runtime:
• In API-Route: export const runtime = 'edge'
• Edge Runtime ist für Streaming optimiert
• In Docker oft stabiler
Fix verifizieren:
```bash
curl -N http://yourdomain.com/api/chat \
-X POST \
-H "Content-Type: application/json" \
-d '{"message": "Hello"}'
```
Mit -N (kein Buffering) sollte zeilenweise Ausgabe sichtbar sein
Weitere Checks:
• Cloudflare-Proxy: orange Wolke puffert ebenfalls (deaktivieren oder Pro)
• Docker-Healthcheck kann Streaming stören
• Load Balancer davor: separat konfigurieren - 6
Step 6: Deployment und Verifikation
Image bauen und deployen:
1. Docker-Image bauen:
```bash
docker build -t nextjs-app .
```
2. Container starten:
```bash
docker run -d \
-p 3000:3000 \
-e DATABASE_URL="postgres://..." \
-e API_KEY="xxx" \
--name nextjs-app \
nextjs-app
```
3. Deployment prüfen:
• Container-Status: docker ps
• Logs: docker logs nextjs-app
• Zugriff testen: curl http://localhost:3000
• Statische Assets: /_next/static/ aufrufen
4. Nginx konfigurieren und neu starten:
• Reverse-Proxy korrekt einrichten
• HTTPS testen
• Streaming-Rendering prüfen
5. Monitoring und Wartung:
• Auto-Restart: --restart unless-stopped
• Logs regelmäßig prüfen
• Server-Ressourcen überwachen
Typische Fehler:
• Statische Assets 404: public und .next/static im Dockerfile kopiert?
• Umgebungsvariablen wirkungslos: Build vs. Laufzeit unterscheiden
• Container nicht erreichbar: HOSTNAME auf 0.0.0.0?
FAQ
Wie viel spart Self-Hosting? Wie sieht der Kostenvergleich aus?
Warum liefern statische Assets 404? Wie beheben?
• COPY --from=builder /app/public ./public
• COPY --from=builder /app/.next/static ./.next/static
Bei weiterhin 404: Dateirechte prüfen, --chown=nextjs:nodejs setzen.
Streaming-Rendering funktioniert nicht – was tun?
1) Nginx: proxy_buffering off; proxy_set_header X-Accel-Buffering no;
2) API-Route: export const runtime = 'edge'
3) Cloudflare-Proxy: orange Wolke deaktivieren oder Pro
4) Test mit curl -N – zeilenweise Ausgabe erwartet
Umgebungsvariablen greifen nicht – was tun?
• NEXT_PUBLIC_*: beim docker build mit --build-arg, ARG und ENV im Dockerfile
• Laufzeitvariablen: docker run -e oder docker-compose.yml, aus process.env lesen
• Im Standalone-Modus funktioniert runtimeConfig nicht – App-Router-Methode nutzen
Docker-Image ist zu groß – was tun?
• Phase 1: nur Abhängigkeiten (Docker-Cache)
• Phase 2: App bauen
• Phase 3: nur Laufzeit-Dateien (standalone, public, static)
• Image von 1,5 GB auf 200 MB reduzierbar
• node:20-alpine als Basis verkleinert weiter
Wann Self-Hosting, wann Vercel?
Vercel: kein Ops-Know-how, stark schwankender Traffic, globales Edge-Netzwerk, Vercel-Features (Analytics, Edge Config), Budget für Entwicklungseffizienz.
Container läuft, ist aber nicht erreichbar – was prüfen?
1) HOSTNAME muss 0.0.0.0 sein (nicht 127.0.0.1), im Dockerfile: ENV HOSTNAME="0.0.0.0"
2) Port-Mapping: docker run -p 3000:3000
3) Container läuft: docker ps
4) Logs: docker logs <container-id>
5) Im Container testen: docker exec -it <container-id> wget -O- http://localhost:3000
9 Min. Lesezeit · Veröffentlicht am: 20. Dez. 2025 · Aktualisiert am: 14. Juli 2026
Next.js Komplettleitfaden
Wenn du über die Suche hier gelandet bist, kommst du am schnellsten weiter, indem du zum vorherigen oder nächsten Beitrag dieser Serie springst.
Vorheriger
Next.js CI/CD in der Praxis: Automatisierte Tests und Deployments mit GitHub Actions
GitHub Actions für automatisierte Next.js-Tests und -Deployments – mit vollständiger Konfiguration, typischen Fallstricken und Best Practices. Schluss mit manuellem Deploy: Push, und die neue Version ist live.
Teil 41 von 51
Nächster
Next.js Produktions-Monitoring: Sentry, Logs und Alerts in der Praxis
Schritt-für-Schritt Next.js Produktions-Monitoring: Sentry-Integration, Log-Management, Performance-Monitoring und Alert-Konfiguration. App Router mit kopierbaren Code-Vorlagen.
Teil 43 von 51



Kommentare
Melde dich mit GitHub an, um einen Kommentar zu hinterlassen