Skip to content

Commit 830d6bb

Browse files
Siumauricioclaude
andauthored
Add OpenStatus template (Dokploy#1126)
Self-hosted OpenStatus (status pages + uptime monitoring) following the official docker-compose.github-packages.yaml setup: local libSQL database, one-shot migration runner built from the pinned upstream commit, workflows, API server, dashboard, status-page, and the private-location ingest server. All app images pinned to upstream commit e1a9825; Tinybird analytics run in no-op mode by default. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent b87d9a9 commit 830d6bb

5 files changed

Lines changed: 308 additions & 0 deletions

File tree

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
services:
2+
libsql:
3+
image: ghcr.io/tursodatabase/libsql-server:v0.24.33
4+
restart: unless-stopped
5+
expose:
6+
- 8080
7+
volumes:
8+
- libsql-data:/var/lib/sqld
9+
environment:
10+
- SQLD_NODE=primary
11+
# Increase limits to handle multiple services without connection pooling
12+
- SQLD_MAX_CONCURRENT_CONNECTIONS=512
13+
- SQLD_MAX_CONCURRENT_REQUESTS=1024
14+
healthcheck:
15+
test:
16+
[
17+
"CMD-SHELL",
18+
'perl -e ''use IO::Socket::INET; exit(IO::Socket::INET->new(PeerAddr=>"127.0.0.1:8080",Timeout=>1) ? 0 : 1);''',
19+
]
20+
interval: 10s
21+
timeout: 5s
22+
retries: 5
23+
start_period: 10s
24+
25+
# One-shot migration runner (idempotent — drizzle skips applied migrations).
26+
# No published image exists for it upstream, so it is built from the pinned
27+
# commit the ghcr.io app images were built from.
28+
db-migrate:
29+
build:
30+
context: https://github.com/openstatusHQ/openstatus.git#e1a98255e39c9cc9f6d4853dbce30c3f6c42514a
31+
dockerfile: packages/db/Dockerfile
32+
restart: on-failure:3
33+
environment:
34+
- DATABASE_URL=http://libsql:8080
35+
- DATABASE_AUTH_TOKEN=
36+
depends_on:
37+
libsql:
38+
condition: service_healthy
39+
40+
workflows:
41+
image: ghcr.io/openstatushq/openstatus-workflows:e1a9825
42+
restart: unless-stopped
43+
expose:
44+
- 3000
45+
volumes:
46+
- workflows-data:/app/data
47+
environment:
48+
- NODE_ENV=production
49+
- PORT=3000
50+
- DATABASE_URL=http://libsql:8080
51+
- DATABASE_AUTH_TOKEN=
52+
- CRON_SECRET=${CRON_SECRET}
53+
- RESEND_API_KEY=${RESEND_API_KEY:-re_selfhost_placeholder}
54+
- SITE_URL=https://${DASHBOARD_HOST}
55+
- TINYBIRD_NOOP=true
56+
depends_on:
57+
db-migrate:
58+
condition: service_completed_successfully
59+
libsql:
60+
condition: service_healthy
61+
healthcheck:
62+
test: ["CMD", "curl", "-f", "http://localhost:3000/ping"]
63+
interval: 15s
64+
timeout: 10s
65+
retries: 3
66+
start_period: 30s
67+
68+
server:
69+
image: ghcr.io/openstatushq/openstatus-server:e1a9825
70+
restart: unless-stopped
71+
expose:
72+
- 3000
73+
environment:
74+
- NODE_ENV=production
75+
- PORT=3000
76+
- DATABASE_URL=http://libsql:8080
77+
- DATABASE_AUTH_TOKEN=
78+
- CRON_SECRET=${CRON_SECRET}
79+
- RESEND_API_KEY=${RESEND_API_KEY:-re_selfhost_placeholder}
80+
- SUPER_ADMIN_TOKEN=${SUPER_ADMIN_TOKEN}
81+
- SELF_HOST=true
82+
- FLY_REGION=self-hosted
83+
- TINYBIRD_NOOP=true
84+
- UPSTASH_REDIS_REST_URL=http://localhost:6379
85+
- UPSTASH_REDIS_REST_TOKEN=placeholder
86+
depends_on:
87+
db-migrate:
88+
condition: service_completed_successfully
89+
workflows:
90+
condition: service_healthy
91+
libsql:
92+
condition: service_healthy
93+
healthcheck:
94+
test: ["CMD", "curl", "-f", "http://localhost:3000/ping"]
95+
interval: 15s
96+
timeout: 10s
97+
retries: 3
98+
start_period: 30s
99+
100+
dashboard:
101+
image: ghcr.io/openstatushq/openstatus-dashboard:e1a9825
102+
restart: unless-stopped
103+
expose:
104+
- 3000
105+
environment:
106+
- NODE_ENV=production
107+
- PORT=3000
108+
- HOSTNAME=0.0.0.0
109+
- AUTH_TRUST_HOST=true
110+
- DATABASE_URL=http://libsql:8080
111+
- DATABASE_AUTH_TOKEN=
112+
- AUTH_SECRET=${AUTH_SECRET}
113+
- SELF_HOST=true
114+
- NEXT_PUBLIC_URL=https://${DASHBOARD_HOST}
115+
- CRON_SECRET=${CRON_SECRET}
116+
- RESEND_API_KEY=${RESEND_API_KEY:-re_selfhost_placeholder}
117+
- TINYBIRD_NOOP=true
118+
- UPSTASH_REDIS_REST_URL=http://localhost:6379
119+
- UPSTASH_REDIS_REST_TOKEN=placeholder
120+
depends_on:
121+
db-migrate:
122+
condition: service_completed_successfully
123+
workflows:
124+
condition: service_healthy
125+
libsql:
126+
condition: service_healthy
127+
server:
128+
condition: service_healthy
129+
healthcheck:
130+
test: ["CMD", "curl", "-f", "http://localhost:3000/"]
131+
interval: 15s
132+
timeout: 10s
133+
retries: 3
134+
start_period: 45s
135+
136+
status-page:
137+
image: ghcr.io/openstatushq/openstatus-status-page:e1a9825
138+
restart: unless-stopped
139+
expose:
140+
- 3000
141+
environment:
142+
- NODE_ENV=production
143+
- PORT=3000
144+
- HOSTNAME=0.0.0.0
145+
- AUTH_TRUST_HOST=true
146+
- DATABASE_URL=http://libsql:8080
147+
- DATABASE_AUTH_TOKEN=
148+
- AUTH_SECRET=${AUTH_SECRET}
149+
- SELF_HOST=true
150+
- NEXT_PUBLIC_URL=https://${DASHBOARD_HOST}
151+
- CRON_SECRET=${CRON_SECRET}
152+
- RESEND_API_KEY=${RESEND_API_KEY:-re_selfhost_placeholder}
153+
- TINYBIRD_NOOP=true
154+
depends_on:
155+
db-migrate:
156+
condition: service_completed_successfully
157+
workflows:
158+
condition: service_healthy
159+
libsql:
160+
condition: service_healthy
161+
server:
162+
condition: service_healthy
163+
healthcheck:
164+
test: ["CMD", "curl", "-f", "http://localhost:3000/"]
165+
interval: 15s
166+
timeout: 10s
167+
retries: 3
168+
start_period: 45s
169+
170+
# Ingest server for private-location probes (the probe itself,
171+
# ghcr.io/openstatushq/private-location, runs wherever you monitor from).
172+
private-location:
173+
image: ghcr.io/openstatushq/openstatus-private-location:e1a9825
174+
restart: unless-stopped
175+
expose:
176+
- 8080
177+
environment:
178+
- PORT=8080
179+
- GIN_MODE=release
180+
- DB_URL=http://libsql:8080
181+
- WORKFLOWS_URL=http://workflows:3000
182+
- CRON_SECRET=${CRON_SECRET}
183+
- TINYBIRD_URL=${TINYBIRD_URL}
184+
- TINYBIRD_TOKEN=${TINYBIRD_TOKEN}
185+
depends_on:
186+
server:
187+
condition: service_healthy
188+
healthcheck:
189+
test: ["CMD", "wget", "--spider", "-q", "http://localhost:8080/health"]
190+
interval: 15s
191+
timeout: 10s
192+
retries: 3
193+
start_period: 30s
194+
195+
volumes:
196+
libsql-data:
197+
workflows-data:
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# OpenStatus
2+
3+
OpenStatus is deployed here in self-hosted mode following the official Docker
4+
setup (`DOCKER.md` / `docker-compose.github-packages.yaml` upstream), with all
5+
app images pinned to the same upstream commit (`e1a9825`).
6+
7+
## Services
8+
9+
| Service | Purpose |
10+
|---|---|
11+
| dashboard | Admin UI (your first domain) |
12+
| status-page | Public status pages (your second domain, pages served at `/<slug>`) |
13+
| server | API backend (tRPC / public API) |
14+
| workflows | Background jobs / alerting |
15+
| libsql | Local libSQL (Turso) database — no cloud account needed |
16+
| db-migrate | One-shot migration runner (built from the pinned upstream commit, exits after applying) |
17+
| private-location | Ingest server that receives check results from your monitoring probes |
18+
19+
Database migrations run automatically on every deploy (the one-shot
20+
`db-migrate` service is idempotent).
21+
22+
Note: `db-migrate` is built from source (upstream publishes no image for it),
23+
so the first deployment takes a few extra minutes while it builds.
24+
25+
## First login
26+
27+
1. Open the dashboard domain and choose **magic link** login with your e-mail.
28+
2. If you did not configure `RESEND_API_KEY`, the magic link is not e-mailed —
29+
it is printed to the **dashboard service logs**. Open the dashboard
30+
container logs in Dokploy and copy the `>>> Magic Link: ...` URL into your
31+
browser. If the printed link starts with `http://0.0.0.0:3000`, replace that
32+
host with your dashboard domain before opening it. (Optionally, once HTTPS
33+
is enabled on your dashboard domain, you can add
34+
`AUTH_URL=https://<your-dashboard-domain>` to the dashboard service in the
35+
compose file so links are generated with the right host — do not set it to
36+
an empty value or a plain-HTTP domain, as that breaks the auth flow.)
37+
3. Create a workspace and a status page with a slug; it becomes available at
38+
`https://<status-page-domain>/<slug>`.
39+
40+
## Running checks (probes)
41+
42+
Self-hosted OpenStatus runs monitors through **private location probes**
43+
(`ghcr.io/openstatushq/private-location`) that you deploy wherever you want to
44+
monitor from. Point the probe at this stack's ingest server:
45+
46+
- Expose the `private-location` service (port 8080) on a domain in Dokploy, and
47+
- set `OPENSTATUS_INGEST_URL` on the probe to that URL, together with the
48+
`OPENSTATUS_KEY` you create in the dashboard.
49+
50+
See the upstream guide: https://www.openstatus.dev/docs (Guides → How to
51+
Self-Host openstatus).
52+
53+
## Analytics (optional)
54+
55+
Tinybird analytics are disabled by default (`TINYBIRD_NOOP=true`), so charts
56+
show no data but everything else works. To enable analytics, run a Tinybird
57+
Local container or use Tinybird Cloud, deploy the `packages/tinybird` project
58+
with the `tb` CLI, and set `TINYBIRD_URL` / `TINYBIRD_TOKEN` in the
59+
environment (plus `TINY_BIRD_API_KEY` and remove `TINYBIRD_NOOP`) — see the
60+
upstream self-hosting guide.

blueprints/openstatus/meta.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"id": "openstatus",
3+
"name": "OpenStatus",
4+
"version": "e1a9825",
5+
"description": "OpenStatus is an open-source synthetic monitoring platform with beautiful status pages, uptime and API monitoring as code, and alerting.",
6+
"logo": "openstatus.png",
7+
"links": {
8+
"github": "https://github.com/openstatusHQ/openstatus",
9+
"website": "https://www.openstatus.dev",
10+
"docs": "https://www.openstatus.dev/docs"
11+
},
12+
"tags": [
13+
"monitoring",
14+
"status-page",
15+
"uptime"
16+
]
17+
}
5.8 KB
Loading
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
[variables]
2+
dashboard_domain = "${domain}"
3+
status_page_domain = "${domain}"
4+
auth_secret = "${base64:32}"
5+
cron_secret = "${password:32}"
6+
super_admin_token = "${password:32}"
7+
8+
[config]
9+
10+
# Dashboard (admin UI — log in here)
11+
[[config.domains]]
12+
serviceName = "dashboard"
13+
port = 3000
14+
host = "${dashboard_domain}"
15+
16+
# Public status pages (served at /<page-slug>)
17+
[[config.domains]]
18+
serviceName = "status-page"
19+
port = 3000
20+
host = "${status_page_domain}"
21+
22+
[config.env]
23+
DASHBOARD_HOST = "${dashboard_domain}"
24+
STATUS_PAGE_HOST = "${status_page_domain}"
25+
AUTH_SECRET = "${auth_secret}"
26+
CRON_SECRET = "${cron_secret}"
27+
SUPER_ADMIN_TOKEN = "${super_admin_token}"
28+
# Optional: Resend API key for outgoing e-mails. Without it, magic-link
29+
# login URLs are printed to the dashboard container logs instead.
30+
RESEND_API_KEY = ""
31+
# Optional: Tinybird analytics for the private-location ingest server
32+
# (see instructions — analytics are disabled/no-op by default)
33+
TINYBIRD_URL = ""
34+
TINYBIRD_TOKEN = ""

0 commit comments

Comments
 (0)