opnform/docker-compose.yml
claude-macmini 817a7cdf77 OpnForm docker-compose deploy-config (forms.doc-gen.eu)
Coolify docker-compose (git-based), exact gepinde image-tags. GEEN route B /
geen registry-image / geen host-watcher. Zie README.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-08 18:56:30 +02:00

184 lines
6.1 KiB
YAML

# OpnForm — forms.doc-gen.eu (CX33)
# =====================================================================
# Deploy-model: Coolify **docker-compose** (git-based), GEEN route B.
# - Geen registry-image, geen Forgejo Actions/CI, geen host-watcher.
# - Coolify klont deze repo en draait `docker compose up`. De losse
# docker/nginx.conf wordt door Coolify NIET geinterpoleerd (bevat
# nginx-$-variabelen) — daarom git-based i.p.v. raw compose.
# Updaten (nieuwe OpnForm-versie): de image-tags hieronder bumpen ->
# commit+push naar main -> in Coolify "Redeploy". Zie README.md.
# Alle images zijn EXACT gepind (geen :latest).
# Secrets (${APP_KEY} etc.) staan NIET hier maar in de Coolify-env +
# ~/.config/doc-gen-deploy/opnform.env (0600) op de Mac Mini.
# =====================================================================
services:
# --- Laravel API (php-fpm op :9000) -------------------------------
api: &api
image: jhumanj/opnform-api:1.13.2
restart: unless-stopped
volumes:
- opnform_storage:/usr/share/nginx/html/storage:rw
environment: &api-env
APP_NAME: "OpnForm"
APP_ENV: production
APP_DEBUG: "false"
APP_KEY: ${APP_KEY}
# APP_URL/FRONT_URL volgen automatisch het toegewezen domein
# (sslip tijdens de test, forms.doc-gen.eu na cutover).
APP_URL: ${SERVICE_URL_INGRESS}
FRONT_URL: ${SERVICE_URL_INGRESS}
FRONT_API_SECRET: ${FRONT_API_SECRET}
LOG_CHANNEL: errorlog
LOG_LEVEL: warning
DB_CONNECTION: pgsql
DB_HOST: db
DB_PORT: "5432"
DB_DATABASE: ${DB_DATABASE:-opnform}
DB_USERNAME: ${DB_USERNAME:-opnform}
DB_PASSWORD: ${DB_PASSWORD}
FILESYSTEM_DRIVER: local
LOCAL_FILESYSTEM_VISIBILITY: public
CACHE_DRIVER: redis
QUEUE_CONNECTION: redis
SESSION_DRIVER: redis
REDIS_HOST: redis
REDIS_PORT: "6379"
REDIS_PASSWORD: "null"
MAIL_MAILER: smtp
MAIL_HOST: mail.2487.eu
MAIL_PORT: "465"
MAIL_USERNAME: ${MAIL_USERNAME}
MAIL_PASSWORD: ${MAIL_PASSWORD}
MAIL_ENCRYPTION: ssl
MAIL_FROM_ADDRESS: ${MAIL_FROM_ADDRESS}
MAIL_FROM_NAME: "OpnForm"
JWT_TTL: "1440"
JWT_SECRET: ${JWT_SECRET}
# Productie: token gebonden aan IP+UA (docker-setup.sh eist false = validatie AAN).
JWT_SKIP_IP_UA_VALIDATION: "false"
# Reverse proxy = Coolify/Traefik -> ingress(nginx) -> php-fpm; vertrouw de interne docker-netwerken.
TRUSTED_PROXIES: "10.0.0.0/8,172.16.0.0/12,192.168.0.0/16"
PHP_MEMORY_LIMIT: "512M"
PHP_MAX_EXECUTION_TIME: "600"
PHP_UPLOAD_MAX_FILESIZE: "64M"
PHP_POST_MAX_SIZE: "64M"
SHOW_OFFICIAL_TEMPLATES: "true"
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL", "php /usr/share/nginx/html/artisan about || exit 1"]
interval: 30s
timeout: 15s
retries: 3
start_period: 90s
# --- Queue-worker (mail, exports) ---------------------------------
api-worker:
<<: *api
command: ["php", "artisan", "queue:work", "--tries=3", "--timeout=120"]
depends_on:
api:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL", "pgrep -f 'artisan queue:work' > /dev/null || exit 1"]
interval: 60s
timeout: 10s
retries: 3
start_period: 30s
# --- Scheduler (cron) ---------------------------------------------
api-scheduler:
<<: *api
command: ["php", "artisan", "schedule:work"]
depends_on:
api:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL", "php /usr/share/nginx/html/artisan app:scheduler-status --mode=check --max-minutes=3 || exit 1"]
interval: 60s
timeout: 30s
retries: 3
start_period: 90s
# --- Frontend (Nuxt SSR op :3000) ---------------------------------
ui:
image: jhumanj/opnform-client:1.13.2
restart: unless-stopped
environment:
NUXT_PUBLIC_APP_URL: ${SERVICE_URL_INGRESS}
NUXT_PUBLIC_API_BASE: ${SERVICE_URL_INGRESS}/api
# Server-side calls van Nuxt lopen intern via de nginx-ingress.
NUXT_PRIVATE_API_BASE: http://ingress/api
NUXT_API_SECRET: ${FRONT_API_SECRET}
NUXT_PUBLIC_ENV: production
NUXT_PUBLIC_ROOT_REDIRECT_URL: ""
depends_on:
api:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL", "wget --spider -q http://localhost:3000/login || exit 1"]
interval: 30s
timeout: 10s
retries: 3
start_period: 45s
# --- Redis (sessies, cache, queue) --------------------------------
redis:
image: redis:7.4.11
restart: unless-stopped
volumes:
- redis-data:/data
healthcheck:
test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
interval: 30s
timeout: 5s
retries: 5
# --- PostgreSQL ----------------------------------------------------
db:
image: postgres:16.15
restart: unless-stopped
environment:
POSTGRES_DB: ${DB_DATABASE:-opnform}
POSTGRES_USER: ${DB_USERNAME:-opnform}
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- postgres-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DB_USERNAME:-opnform} -d ${DB_DATABASE:-opnform}"]
interval: 30s
timeout: 5s
retries: 5
# --- Nginx ingress: HTTP<->FastCGI + /-routing (het enige web-endpoint) ---
ingress:
image: nginx:1.30.4
restart: unless-stopped
environment:
# Coolify: expose service 'ingress' op container-poort 80 achter het
# toegewezen domein (Traefik + Let's Encrypt). Leeg = auto (sslip);
# zet dit op https://forms.doc-gen.eu voor de cutover.
SERVICE_FQDN_INGRESS_80: ""
NGINX_MAX_BODY_SIZE: 64m
volumes:
- ./docker/nginx.conf:/etc/nginx/templates/default.conf.template:ro
depends_on:
api:
condition: service_started
ui:
condition: service_started
healthcheck:
test: ["CMD-SHELL", "nginx -t >/dev/null 2>&1 || exit 1"]
interval: 30s
timeout: 5s
retries: 3
start_period: 10s
volumes:
postgres-data:
opnform_storage:
redis-data: