174 lines
5.8 KiB
YAML
174 lines
5.8 KiB
YAML
|
|
services:
|
|
# Traefik Reverse Proxy
|
|
traefik:
|
|
image: traefik:latest
|
|
container_name: traefik
|
|
restart: unless-stopped
|
|
security_opt:
|
|
- no-new-privileges:true
|
|
networks:
|
|
- web
|
|
ports:
|
|
- "80:80"
|
|
- "443:443"
|
|
- "8080:8080"
|
|
environment:
|
|
- CF_DNS_API_TOKEN=${CLOUDFLARE_DNS_API_TOKEN}
|
|
volumes:
|
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
|
- ./traefik/traefik.yml:/traefik.yml:ro
|
|
- ./traefik/acme.json:/acme.json
|
|
- ./traefik/config:/config:ro
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.http.routers.traefik.rule=Host(`${TRAEFIK_DOMAIN}`)"
|
|
- "traefik.http.routers.traefik.entrypoints=websecure"
|
|
- "traefik.http.routers.traefik.tls.certresolver=letsencrypt"
|
|
- "traefik.http.routers.traefik.service=api@internal"
|
|
- "traefik.http.routers.traefik.middlewares=auth"
|
|
- "traefik.http.middlewares.auth.basicauth.users=admin:$$apr1$$8evjzm8w$$FU3G.qPxZRGlnUKzPJ6QB/"
|
|
|
|
# PostgreSQL
|
|
postgres:
|
|
image: postgres:16-alpine
|
|
container_name: postgres
|
|
restart: unless-stopped
|
|
networks:
|
|
- web
|
|
environment:
|
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
|
POSTGRES_MULTIPLE_DATABASES: vorteq_dev,vorteq_test,vorteq_prod
|
|
volumes:
|
|
- postgres_data:/var/lib/postgresql/data
|
|
- ./init-databases.sh:/docker-entrypoint-initdb.d/init-databases.sh:ro
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
|
|
# Redis
|
|
redis:
|
|
image: redis:7-alpine
|
|
container_name: redis
|
|
restart: unless-stopped
|
|
networks:
|
|
- web
|
|
volumes:
|
|
- redis_data:/data
|
|
healthcheck:
|
|
test: ["CMD", "redis-cli", "ping"]
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 5
|
|
|
|
# Development Environment
|
|
app-dev:
|
|
image: forgejo.wulfconsulting.cloud/lorentz/quest-vorteq:dev
|
|
container_name: vorteq-dev
|
|
restart: unless-stopped
|
|
networks:
|
|
- web
|
|
environment:
|
|
NODE_ENV: development
|
|
DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD}@postgres:5432/vorteq_dev
|
|
REDIS_URL: redis://redis:6379/0
|
|
BETTER_AUTH_SECRET: ${DEV_AUTH_SECRET}
|
|
BETTER_AUTH_URL: https://${DEV_DOMAIN}
|
|
PORT: 3000
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.http.routers.app-dev.rule=Host(`${DEV_DOMAIN}`)"
|
|
- "traefik.http.routers.app-dev.entrypoints=websecure"
|
|
- "traefik.http.routers.app-dev.tls.certresolver=letsencrypt"
|
|
- "traefik.http.services.app-dev.loadbalancer.server.port=3000"
|
|
- "traefik.http.routers.app-dev.middlewares=dev-headers"
|
|
- "traefik.http.middlewares.dev-headers.headers.customresponseheaders.X-Environment=development"
|
|
depends_on:
|
|
postgres:
|
|
condition: service_healthy
|
|
redis:
|
|
condition: service_healthy
|
|
|
|
# Testing Environment
|
|
app-test:
|
|
image: forgejo.wulfconsulting.cloud/lorentz/quest-vorteq:test
|
|
container_name: vorteq-test
|
|
restart: unless-stopped
|
|
networks:
|
|
- web
|
|
environment:
|
|
NODE_ENV: test
|
|
DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD}@postgres:5432/vorteq_test
|
|
REDIS_URL: redis://redis:6379/1
|
|
BETTER_AUTH_SECRET: ${TEST_AUTH_SECRET}
|
|
BETTER_AUTH_URL: https://${TEST_DOMAIN}
|
|
PORT: 3000
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.http.routers.app-test.rule=Host(`${TEST_DOMAIN}`)"
|
|
- "traefik.http.routers.app-test.entrypoints=websecure"
|
|
- "traefik.http.routers.app-test.tls.certresolver=letsencrypt"
|
|
- "traefik.http.services.app-test.loadbalancer.server.port=3000"
|
|
- "traefik.http.routers.app-test.middlewares=test-headers"
|
|
- "traefik.http.middlewares.test-headers.headers.customresponseheaders.X-Environment=testing"
|
|
depends_on:
|
|
postgres:
|
|
condition: service_healthy
|
|
redis:
|
|
condition: service_healthy
|
|
|
|
# Production Environment
|
|
app-prod:
|
|
image: forgejo.wulfconsulting.cloud/lorentz/quest-vorteq:latest
|
|
container_name: vorteq-prod
|
|
restart: unless-stopped
|
|
networks:
|
|
- web
|
|
environment:
|
|
NODE_ENV: production
|
|
DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD}@postgres:5432/vorteq_prod
|
|
REDIS_URL: redis://redis:6379/2
|
|
BETTER_AUTH_SECRET: ${PROD_AUTH_SECRET}
|
|
BETTER_AUTH_URL: https://${PROD_DOMAIN}
|
|
PORT: 3000
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.http.routers.app-prod.rule=Host(`${PROD_DOMAIN}`)"
|
|
- "traefik.http.routers.app-prod.entrypoints=websecure"
|
|
- "traefik.http.routers.app-prod.tls.certresolver=letsencrypt"
|
|
- "traefik.http.services.app-prod.loadbalancer.server.port=3000"
|
|
- "traefik.http.routers.app-prod.middlewares=prod-chain"
|
|
- "traefik.http.middlewares.prod-chain.chain.middlewares=security-headers,rate-limit,compress"
|
|
- "traefik.http.middlewares.security-headers.headers.stsSeconds=31536000"
|
|
- "traefik.http.middlewares.security-headers.headers.stsIncludeSubdomains=true"
|
|
- "traefik.http.middlewares.security-headers.headers.stsPreload=true"
|
|
- "traefik.http.middlewares.security-headers.headers.forceSTSHeader=true"
|
|
- "traefik.http.middlewares.security-headers.headers.frameDeny=true"
|
|
- "traefik.http.middlewares.security-headers.headers.contentTypeNosniff=true"
|
|
- "traefik.http.middlewares.security-headers.headers.browserXssFilter=true"
|
|
- "traefik.http.middlewares.rate-limit.ratelimit.average=100"
|
|
- "traefik.http.middlewares.rate-limit.ratelimit.burst=50"
|
|
- "traefik.http.middlewares.compress.compress=true"
|
|
depends_on:
|
|
postgres:
|
|
condition: service_healthy
|
|
redis:
|
|
condition: service_healthy
|
|
deploy:
|
|
resources:
|
|
limits:
|
|
cpus: '2'
|
|
memory: 2G
|
|
reservations:
|
|
cpus: '1'
|
|
memory: 1G
|
|
|
|
networks:
|
|
web:
|
|
external: true
|
|
|
|
volumes:
|
|
postgres_data:
|
|
redis_data:
|