-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdocker-compose.yml
More file actions
111 lines (107 loc) · 5.61 KB
/
Copy pathdocker-compose.yml
File metadata and controls
111 lines (107 loc) · 5.61 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
# Production stack: Next.js app + Yjs collaboration server, exposed to the
# internet through a dedicated Cloudflare Tunnel (no inbound ports opened).
#
# docker compose --env-file .env.docker up -d --build
#
# The app's public config (NEXT_PUBLIC_*) is baked into the client bundle at
# BUILD time, so changing the Supabase or Yjs URL requires a rebuild (--build),
# not just a restart. Variables below are interpolated from .env.docker.
services:
# ── Next.js app (standalone) ────────────────────────────────────────────────
app:
build:
context: .
dockerfile: Dockerfile
args:
NEXT_PUBLIC_SUPABASE_URL: ${NEXT_PUBLIC_SUPABASE_URL:?set NEXT_PUBLIC_SUPABASE_URL in .env.docker}
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY: ${NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY:?set NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY in .env.docker}
NEXT_PUBLIC_YJS_WEBSOCKET_URL: ${NEXT_PUBLIC_YJS_WEBSOCKET_URL:?set NEXT_PUBLIC_YJS_WEBSOCKET_URL in .env.docker}
SERVER_ACTIONS_ALLOWED_ORIGINS: ${SERVER_ACTIONS_ALLOWED_ORIGINS:-}
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: ${NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY:?set NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY in .env.docker}
NEXT_PUBLIC_CLERK_SIGN_IN_URL: ${NEXT_PUBLIC_CLERK_SIGN_IN_URL:-/login}
NEXT_PUBLIC_CLERK_SIGN_UP_URL: ${NEXT_PUBLIC_CLERK_SIGN_UP_URL:-/signup}
NEXT_PUBLIC_CLERK_SIGN_IN_FALLBACK_REDIRECT_URL: ${NEXT_PUBLIC_CLERK_SIGN_IN_FALLBACK_REDIRECT_URL:-/dashboard}
NEXT_PUBLIC_CLERK_SIGN_UP_FALLBACK_REDIRECT_URL: ${NEXT_PUBLIC_CLERK_SIGN_UP_FALLBACK_REDIRECT_URL:-/dashboard}
environment:
NODE_ENV: production
# NEXT_PUBLIC_* are also provided at runtime for server components.
NEXT_PUBLIC_SUPABASE_URL: ${NEXT_PUBLIC_SUPABASE_URL}
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY: ${NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY}
NEXT_PUBLIC_YJS_WEBSOCKET_URL: ${NEXT_PUBLIC_YJS_WEBSOCKET_URL}
# Clerk: publishable key + URLs are also needed at runtime for server-side
# Clerk; the secret/webhook/service-role keys are server-only runtime secrets.
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: ${NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY}
NEXT_PUBLIC_CLERK_SIGN_IN_URL: ${NEXT_PUBLIC_CLERK_SIGN_IN_URL:-/login}
NEXT_PUBLIC_CLERK_SIGN_UP_URL: ${NEXT_PUBLIC_CLERK_SIGN_UP_URL:-/signup}
NEXT_PUBLIC_CLERK_SIGN_IN_FALLBACK_REDIRECT_URL: ${NEXT_PUBLIC_CLERK_SIGN_IN_FALLBACK_REDIRECT_URL:-/dashboard}
NEXT_PUBLIC_CLERK_SIGN_UP_FALLBACK_REDIRECT_URL: ${NEXT_PUBLIC_CLERK_SIGN_UP_FALLBACK_REDIRECT_URL:-/dashboard}
ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY:-}
CLERK_SECRET_KEY: ${CLERK_SECRET_KEY:?set CLERK_SECRET_KEY in .env.docker}
CLERK_WEBHOOK_SIGNING_SECRET: ${CLERK_WEBHOOK_SIGNING_SECRET:-}
SUPABASE_SERVICE_ROLE_KEY: ${SUPABASE_SERVICE_ROLE_KEY:-}
expose:
- "3005" # internal only — reached by the web proxy over the compose network
healthcheck:
# 127.0.0.1 (not localhost): the app binds IPv4 (HOSTNAME=0.0.0.0), while
# localhost resolves to ::1 first in Alpine → connection refused.
test: ['CMD', 'wget', '-q', '-O', '/dev/null', 'http://127.0.0.1:3005/login']
interval: 30s
timeout: 5s
retries: 3
start_period: 15s
restart: unless-stopped
# ── Yjs realtime collaboration server ───────────────────────────────────────
yjs:
build:
context: .
dockerfile: Dockerfile.yjs
environment:
PORT: "3006"
expose:
- "3006"
healthcheck:
test: ['CMD', 'wget', '-qO-', 'http://localhost:3006/health']
interval: 30s
timeout: 5s
retries: 3
start_period: 10s
restart: unless-stopped
# ── Edge proxy + maintenance fallback ───────────────────────────────────────
# The app hostname points here (http://web:80), not at the app directly. nginx
# proxies to the app and automatically serves maintenance/maintenance.html
# whenever the app is unreachable (deploy, restart, crash) or when the planned-
# maintenance flag file exists. Stays up independently so users always get a
# friendly page instead of a raw 502.
web:
build:
context: .
dockerfile: Dockerfile.web
expose:
- "80"
healthcheck:
test: ['CMD', 'wget', '-q', '-O', '/dev/null', 'http://127.0.0.1:80/healthz']
interval: 30s
timeout: 5s
retries: 3
start_period: 5s
depends_on:
- app
restart: unless-stopped
# ── Cloudflare Tunnel ───────────────────────────────────────────────────────
# Remotely-managed (token) tunnel. Create the tunnel in the Zero Trust
# dashboard and configure its public hostnames there (see DOCKER.md):
# codely.simplemart.dev -> http://web:80 (proxy + maintenance fallback)
# codely-ws.simplemart.dev -> http://yjs:3006 (WebSocket, direct)
# cloudflared shares this compose network, so it resolves web / yjs by name.
# The token is read from the TUNNEL_TOKEN env var (kept out of the process args).
cloudflared:
image: cloudflare/cloudflared:2026.6.1 # pin for reproducibility; bump deliberately
command: tunnel --no-autoupdate run
environment:
TUNNEL_TOKEN: ${TUNNEL_TOKEN:?set TUNNEL_TOKEN in .env.docker}
depends_on:
web:
condition: service_healthy
yjs:
condition: service_healthy
restart: unless-stopped