deploy: add production Compose without Traefik
This commit is contained in:
parent
dd79dde532
commit
9317a6131f
@ -12,6 +12,9 @@ NEXTAUTH_SECRET=
|
||||
POSTGRES_VOLUME=
|
||||
UPLOADS_VOLUME=
|
||||
TRAEFIK_NETWORK=dokploy-network
|
||||
# Only docker-compose.production.direct.yml (no Traefik):
|
||||
APP_BIND_ADDRESS=127.0.0.1
|
||||
APP_PORT=3000
|
||||
APP_TIMEZONE=Europe/Berlin
|
||||
TRUST_PROXY=false
|
||||
GROUP_UPLOAD_QUOTA_MB=1024
|
||||
|
||||
@ -4,6 +4,31 @@
|
||||
|
||||
## Konfiguration
|
||||
|
||||
### Variante ohne Traefik
|
||||
|
||||
`docker-compose.production.direct.yml` ist ebenfalls eigenständig und benötigt weder Dokploy noch ein externes Proxy-Netz. Sie veröffentlicht die App standardmäßig auf `127.0.0.1:3000` des Docker-Hosts. Die übrigen Dienste, Daten-Volumes und Migrationen entsprechen der Traefik-Variante. Nur **eine** der beiden Compose-Dateien verwenden.
|
||||
|
||||
`APP_PORT` bestimmt den Host-Port. `APP_BIND_ADDRESS=127.0.0.1` eignet sich für einen auf demselben Host laufenden HTTPS-Proxy, beispielsweise Nginx oder Caddy. Bei einem separaten vorgeschalteten Proxy die erreichbare private Host-IP einstellen und den Port entsprechend auf diesen Proxy begrenzen. `0.0.0.0` bindet an alle IPv4-Schnittstellen. `TRAEFIK_NETWORK` wird in dieser Variante nicht verwendet.
|
||||
|
||||
Die App selbst stellt HTTP bereit. Die öffentliche Produktionsadresse in `NEXTAUTH_URL` bleibt HTTPS; TLS muss deshalb ein vorhandener HTTPS-Proxy oder Load Balancer übernehmen. Die Datei stellt keinen eigenen TLS-Dienst bereit und deaktiviert die HTTPS-Prüfung der Anwendung nicht. Eine Nginx-Vorlage liegt unter [deploy/nginx.conf.example](deploy/nginx.conf.example).
|
||||
|
||||
Für alle nachfolgenden CLI-Schritte und die Datenübernahme diese Funktion verwenden:
|
||||
|
||||
```bash
|
||||
dc() { docker compose --env-file .env.production -p taskmanager-next -f docker-compose.production.direct.yml "$@"; }
|
||||
dc config --quiet
|
||||
```
|
||||
|
||||
Den Projektnamen konsistent auf den Namen der vorbereiteten Zielinstallation setzen. Die spätere Funktionsdefinition für die Dokploy-Variante überspringen. Nach Restore, Migration und Start lässt sich die App lokal prüfen:
|
||||
|
||||
```bash
|
||||
curl --fail http://127.0.0.1:3000/api/health
|
||||
```
|
||||
|
||||
Bei abweichendem `APP_PORT` oder `APP_BIND_ADDRESS` die Prüfadresse entsprechend anpassen.
|
||||
|
||||
### Variante mit Dokploy/Traefik
|
||||
|
||||
In Dokploy ein Compose-Projekt mit `docker-compose.production.yml` konfigurieren. Die Werte aus `.env.production.example` in die Compose-Umgebung übernehmen. Alternativ auf dem Server:
|
||||
|
||||
```bash
|
||||
|
||||
121
docker-compose.production.direct.yml
Normal file
121
docker-compose.production.direct.yml
Normal file
@ -0,0 +1,121 @@
|
||||
# Standalone production deployment with a configurable host port; no Traefik required.
|
||||
# Read PRODUCTION.md before deploying an existing installation.
|
||||
x-app-environment: &app-environment
|
||||
NODE_ENV: production
|
||||
DATABASE_URL: ${DATABASE_URL:?Set DATABASE_URL with host db and URL-encoded credentials}
|
||||
NEXTAUTH_URL: ${NEXTAUTH_URL:?Set the public HTTPS URL}
|
||||
NEXTAUTH_SECRET: ${NEXTAUTH_SECRET:?Set NEXTAUTH_SECRET}
|
||||
ALLOW_LOCAL_HTTP: "false"
|
||||
TRUST_PROXY: ${TRUST_PROXY:-false}
|
||||
APP_TIMEZONE: ${APP_TIMEZONE:-Europe/Berlin}
|
||||
UPLOAD_DIR: /app/private-uploads
|
||||
GROUP_UPLOAD_QUOTA_MB: ${GROUP_UPLOAD_QUOTA_MB:-1024}
|
||||
ARCHIVE_RETENTION_DAYS: ${ARCHIVE_RETENTION_DAYS:-0}
|
||||
SMTP_URL: ${SMTP_URL:-}
|
||||
MAIL_FROM: ${MAIL_FROM:-}
|
||||
OIDC_ISSUER: ${OIDC_ISSUER:-}
|
||||
OIDC_CLIENT_ID: ${OIDC_CLIENT_ID:-}
|
||||
OIDC_CLIENT_SECRET: ${OIDC_CLIENT_SECRET:-}
|
||||
OIDC_REQUIRED_ACR: ${OIDC_REQUIRED_ACR:-}
|
||||
WEBHOOK_ALLOWED_HOSTS: ${WEBHOOK_ALLOWED_HOSTS:-}
|
||||
|
||||
x-logging: &logging
|
||||
driver: json-file
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
|
||||
services:
|
||||
db:
|
||||
image: postgres:16-alpine
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
POSTGRES_USER: ${POSTGRES_USER:-taskmanager}
|
||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD}
|
||||
POSTGRES_DB: ${POSTGRES_DB:-taskmanager}
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U \"$$POSTGRES_USER\" -d \"$$POSTGRES_DB\""]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 20
|
||||
start_period: 10s
|
||||
stop_grace_period: 60s
|
||||
logging: *logging
|
||||
|
||||
migrate:
|
||||
image: git.jfritzsche.de/jf/taskmanager-operations:${TASKMANAGER_VERSION:?Set a published release version}
|
||||
restart: "no"
|
||||
init: true
|
||||
user: "1001:1001"
|
||||
security_opt: ["no-new-privileges:true"]
|
||||
environment:
|
||||
<<: *app-environment
|
||||
LEGACY_UPLOAD_DIR: /app/private-uploads
|
||||
command: ["sh", "-c", "npx prisma migrate deploy && npx tsx scripts/migrate-access.ts && npx tsx scripts/migrate-uploads.ts"]
|
||||
volumes:
|
||||
- uploads:/app/private-uploads
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
logging: *logging
|
||||
|
||||
app:
|
||||
image: git.jfritzsche.de/jf/taskmanager:${TASKMANAGER_VERSION:?Set a published release version}
|
||||
restart: unless-stopped
|
||||
init: true
|
||||
user: "1001:1001"
|
||||
security_opt: ["no-new-privileges:true"]
|
||||
cap_drop: ["ALL"]
|
||||
read_only: true
|
||||
tmpfs: ["/tmp:rw,noexec,nosuid,size=64m"]
|
||||
environment: *app-environment
|
||||
ports:
|
||||
- "${APP_BIND_ADDRESS:-127.0.0.1}:${APP_PORT:-3000}:3000"
|
||||
volumes:
|
||||
- uploads:/app/private-uploads
|
||||
healthcheck:
|
||||
test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:3000/api/health',{signal:AbortSignal.timeout(4000)}).then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
start_period: 30s
|
||||
retries: 3
|
||||
depends_on:
|
||||
migrate:
|
||||
condition: service_completed_successfully
|
||||
stop_grace_period: 30s
|
||||
logging: *logging
|
||||
|
||||
worker:
|
||||
image: git.jfritzsche.de/jf/taskmanager-operations:${TASKMANAGER_VERSION:?Set a published release version}
|
||||
restart: unless-stopped
|
||||
init: true
|
||||
user: "1001:1001"
|
||||
security_opt: ["no-new-privileges:true"]
|
||||
cap_drop: ["ALL"]
|
||||
environment:
|
||||
<<: *app-environment
|
||||
WORKER_HEARTBEAT_FILE: /tmp/taskmanager-worker-heartbeat
|
||||
command: ["node", "--import", "tsx", "scripts/worker.ts"]
|
||||
volumes:
|
||||
- uploads:/app/private-uploads
|
||||
healthcheck:
|
||||
test: ["CMD", "node", "-e", "const fs=require('fs');process.exit(Date.now()-fs.statSync('/tmp/taskmanager-worker-heartbeat').mtimeMs<180000?0:1)"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
start_period: 60s
|
||||
retries: 3
|
||||
depends_on:
|
||||
app:
|
||||
condition: service_healthy
|
||||
stop_grace_period: 30s
|
||||
logging: *logging
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
external: true
|
||||
name: ${POSTGRES_VOLUME:?Set the prepared PostgreSQL target volume name}
|
||||
uploads:
|
||||
external: true
|
||||
name: ${UPLOADS_VOLUME:?Set the prepared uploads target volume name}
|
||||
Loading…
Reference in New Issue
Block a user