-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdocker-compose.yml
More file actions
145 lines (138 loc) · 5.86 KB
/
Copy pathdocker-compose.yml
File metadata and controls
145 lines (138 loc) · 5.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
services:
app:
build:
context: .
dockerfile: Dockerfile
container_name: elahe-app
image: elahe-app
restart: unless-stopped
environment:
# Database — PostgreSQL via docker network
- DATABASE_URL=${DATABASE_URL:?DATABASE_URL is required}
- MIGRATION_DATABASE_URL=${MIGRATION_DATABASE_URL:-}
# Least-privilege runtime DB credentials — required by lib/env-security.ts
# for strict production validation (length, weak-value, etc.).
- APP_DB_USER=${APP_DB_USER:?APP_DB_USER is required}
- APP_DB_PASSWORD=${APP_DB_PASSWORD:?APP_DB_PASSWORD is required}
- PRISMA_CONNECTION_LIMIT=${PRISMA_CONNECTION_LIMIT:-10}
- PGBOUNCER_ENABLED=${PGBOUNCER_ENABLED:-false}
- ADMIN_BOOTSTRAP_STATE_DIR=${ADMIN_BOOTSTRAP_STATE_DIR:-/app/runtime_state}
- OBJECT_STORAGE_ENSURE_OWNERSHIP_RECURSIVE=${OBJECT_STORAGE_ENSURE_OWNERSHIP_RECURSIVE:-false}
# Storage
- OBJECT_STORAGE_DRIVER=${OBJECT_STORAGE_DRIVER:-local}
- OBJECT_STORAGE_ROOT=${OBJECT_STORAGE_ROOT:-/app/object_storage}
# File storage now defaults to the local filesystem. To enable an
# external object store (e.g. MinIO or S3) set the corresponding
# environment variables (MINIO_ENDPOINT, MINIO_ACCESS_KEY,
# MINIO_SECRET_KEY) here and implement a storage adapter.
# Redis (optional — leave empty to disable)
- REDIS_URL=${REDIS_URL:-}
# App
- APP_URL=${APP_URL:-http://localhost:3000}
- ALLOWED_ORIGINS=${ALLOWED_ORIGINS:-}
- LOG_LEVEL=${LOG_LEVEL:-info}
- NODE_ENV=production
- PORT=3000
- HOSTNAME=0.0.0.0
# Security — production secrets must be set explicitly via env/.env
- JWT_SECRET=${JWT_SECRET:?JWT_SECRET is required}
- SESSION_SECRET=${SESSION_SECRET:?SESSION_SECRET is required}
- ENCRYPTION_KEY=${ENCRYPTION_KEY:?ENCRYPTION_KEY is required}
- DOWNLOAD_TOKEN_SECRET=${DOWNLOAD_TOKEN_SECRET:?DOWNLOAD_TOKEN_SECRET is required}
- LOCAL_CAPTCHA_SECRET=${LOCAL_CAPTCHA_SECRET:-}
- CAPTCHA_PROVIDER=${CAPTCHA_PROVIDER:-recaptcha}
- ADMIN_USERNAME=${ADMIN_USERNAME:?ADMIN_USERNAME is required}
- ADMIN_PASSWORD=${ADMIN_PASSWORD:-}
- ADMIN_BOOTSTRAP_PASSWORD_FILE=${ADMIN_BOOTSTRAP_PASSWORD_FILE:-}
- ADMIN_BOOTSTRAP_STRICT=${ADMIN_BOOTSTRAP_STRICT:-false}
- ADMIN_BOOTSTRAP_FORCE_PASSWORD_CHANGE=${ADMIN_BOOTSTRAP_FORCE_PASSWORD_CHANGE:-false}
- ADMIN_BOOTSTRAP_RESET_EXISTING=${ADMIN_BOOTSTRAP_RESET_EXISTING:-false}
# VAPID (optional — push notifications disabled if not set)
- VAPID_PUBLIC_KEY=${VAPID_PUBLIC_KEY:-}
- VAPID_PRIVATE_KEY=${VAPID_PRIVATE_KEY:-}
- VAPID_EMAIL=${VAPID_EMAIL:-}
# Firebase (optional)
- NEXT_PUBLIC_FIREBASE_API_KEY=${NEXT_PUBLIC_FIREBASE_API_KEY:-}
- NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=${NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN:-}
- NEXT_PUBLIC_FIREBASE_PROJECT_ID=${NEXT_PUBLIC_FIREBASE_PROJECT_ID:-}
- NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=${NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET:-}
- NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=${NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID:-}
- NEXT_PUBLIC_FIREBASE_APP_ID=${NEXT_PUBLIC_FIREBASE_APP_ID:-}
- NEXT_PUBLIC_FIREBASE_VAPID_KEY=${NEXT_PUBLIC_FIREBASE_VAPID_KEY:-}
# Rate limiting
- RATE_LIMIT_WINDOW_MS=${RATE_LIMIT_WINDOW_MS:-900000}
- RATE_LIMIT_MAX_REQUESTS=${RATE_LIMIT_MAX_REQUESTS:-100}
- SOCKET_RATE_LIMIT_WINDOW_MS=${SOCKET_RATE_LIMIT_WINDOW_MS:-10000}
- SOCKET_RATE_LIMIT_MAX=${SOCKET_RATE_LIMIT_MAX:-30}
# Queue
- QUEUE_CONCURRENCY=${QUEUE_CONCURRENCY:-5}
volumes:
- object_storage_data:/app/object_storage
- runtime_state_data:/app/runtime_state
- ./runtime:/run/secrets:ro
depends_on:
db:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:3000/api/health/live >/dev/null 2>&1 || exit 1"]
interval: 15s
timeout: 10s
retries: 12
start_period: 180s
networks:
- elahe-net
caddy:
image: caddy:2-alpine
container_name: elahe-caddy
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "443:443/udp" # HTTP/3 (QUIC)
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- ./certs:/etc/caddy/certs:ro
- caddy_data:/data
- caddy_config:/config
depends_on:
app:
condition: service_healthy
networks:
- elahe-net
db:
image: postgres:16-alpine
container_name: elahe-db
restart: unless-stopped
environment:
# Bootstrap/provisioning account used by postgres init and installer role grants.
- POSTGRES_USER=${POSTGRES_USER:?POSTGRES_USER is required}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}
- POSTGRES_DB=${POSTGRES_DB:?POSTGRES_DB is required}
# Runtime app credentials are provisioned by installer and should remain least-privilege.
- APP_DB_USER=${APP_DB_USER:?APP_DB_USER is required}
- APP_DB_PASSWORD=${APP_DB_PASSWORD:?APP_DB_PASSWORD is required}
volumes:
- pgdata:/var/lib/postgresql/data
- ./docker/postgres/init:/docker-entrypoint-initdb.d:ro
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
interval: 5s
timeout: 5s
retries: 10
start_period: 20s
networks:
- elahe-net
# Backup scheduling is handled by the in-process worker scheduler in the
# authoritative app runtime. No separate backup container is defined here.
# The MinIO service has been removed in favour of local storage. If you
# wish to use object storage, configure an external MinIO or S3 service
# and set the appropriate environment variables in the app container.
networks:
elahe-net:
driver: bridge
volumes:
pgdata:
caddy_data:
caddy_config:
object_storage_data:
runtime_state_data: