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>
Same root cause as odoo_19 (#1108, fixed in #1110): the compose file
bind-mounts ../files/config over /etc/odoo, but with mounts = [] the
directory is empty, hiding the image's /etc/odoo/odoo.conf. As a result
wait-for-psql.py crashes with configparser.NoSectionError: No section:
'options' and the web container never starts.
Ship odoo.conf through the template config mount instead, with
proxy_mode enabled so websocket/POS/livechat work behind Traefik.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* fix(postiz): pass all social provider env vars and fix Temporal healthcheck
* fix(postiz): drop env vars Postiz does not read, unset NOT_SECURED
- GOOGLE_CLIENT_ID/GOOGLE_CLIENT_SECRET are not read by Postiz:
the Google auth provider and GMB both use YOUTUBE_CLIENT_ID
(google.provider.ts, gmb.provider.ts).
- NEXT_PUBLIC_FRONTEND_URL does not exist in the Postiz codebase.
- Postiz checks NOT_SECURED for truthiness only, so the string
"false" still enables insecure mode; remove the variable so
secure cookies are actually on for the HTTPS deployment.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Mauricio Siu <mauricio@dokploy.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* data permission right & Traefik configuration
Permession to write on data directory is mandatory for odoo server to run
Added Traefik configuration to allow POS and live chat to run
* fix(odoo_19): provide odoo.conf via config mount and enable proxy_mode
The empty ../files/config bind mount was hiding the image's
/etc/odoo/odoo.conf, crashing wait-for-psql.py (NoSectionError:
'options') in a restart loop. Ship odoo.conf through the template
mount instead, with proxy_mode enabled so websocket/POS/livechat
work behind Traefik (threaded mode serves /websocket on 8069, so
no extra routing is needed). Revert the manual Traefik labels
(invalid compose: labels must be a mapping; Dokploy generates
routing from template.toml) and the chown command (the named
volume already gets odoo ownership from the image).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Mauricio Siu <mauricio@dokploy.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
- ghcr.io/plausible/community-edition v2.1.5 -> v3.2.1 (latest stable release)
- clickhouse-server 24.3.3.102-alpine -> 24.12-alpine, matching the official
CE v3.2.1 compose.yml
- CLICKHOUSE_SKIP_USER_SETUP=1 on the events db: required by ClickHouse
24.11+ images so Plausible can connect as the passwordless default user
(without it the app crash-loops with AUTHENTICATION_FAILED)
- plausible-data volume + TMPDIR per the official v3 compose
Deploy-verified on a Dokploy instance: fresh import, all 3 containers
running, HTTP 200 on the domain with the Plausible login page.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
#1107 targeted main instead of canary and was squash-merged there. This merge
brings blueprints/openseo into canary and keeps both histories converged so
the next canary->main release stays conflict-free.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Add OpenSEO template
OpenSEO is an open source, self-hosted alternative to Semrush and
Ahrefs (keyword research, rank tracking, backlinks, site audits).
Requires a DataForSEO API key, which the template leaves blank for
the user to fill in via the Dokploy UI.
* openseo: pin image to v0.1.6 and set ALLOWED_HOST so Vite preview accepts the Dokploy domain
---------
Co-authored-by: Mauricio Siu <mauricio@dokploy.com>
* fix(appwrite): enable HTTPS for function API endpoint
* appwrite: document that _APP_OPTIONS_FORCE_HTTPS=enabled requires an HTTPS domain
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Mauricio Siu <mauricio@dokploy.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* feat: update calcom image version and add QOL Env Var for public signup
* fix: add quotes to env var definition
* fix: add more information for selfhosting
* feat: add env vars and config for Email SMTP Creds
* chore(calcom): bump meta.json version to v6.2.0 and fix ARM comment line reference
---------
Co-authored-by: Mauricio Siu <mauricio@dokploy.com>
* feat: add Instatic template
Instatic is a self-hosted, open-source visual CMS combining a canvas
editor, content engine, and static site publisher. Deployed as a
single container backed by SQLite, with uploads and DB on one
persistent volume.
Signed-off-by: Tekena Solomon <tekena157@gmail.com>
* fix: add init container to fix Instatic storage volume permissions
Signed-off-by: Tekena Solomon <tekena157@gmail.com>
* fix(instatic): accept both https and http public origins so the setup wizard works before HTTPS is enabled
---------
Signed-off-by: Tekena Solomon <tekena157@gmail.com>
Co-authored-by: Mauricio Siu <mauricio@dokploy.com>
- rustrak-full: the Next.js standalone UI bound to $HOSTNAME (container id),
so Traefik got connection refused and the UI domain returned 502 (pre-existing
on canary, confirmed by deploying both #1102 and canary). HOSTNAME=0.0.0.0
was deploy-verified: UI 200 "Rustrak - Error Tracking System".
- trmnl-larapaper: #1101 bumped to 0.33.0 (Apr 2026); upstream is at 0.40.0.
0.40.0 was deploy-verified on the same template: healthy, /, /login,
/register, /up all 200.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Both Rustrak blueprints shipped abians7/* images pinned to v0.2.1, twelve
minor versions behind the current release, and linked to the old personal
repo. Updated to the official rustrak/* images on latest, refreshed the
metadata, and replaced the logo with the current mark.
The memory figure in the description is now measured rather than estimated:
32 MB resident at idle with SQLite, from docker stats on these images.
* feat: add postgres-pgadmin template
* feat: expose postgres via second domain
Add postgres_domain variable and second [[config.domains]] for
postgres:5432 alongside pgadmin:80, so both the DB and the web UI
are reachable via Dokploy domains.
* fix(postgres-pgadmin): drop HTTP domain on postgres:5432, pre-register server in pgAdmin, bump pgAdmin to 9.17
- Remove the second [[config.domains]] pointing an HTTP host at postgres:5432 (Traefik returned 502).
- Mount servers.json + pgpass via config.mounts so pgAdmin comes with the bundled PostgreSQL pre-registered and connects without a password prompt (pgpass is copied to the data volume with 0600 for uid 5050).
- Bump dpage/pgadmin4 8.13 -> 9.17.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Mauricio Siu <mauricio@dokploy.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
- ghcr.io/trixtylab/kotonoba:latest -> 1.0.19 (same digest as latest today); meta.json version 1.0.19.
- ADMIN_DOMAIN is documented upstream as a bare hostname, pass ${main_domain} without scheme.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat: add DockRoute template
* fix: pass template env vars through to the dockroute container
The compose file had no environment block, so the DOCKROUTE_*/CLOUDFLARE_*
variables defined in template.toml never reached the container - switching
the provider to cloudflare from the Dokploy environment tab would have
silently stayed in the log dry-run mode.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Mauricio Siu <mauricio@dokploy.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Louez is an open-source equipment rental platform (AGPL-3.0): a booking
storefront with live availability plus a back office for reservations,
customers, PDF contracts and statistics.
The blueprint brings up the app, MySQL 8.4 and a private MinIO bucket for
product images. Louez installs its own database schema on first boot.
Didacta is a fair-code self-hosted LMS. The blueprint ships the app image
alongside a pgvector-enabled Postgres (the baseline migration runs
CREATE EXTENSION "vector", so a plain postgres image fails on first boot)
and Redis.
A single domain is enough: the container runs the API on :4000 and the web
on :3000, and Next.js rewrites /api/*, /healthz and /readyz to the internal
API, so the domain only targets port 3000.
* Add Langfuse template
Open-source LLM engineering platform: tracing, prompt management,
evaluation and cost/usage analytics for LLM apps.
Stack: langfuse-web + langfuse-worker (image tag 4), Postgres 17,
ClickHouse 25.12, Redis 7, MinIO. Adapted from the official
docker-compose.yml at https://github.com/langfuse/langfuse/blob/main/docker-compose.yml,
with all secrets generated via Dokploy's template.toml helpers instead
of the upstream hardcoded defaults.
MinIO gets its own domain because Langfuse's web UI issues presigned
S3 URLs that the browser fetches directly (media attached to traces),
so that endpoint has to be reachable from outside the internal network.
Validated locally with build-scripts/validate-template.ts,
validate-docker-compose.ts and generate-meta.js --check (all pass),
plus `docker compose config` with sample secrets to confirm the
langfuse-web override of LANGFUSE_S3_MEDIA_UPLOAD_ENDPOINT resolves
correctly. Not yet deployed on a live Dokploy instance.
* fix: bind langfuse-web to 0.0.0.0 so Traefik can reach it
Docker sets HOSTNAME to the container id, and Next.js standalone binds to
it, which resolves to a single network's IP. With Dokploy's proxy network
attached as a second network, Traefik got connection refused (502).
Setting HOSTNAME=0.0.0.0 fixes routing; verified with a live deploy.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Mauricio Siu <mauricio@dokploy.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* feat: add Waxum template
* fix(waxum): pin SQLITE_PATH inside the mounted session volume
Waxum's default SQLite path already resolves inside
WHATSAPP_STORAGE_PATH, so this was already persisted, but make it
explicit so it doesn't depend on undocumented default derivation
surviving a redeploy.
Addresses: https://github.com/Dokploy/templates/pull/1074#pullrequestreview-4883962555
---------
Co-authored-by: fdciabdul <taqin2731@gmail.com>
* fix(supabase): generate the new API keys and wire up JWKS verification
The template has carried the plumbing for Supabase's new opaque API keys
since #872 — kong-entrypoint.sh builds the Lua translation expressions and
kong.yml registers the keys as key-auth credentials — and #1068 added the
studio/kong compose references while aligning with upstream.
But four of the variables that plumbing reads have never been declared in
template.toml, so they never reached the Environment tab:
SUPABASE_PUBLISHABLE_KEY, SUPABASE_SECRET_KEY,
ANON_KEY_ASYMMETRIC, SERVICE_ROLE_KEY_ASYMMETRIC
kong-entrypoint.sh gates on the first two being non-empty, so every deploy
silently took the legacy-only branch and users had no field to fill in.
Generate them from [variables] instead:
- SUPABASE_PUBLISHABLE_KEY / SUPABASE_SECRET_KEY as opaque sb_* strings
- ANON_KEY / SERVICE_ROLE_KEY move to [variables] so ANON_KEY_ASYMMETRIC
and SERVICE_ROLE_KEY_ASYMMETRIC can reuse the same JWT
Kong substitutes whatever token those hold and every backend already
verifies HS256 with JWT_SECRET, so the opaque keys work without an EC
keypair (which the dokploy helpers cannot generate). Clients still only
ever hold an opaque string. JWT_KEYS / JWT_JWKS stay empty as a
documented opt-in for real ES256.
Also fixed while in here:
- JWT_JWKS was missing entirely. GOTRUE_JWT_KEYS was already enabled, so
anyone setting a real JWKS got Auth signing ES256 tokens that PostgREST,
Storage, Realtime and Functions had no way to verify. Wire it into all
four verifiers.
- Restore two routes kong.yml dropped: /realtime/v1/api/tenants and
/realtime/v1/api/openapi were reachable with the anon key, and the
PostgREST OpenAPI root at /rest/v1/ was anon-readable (supabase#42949).
Needs KONG_ROUTER_FLAVOR: expressions, as upstream sets.
- graphql-v1 had key-auth hide_credentials: true. key-auth runs before
request-transformer, so the apikey header was stripped before the Lua
expression could read it and service_role GraphQL requests were
silently downgraded to anon.
- DB_ENC_KEY was hardcoded to the well-known "supabaserealtime" default;
generate REALTIME_DB_ENC_KEY instead.
- functions/main/index.ts was the old remote-JWKS version pinned to
deno.land/x/jose@4.14.4; sync with upstream (jsr:@panva/jose@6 and
local SUPABASE_JWKS).
Verified against all 11 services running locally: an RLS-protected table
confirms anon and publishable keys are blocked while service_role and
secret keys read the row, so the opaque keys really are translated and
not downgraded. Storage and Realtime still verify HS256 with JWT_JWKS
empty. 21/22 end-to-end checks pass; the last was the test not following
Studio's redirect.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(supabase): match dokploy hash helper semantics (length = chars, not bytes)
Dokploy's generateHash(length) returns exactly `length` hex characters,
not `length` random bytes hex-encoded. Realtime requires DB_ENC_KEY to be
exactly 16 characters (AES-128), so ${hash:8} produced an 8-char key and
the realtime container crash-looped. Bump to ${hash:16}, and bump the
opaque API key segments to ${hash:22}/${hash:8} to match the intended
sb_<role>_<22>_<8> shape.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Mauricio Siu <mauricio@dokploy.com>