-
-
Notifications
You must be signed in to change notification settings - Fork 969
Expand file tree
/
Copy pathdocker-compose.yml
More file actions
147 lines (141 loc) · 6.15 KB
/
Copy pathdocker-compose.yml
File metadata and controls
147 lines (141 loc) · 6.15 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
# ──────────────────────────────────────────────────────────
# Openship — Docker Compose (SaaS / from-source control plane)
#
# cp .env.example .env # then edit
# docker compose up -d --build
#
# This is the CONTROL PLANE: it BUILDS api + dashboard + web from source and
# runs postgres + redis. It's what we deploy for the openship.io SaaS, and what
# a from-source contributor runs locally. The MODE is decided entirely by .env —
# no profiles, no per-mode service variants:
# • SaaS (our env): CLOUD_MODE=true + OPENSHIP_TARGET=cloud-saas + Oblien /
# GitHub App / secrets. Deployed apps run in Oblien
# sandboxes — the control plane never runs them here, so
# there is deliberately NO Docker socket and NO edge.
# • From-source dev: CLOUD_MODE=false (the .env.example default).
#
# SELF-HOSTING (run your own apps as host containers with the OpenResty edge on
# :80/:443) is a DIFFERENT stack — the pull-based images + `edge` + Docker-out-
# of-Docker. That lives in docker/docker-compose.yml (or install it with the
# `openship up` CLI). Don't add the edge/socket here; this stays a clean,
# unprivileged control plane.
#
# Services:
# • postgres → private :5432 (storage)
# • redis → private :6379 (queue + cache + rate-limit)
# • api → :4000 (override: API_PORT)
# • dashboard→ :3001 (override: DASHBOARD_PORT)
# • web → :3000 (override: WEB_PORT) landing site (openship.io)
#
# The API + dashboard bind fixed internal ports via PORT (the API honors PORT
# regardless of OPENSHIP_TARGET); a reverse proxy maps the public domains to
# them. postgres/redis are internal-only. The API auto-migrates Postgres on boot.
#
# REMOTE ACCESS: reaching this from another machine (LAN IP or a reverse proxy)
# requires OPENSHIP_PUBLIC_URL in .env — else the dashboard loads but login is
# rejected (403 ORIGIN_REJECTED). Behind a proxy also set TRUST_PROXY=true.
#
# BIND INTERFACE: the api/dashboard/web ports publish on 127.0.0.1 (loopback)
# by default, so nothing is exposed off-box unless you say so — a same-host
# reverse proxy still reaches them over loopback. If your proxy runs on ANOTHER
# machine (or you want direct off-box access), set OPENSHIP_BIND_ADDR to the
# interface to publish on, e.g. OPENSHIP_BIND_ADDR=0.0.0.0 (all) or a specific
# LAN IP. Prefer fronting with a proxy over binding 0.0.0.0.
# ──────────────────────────────────────────────────────────
services:
# ─── Database (storage, private) ──────────────────────
postgres:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_USER: ${POSTGRES_USER:-openship}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-openship}
POSTGRES_DB: ${POSTGRES_DB:-openship}
# PRIVATE: not published to the host. api reaches it at postgres:5432.
expose:
- "5432"
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-openship} -d ${POSTGRES_DB:-openship}"]
interval: 5s
timeout: 3s
retries: 12
# ─── Cache / Queue / Rate-limit (private) ─────────────
redis:
image: redis:7-alpine
restart: unless-stopped
command: ["redis-server", "--appendonly", "yes"]
# PRIVATE: not published to the host. api reaches it at redis:6379.
expose:
- "6379"
volumes:
- redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 12
# ─── API (control plane) ──────────────────────────────
api:
build:
context: .
dockerfile: apps/api/Dockerfile
restart: unless-stopped
ports:
# Loopback by default (nothing exposed off-box); OPENSHIP_BIND_ADDR opts
# into a public/LAN interface. See the "BIND INTERFACE" note above.
- "${OPENSHIP_BIND_ADDR:-127.0.0.1}:${API_PORT:-4000}:${API_PORT:-4000}"
# Mode + secrets (CLOUD_MODE, DEPLOY_MODE, OPENSHIP_TARGET, Oblien, GitHub
# App, auth secrets, …) all come from .env. The values below OVERRIDE it
# with the fixed internal port + in-cluster service DNS (compose
# `environment` wins over `env_file`).
env_file:
- .env
environment:
NODE_ENV: production
PORT: "${API_PORT:-4000}"
DATABASE_URL: postgresql://${POSTGRES_USER:-openship}:${POSTGRES_PASSWORD:-openship}@postgres:5432/${POSTGRES_DB:-openship}
REDIS_URL: redis://redis:6379
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL", "bun -e \"fetch('http://127.0.0.1:${API_PORT:-4000}/api/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))\""]
interval: 10s
timeout: 5s
retries: 12
start_period: 40s
# ─── Dashboard (app UI) ───────────────────────────────
dashboard:
build:
context: .
dockerfile: apps/dashboard/Dockerfile
restart: unless-stopped
ports:
- "${OPENSHIP_BIND_ADDR:-127.0.0.1}:${DASHBOARD_PORT:-3001}:${DASHBOARD_PORT:-3001}"
env_file:
- .env
environment:
NODE_ENV: production
PORT: "${DASHBOARD_PORT:-3001}"
INTERNAL_API_URL: http://api:${API_PORT:-4000}
depends_on:
api:
condition: service_healthy
# ─── Web / Landing ────────────────────────────────────
web:
build:
context: .
dockerfile: apps/web/Dockerfile
restart: unless-stopped
ports:
- "${OPENSHIP_BIND_ADDR:-127.0.0.1}:${WEB_PORT:-3000}:${WEB_PORT:-3000}"
environment:
NODE_ENV: production
PORT: "${WEB_PORT:-3000}"
volumes:
postgres_data:
redis_data: