-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathdocker-compose.yml
More file actions
154 lines (148 loc) · 6.4 KB
/
Copy pathdocker-compose.yml
File metadata and controls
154 lines (148 loc) · 6.4 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
146
147
148
149
150
151
152
153
154
services:
deft:
build:
context: .
# NEXT_PUBLIC_* must be present at build time — Next.js bakes them
# into the client JS bundle. Compose interpolates ${VAR} from the
# host .env automatically.
args:
NEXT_PUBLIC_APP_URL: ${NEXT_PUBLIC_APP_URL:-http://localhost:3000}
NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL:-http://localhost:3001}
NEXT_PUBLIC_WS_URL: ${NEXT_PUBLIC_WS_URL:-http://localhost:3001}
NEXT_PUBLIC_FEATURE_HUDDLES: ${NEXT_PUBLIC_FEATURE_HUDDLES:-false}
NEXT_PUBLIC_FEATURE_APPS: ${NEXT_PUBLIC_FEATURE_APPS:-false}
ports:
- '${DEFT_WEB_PORT:-3000}:3000'
- '${DEFT_API_PORT:-3001}:3001'
env_file: .env
environment:
DATABASE_URL: postgres://postgres:${POSTGRES_PASSWORD:?POSTGRES_PASSWORD required — generate with `openssl rand -hex 32`}@postgres:5432/deft
API_PORT: 3001
NEXT_PUBLIC_APP_URL: ${NEXT_PUBLIC_APP_URL:-http://localhost:3000}
NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL:-http://localhost:3001}
NEXT_PUBLIC_WS_URL: ${NEXT_PUBLIC_WS_URL:-http://localhost:3001}
NEXT_PUBLIC_FEATURE_HUDDLES: ${NEXT_PUBLIC_FEATURE_HUDDLES:-false}
NEXT_PUBLIC_FEATURE_APPS: ${NEXT_PUBLIC_FEATURE_APPS:-false}
DEFT_APPS_ENABLED: ${DEFT_APPS_ENABLED:-false}
DEFT_APP_DEVELOPER_PAIRING_ENABLED: ${DEFT_APP_DEVELOPER_PAIRING_ENABLED:-false}
DEFT_MCP_PRIVATE_ORIGIN_ALLOWLIST: ${DEFT_MCP_PRIVATE_ORIGIN_ALLOWLIST:-}
DEFT_MCP_ENABLE_UNSAFE_STDIO: ${DEFT_MCP_ENABLE_UNSAFE_STDIO:-false}
MCP_STDIO_ALLOWED_COMMANDS: ${MCP_STDIO_ALLOWED_COMMANDS:-}
depends_on:
postgres:
condition: service_healthy
volumes:
- uploads:/app/uploads
- uploads:/app/apps/api/uploads
restart: unless-stopped
init:
build:
context: .
args:
NEXT_PUBLIC_APP_URL: ${NEXT_PUBLIC_APP_URL:-http://localhost:3000}
NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL:-http://localhost:3001}
NEXT_PUBLIC_WS_URL: ${NEXT_PUBLIC_WS_URL:-http://localhost:3001}
NEXT_PUBLIC_FEATURE_HUDDLES: ${NEXT_PUBLIC_FEATURE_HUDDLES:-false}
NEXT_PUBLIC_FEATURE_APPS: ${NEXT_PUBLIC_FEATURE_APPS:-false}
env_file: .env
environment:
DATABASE_URL: postgres://postgres:${POSTGRES_PASSWORD:?POSTGRES_PASSWORD required — generate with `openssl rand -hex 32`}@postgres:5432/deft
NODE_ENV: production
depends_on:
postgres:
condition: service_healthy
command: sh -c "pnpm db:assert-fresh && pnpm db:push-full && pnpm db:seed"
profiles: ['tools']
upgrade:
build:
context: .
args:
NEXT_PUBLIC_APP_URL: ${NEXT_PUBLIC_APP_URL:-http://localhost:3000}
NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL:-http://localhost:3001}
NEXT_PUBLIC_WS_URL: ${NEXT_PUBLIC_WS_URL:-http://localhost:3001}
NEXT_PUBLIC_FEATURE_HUDDLES: ${NEXT_PUBLIC_FEATURE_HUDDLES:-false}
NEXT_PUBLIC_FEATURE_APPS: ${NEXT_PUBLIC_FEATURE_APPS:-false}
env_file: .env
environment:
DATABASE_URL: postgres://postgres:${POSTGRES_PASSWORD:?POSTGRES_PASSWORD required - generate with `openssl rand -hex 32`}@postgres:5432/deft
NODE_ENV: production
depends_on:
postgres:
condition: service_healthy
command: sh -c "pnpm db:upgrade"
profiles: ['tools']
doctor:
build:
context: .
args:
NEXT_PUBLIC_APP_URL: ${NEXT_PUBLIC_APP_URL:-http://localhost:3000}
NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL:-http://localhost:3001}
NEXT_PUBLIC_WS_URL: ${NEXT_PUBLIC_WS_URL:-http://localhost:3001}
NEXT_PUBLIC_FEATURE_HUDDLES: ${NEXT_PUBLIC_FEATURE_HUDDLES:-false}
NEXT_PUBLIC_FEATURE_APPS: ${NEXT_PUBLIC_FEATURE_APPS:-false}
env_file: .env
environment:
DATABASE_URL: postgres://postgres:${POSTGRES_PASSWORD:?POSTGRES_PASSWORD required — generate with `openssl rand -hex 32`}@postgres:5432/deft
DEFT_API_URL: http://deft:3001
DEFT_WEB_URL: http://deft:3000
DEFT_SELFHOST_INTERNAL_CHECK: 1
depends_on:
deft:
condition: service_started
postgres:
condition: service_healthy
command: sh -c "pnpm selfhost:doctor"
profiles: ['tools']
smoke:
build:
context: .
args:
NEXT_PUBLIC_APP_URL: ${NEXT_PUBLIC_APP_URL:-http://localhost:3000}
NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL:-http://localhost:3001}
NEXT_PUBLIC_WS_URL: ${NEXT_PUBLIC_WS_URL:-http://localhost:3001}
NEXT_PUBLIC_FEATURE_HUDDLES: ${NEXT_PUBLIC_FEATURE_HUDDLES:-false}
NEXT_PUBLIC_FEATURE_APPS: ${NEXT_PUBLIC_FEATURE_APPS:-false}
env_file: .env
environment:
DATABASE_URL: postgres://postgres:${POSTGRES_PASSWORD:?POSTGRES_PASSWORD required - generate with `openssl rand -hex 32`}@postgres:5432/deft
DEFT_API_URL: http://deft:3001
DEFT_WEB_URL: http://deft:3000
DEFT_SELFHOST_INTERNAL_CHECK: 1
depends_on:
deft:
condition: service_started
postgres:
condition: service_healthy
command: sh -c "pnpm selfhost:smoke"
profiles: ['tools']
postgres:
# pgvector image ships a standard postgres:16 with the `vector`
# extension pre-built. Deft's wiki + tasks embeddings columns are
# declared as `vector(1536)` in the Drizzle schema, so `db:push`
# fails against plain postgres:16-alpine on a fresh volume.
image: pgvector/pgvector:pg16
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD required — generate with `openssl rand -hex 32`}
POSTGRES_DB: deft
ports:
# SECURITY: bind to loopback only. Docker's iptables NAT rules sit
# ABOVE ufw, so `ports: '5432:5432'` would expose postgres to the
# public internet regardless of `ufw deny`. PG attackers scan the
# whole IPv4 space for 5432 and try default creds — this is how the
# 2026-05-11 incident happened on a test deploy. Localhost-only
# binding keeps it reachable from host-side dev tools but invisible
# to the public. `compose.prod.yml` drops the binding entirely for
# hardened production deploys; containers still talk to each other on
# the internal docker network.
- '${DEFT_BIND_HOST:-127.0.0.1}:${DEFT_POSTGRES_PORT:-5432}:5432'
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U postgres']
interval: 5s
timeout: 5s
retries: 5
volumes:
pgdata:
uploads: