* fix: meta.json of Poke blueprint The current github/docs links was broken before: https://codeberg.org/ashley/poke after: https://codeberg.org/ashleyirispuppy/poke * fix: broken links in some blueprints * Add openhabittracker blueprint * fix(affinepro): update to current AFFiNE images The template pinned ghcr.io/toeverything/affine-graphql:stable-780dd83, an ephemeral per-commit tag on the old image name that has since been removed from GHCR, so the template could no longer pull and deploy. - Switch both app and migration services to ghcr.io/toeverything/affine:stable, the rolling stable tag recommended by the official self-host compose, so the template no longer rots when per-commit tags are garbage-collected - Move postgres to pgvector/pgvector:pg16 and set AFFINE_INDEXER_ENABLED=false, matching the current upstream self-host compose requirements - Add postgres/redis healthchecks and proper depends_on conditions so the self-host-predeploy migration job runs only once the database is ready, and the server starts only after migrations complete successfully Closes #777 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(cockpit): persist config and storage volumes per upstream docs The template mounted `html:/var/www/html` (freezing the app code from the first deploy) and `data:/var/www/html/storage/data`, which misses uploaded assets (stored under `storage/uploads`) and cache. Per the official Cockpit persistent-storage docs, mount `config:/var/www/html/config` and `storage:/var/www/html/storage` instead. Closes #549 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(kener): define REDIS_URL and drop unused databases Kener v4 requires Redis for its BullMQ queues, caching and scheduler, so the app crashed on startup with "REDIS_URL is not defined in environment variables" right after printing that it was running (issue #976). The template also spun up both a postgres and a mariadb container while DATABASE_URL pointed at SQLite, so neither database was ever used (issue #282). Changes, aligned with the upstream docker-compose.yml (rajnandan1/kener): - Add a redis:7-alpine service with a healthcheck and persistent volume, wire REDIS_URL=redis://redis:6379 and make kener depend on redis being healthy - Remove the unused postgres and mysql services plus their env vars and generated passwords; keep SQLite (upstream default) persisted in the kener_db volume - Set ORIGIN to https://<domain> instead of http://localhost:3000 so CSRF protection works behind the generated domain - Drop the stale /app/uploads bind mount (kener v4 only persists /app/database) and the obsolete compose version key Deploy-tested on a Dokploy instance: migrations and seed complete, schedulers start, "Kener version 4.1.2 is running!", HTTP 200 on the generated domain, both containers stable. Closes #976 Closes #282 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(homarr): use named volume for /appdata and hex encryption key - Replace the relative bind mount `../homarr/appdata:/appdata` with a named volume `homarr_appdata:/appdata` so the data survives cleanups and can be backed up through Dokploy volume backups. - Generate SECRET_ENCRYPTION_KEY with `${hash:64}` instead of `${password:64}`: homarr requires a 64-character hex string (`openssl rand -hex 32`) and the password helper emits non-hex characters (g-z). Closes #738 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(logto): fix postgres role error and update to 1.41.0 The postgres healthcheck ran pg_isready without -U while POSTGRES_USER was set to logto, so every probe attempted to connect as role "postgres" and spammed FATAL: role "postgres" does not exist. Pass -U logto -d logto explicitly and set POSTGRES_DB. Also fix LOGTO_ENDPOINT pointing at the admin domain instead of the main domain, update Logto 1.27.0 -> 1.41.0, use ${password:32} for the generated password, drop the ephemeral host port publishing and add restart policies. Closes #130 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(gitlab-ce): serve on the generated domain (remove removed unicorn config, pin omnibus) The template set unicorn['worker_processes'] / unicorn['worker_timeout'] in GITLAB_OMNIBUS_CONFIG. Unicorn was removed in GitLab 14.0, so on current gitlab-ce images `gitlab-ctl reconfigure` aborts with "Removed configurations found in gitlab.rb" and GitLab never starts serving — the generated domain returned 502 Bad Gateway (issue #380). Rewrite the template as the official all-in-one Omnibus setup: - pin gitlab/gitlab-ce:19.1.2-ce.0 instead of :latest - external_url http://<domain> with nginx listen_port 80 / listen_https false (TLS terminates at Traefik) - set gitlab_rails['initial_root_password'] from a generated template password - puma single mode + prometheus monitoring off to keep memory reasonable - drop the external postgres/redis containers (Omnibus bundles and manages its own) and the broken ports entries ("2224" published a random host port while sshd listens on 22) Verified on a live Dokploy instance: domain serves the GitLab sign-in page and root login with the generated password works. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(zitadel): wire EXTERNALDOMAIN/PORT/SECURE to the generated domain Zitadel resolves its instance from the external domain/port/scheme, so the template's ZITADEL_EXTERNALPORT=8080 made every generated URL (OIDC issuer, login redirects) point at http://<domain>:8080 instead of the domain served by Traefik, ending in {"code":5,"message":"Not Found"} (#516). - Expose ZITADEL_EXTERNALDOMAIN / ZITADEL_EXTERNALPORT / ZITADEL_EXTERNALSECURE as template env vars, defaulting to the generated domain over HTTP (port 80, secure=false) so the routed domain and Zitadel's external config always match; HTTPS users flip them to 443/true in the Env tab. - Pin image to v4.16.0 (was latest) and keep the built-in login v1 via ZITADEL_DEFAULTINSTANCE_FEATURES_LOGINV2_REQUIRED=false so no separate login-v2 container is needed. - Add the official readiness healthcheck, drop the unused /app/data volume, bogus SMTP env keys, published port and obsolete compose version key. Closes #516 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(immich): update to v3.0.2 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(automatisch): switch to official image and wire up DOMAIN to fix Bad Gateway - Replace unofficial dockeriddonuts/automatisch:2.0 mirror (stale since Nov 2024) with the official automatischio/automatisch:0.15.0 image - Define DOMAIN in template.toml [config.env]: the compose referenced ${DOMAIN} but it was never provided, so HOST resolved empty and the app generated localhost URLs for the web app and webhooks - Set API_URL/WEB_APP_URL so generated URLs don't carry the internal :3000 port behind Traefik - Add postgres healthcheck and gate the app on service_healthy to avoid the boot-time migration race; worker now starts after main (official compose order) - Drop unnecessary published port and no-op REDIS_* env on the redis service - Bump meta.json version to 0.15.0 Closes #97 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(signoz): fix ClickHouse hostname resolution and IPv6 binding - Override the ClickHouse image's config.d/docker_related_config.xml, which listens on the IPv6 wildcard address ([::]) first and fails to bind on hosts without IPv6 support; listen on 0.0.0.0 (IPv4) only and disable the internal DNS cache so transient startup DNS failures for zookeeper-1/clickhouse are not cached (issue #534). - Set hostname: clickhouse (instead of container_name) so the server identifies itself as the cluster host declared in cluster.xml. - Remove the explicit signoz-net network: Dokploy attaches its own networks automatically and the repo validator rejects explicit networks; a fixed-name shared network also breaks service DNS across deployments. - Fix mount mismatch: template.toml created files/signoz/prometheus.xml while the compose mounts ../files/signoz/prometheus.yml, so Docker silently mounted a directory as the signoz prometheus config. - Give the otel-collector domain its own generated host: both domains previously shared the same host and path "/", creating two conflicting Traefik routers where one service randomly won. Closes #534 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(infisical): update to v0.162.6 - Bump image from v0.135.0-postgres to v0.162.6 (upstream dropped the -postgres tag suffix after v0.146.0; plain tags are the postgres build) - Remove the db-migration service: the standalone image runs database migrations automatically on boot (auto-start-migrations), matching the official docker-compose.prod.yml which no longer ships that service - Generate ENCRYPTION_KEY (${hash:32}) and AUTH_SECRET (${base64:32}) per deployment instead of shipping hardcoded example secrets - Fix SITE_URL to http://${main_domain} (no :8080; the domain is proxied) - Refresh SMTP env names (SMTP_FROM_ADDRESS/SMTP_FROM_NAME; SMTP_SECURE was removed upstream) and drop unused CLIENT_* env placeholders that were never passed to the container Closes #215 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: add databasus (postgresus renamed upstream) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(evolutionapi): enable integration flags and update version Adds the integration enable env flags introduced in Evolution API v2.3.x (N8N_ENABLED, OPENAI_ENABLED, EVOAI_ENABLED, DIFY_ENABLED, TYPEBOT_ENABLED, CHATWOOT_ENABLED) so integrations no longer fail with 'N8n is disabled', and pins the image to v2.3.7 instead of latest. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(rybbit): update to v2.7.0 The template shipped rybbit v1.5.1, which is no longer supported and is vulnerable to known React2Shell exploits (see #659). Update to the latest stable release v2.7.0 and align the stack with the upstream docker-compose: - Pin ghcr.io/rybbit-io/rybbit-backend and rybbit-client to v2.7.0 - Add the redis service now required by the backend (session tracking and BullMQ queues), with password auth, AOF persistence and noeviction policy per upstream - Drop the DOMAIN_NAME env var (only used by the upstream Caddy webserver, which Dokploy replaces with Traefik) - Add DISABLE_TELEMETRY env and generate BETTER_AUTH_SECRET as base64 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(phpmyadmin): raise PHP upload limit so SQL imports over 2MB work Without UPLOAD_LIMIT the phpMyAdmin image keeps PHP's default 2M post_max_size/upload_max_filesize, so importing any SQL file larger than 2MB fails with 'POST Content-Length exceeds the limit of 2097152 bytes' followed by a session_start error page. - Add UPLOAD_LIMIT (512M) and MAX_EXECUTION_TIME (600) env vars, configurable from the template env - Wire the previously unused MYSQL_DATABASE env var into the compose file, replacing the hardcoded 'tu_base_de_datos' placeholder, and default it to 'phpmyadmin' instead of the system 'mysql' schema Closes #236 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(openpanel): pin verified 2.2.1 images and fix ClickHouse interserver host - Pin lindesvard/openpanel-api|dashboard|worker to 2.2.1 (verified working end-to-end on a Dokploy instance) instead of the mutable :2 tag, so a future broken 2.x release cannot silently break the template again — which is how #615 originated when 2.0.0 shipped. - Fix interserver_http_host to match the actual service name (op-ch), aligning with upstream self-hosting config. - Set meta.json version to the pinned 2.2.1. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(wordpress): route loopback requests through Traefik to fix cURL error 28 WordPress resolves its own public domain to the server's public IP from inside the container, so REST API / WP-Cron / Site Health loopback requests depend on hairpin NAT, which times out (cURL error 28) on many hosts. Pin the site domain to the dokploy-traefik container IP in /etc/hosts at startup (with retries, since Traefik joins the compose network shortly after the container starts) so loopback traffic stays inside the Docker network for both HTTP and HTTPS. No-op fallback when dokploy-traefik is not resolvable. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(minio): migrate to pgsty/minio community fork (upstream is source-only and archived) MinIO Inc. stopped publishing Docker images and pre-built binaries in October 2025 and archived the minio/minio repository in February 2026. The official minio/minio image is frozen at RELEASE.2025-09-07T16-13-09Z and no longer receives security fixes (the fix for CVE-2025-62506 was never published as an image). - Switch image to pgsty/minio:RELEASE.2026-06-18T00-00-00Z, the actively maintained community fork (drop-in replacement, AGPLv3, same env vars, same /data on-disk format, restores the full web console) - Route the S3 API (port 9000) through its own generated domain instead of publishing host port 9000, per repo conventions - Update meta.json links/description to point at the maintained fork Closes #469 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(nextcloud-aio): drop AIO branding, keep template id, pin nextcloud 33.0.6 The template ships plain nextcloud + mariadb + redis + cron, not the nextcloud/all-in-one mastercontainer. Display name and description no longer claim AIO; folder id is kept as nextcloud-aio to avoid breaking existing installs. Image pinned to the current stable tag (33.0.6). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat: add MailCatcher NG template Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs: add per-template setup instructions (supabase, trigger.dev) Adds instructions.md files for the Supabase and Trigger.dev templates and renders them in the template browser as a new Instructions tab in the template dialog (fetched from blueprints/<id>/instructions.md, rendered with a small dependency-free markdown component). Also removes the placeholder blueprints/ackee/instructions.md so it does not surface as an empty Instructions tab. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat: add Weblate template Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat: add Synapse (Matrix homeserver) template Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat: add Dify template Dify 1.15.0 (open-source LLM app development platform): api + worker + worker_beat + web + pgvector PostgreSQL (also used as the vector store) + redis + sandbox + ssrf_proxy (squid) + plugin_daemon, fronted by an internal nginx gateway that mirrors the upstream path routing. Closes #88 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat: add Sim Studio template Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat: add Steedos template Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat: add Silex template Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat: add SpacetimeDB template Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat: add CertMate template Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat: add PostHog template Based on the official hobby deployment, trimmed to run on a single server: Django web + Celery worker, Node plugin-server (CDP, ingestion, session replay, recording API), Rust capture/replay-capture/ feature-flags/hypercache, livestream, Caddy path router, Postgres, Redis, Redpanda (Kafka), ZooKeeper, ClickHouse and MinIO. Images are pinned to a tested master commit (PostHog no longer publishes tagged releases); an init container fetches the matching ClickHouse configuration, Kafka table schemas, funnel UDF binaries and the GeoIP database at the same pinned ref. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat: add Markup template Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat: add Frappe LMS template Adds a Frappe LMS (Frappe Learning) template based on the erpnext-v16 blueprint pattern (configurator + create-site + workers + scheduler + websocket + mariadb + 3x redis). Pins ghcr.io/frappe/lms:v2.52.0, the latest upstream image that ships the lms app (v2.52.1+ images are currently published without any apps baked in). The image does not bundle the payments app, so create-site clears lms's required_apps before install; paid-course checkout is unavailable, everything else works. The backend is gated on a create-site completion marker so gunicorn workers never serve (and cache) a half-installed site during the 3-6 minute first boot. Closes #517 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat: add TREK template Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat: add Oryx (SRS) media streaming template Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: stop plugins service crash loop (logs-redis TLS default) In production images LOGS_REDIS_TLS/TRACES_REDIS_TLS default to true, so the logs-ingestion consumer (part of the plugin-server default mode) kept attempting a TLS handshake against the plaintext Redis, timed out every ~11s and killed the process after 10 errors (restart loop every ~2.5 min). Constrain the plugins service to the capability groups this template ships (cdp_workflows, realtime_cohorts, feature_flags) and pin the redis TLS flags to false as belt-and-braces. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat: add n8n queue mode template n8n running in queue mode (EXECUTIONS_MODE=queue): main instance for the editor/webhooks, a scalable pool of workers (deploy.replicas driven by the N8N_WORKER_REPLICAS env var), Redis (Bull) as the queue broker and PostgreSQL as the database. Pinned to the current stable n8nio/n8n:2.30.4. Closes #455 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat: add bonfire template Bonfire (social flavour) — federated social networking toolkit. App + PostGIS + Meilisearch, mirroring upstream's reference deployments. Closes #125 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat: add dagu blueprint Dagu is a self-contained workflow engine with a Web UI for scheduling and orchestrating jobs as DAGs defined in declarative YAML. - Pin ghcr.io/dagucloud/dagu:2.10.7 and expose the Web UI on port 8080 - Set DAGU_HOST=0.0.0.0 so the service is reachable through the proxy - Enable basic auth with a generated per-deploy admin password - Persist /var/lib/dagu (DAGs, logs, run history) in a named volume Claude-Session: https://claude.ai/code/session_01CRNT6sa2q2P9rUTokeoGhQ * feat: add OneUptime template Adds OneUptime (open-source observability platform: uptime monitoring, status pages, incident management, on-call, logs/traces/metrics) as a template, following upstream's current single-app architecture (app + nginx ingress + postgres + redis + clickhouse + probe). Closes #514 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat: add Mailu template Mailu 2024.06 mail server: front (nginx), admin, imap (dovecot), smtp (postfix), antispam (rspamd), Roundcube webmail and redis. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(templates): add systemprompt (#1032) * feat(templates): add systemprompt * fix header comment: accurate in both repos * chore: normalize template tags to kebab-case (#987) * feat: adds `check-links.js` to find broken links (#983) * feat: add struxa template (#1037) * feat: add struxa template Adds a Dokploy blueprint for Struxa (github.com/struxadotcloud/struxa), a self-hosted, open-source server management panel. Deploys the published GHCR images (dashboard, watchkeeper, migrate) plus MySQL and MinIO sidecars. The web service generates its RS256 JWT keypair at startup via Node's built-in crypto module, since no Dokploy template helper covers RSA key generation. * fix: pin struxa images to latest floating tag struxa's release workflow pushes a latest floating tag alongside version tags on every stable release, matching the convention used by ~44% of existing blueprints (version: "latest" in meta.json). * fix: generate a 64-char DATABASE_ENCRYPTION_KEY Dokploy's runtime \${hash:N} helper produces N hex characters, not N bytes (the templates repo's local preview helpers.ts models it as byte count, which is inconsistent with the platform). struxa's env schema requires DATABASE_ENCRYPTION_KEY to be >=64 chars (it's hex decoded to a 32-byte AES-256 key), so \${hash:32} only produced half the required length. Confirmed against other blueprints (sim, chatwoot, outline) which all use \${hash:64} for 64-char secrets. * fix: address Copilot review comments - Add explicit \`version: "3.8"\` to docker-compose.yml, matching the documented template format. - Pin minio/minio to a specific RELEASE tag (used elsewhere in the repo: plane, posthog) instead of the floating latest tag. - Default BETTER_AUTH_URL/APP_URL/CORS_ORIGIN to http://, matching repo convention for Dokploy-fronted apps (TLS terminates at the proxy). * fix: rename web service to struxa AGENTS.md convention: the primary Docker service name should match the blueprint folder name. Renamed the web/dashboard service from "web" to "struxa" in docker-compose.yml and updated template.toml's config.domains.serviceName to match. * Add PodFetch template (#1035) * Add PodFetch template * Use env array syntax in template.toml * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Address review: match version to image tag, expose admin_username variable, dark-mode friendly logo --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * fix(docker): share plugins and themes volumes across containers (#990) * feat(directus): upgrade template to Directus 12.1.1 (#986) * feat(directus): upgrade template to Directus 12.1.1 * feat(directus): add commented S3 env variables to template.toml --------- Co-authored-by: Zakher Masri <46135573+zaaakher@users.noreply.github.com> Co-authored-by: zakher <zakhermasri@gmail.com> Co-authored-by: Jinjinov <dzindzinovic@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: Stephan Fitzpatrick <stephan@knowsuchagency.com> Co-authored-by: Mauricio Siu <mauricio@dokploy.com> Co-authored-by: Edward Burton <ejb503@gmail.com> Co-authored-by: Marko Kostich <markokosticdev@gmail.com> Co-authored-by: Jakub Krzyżanowski <jakubkrzyz.kontakt@gmail.com> Co-authored-by: SamTV12345 <40429738+SamTV12345@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: Mafly <110502739+Nekoplii@users.noreply.github.com>
Dokploy Open Source Templates
This is the official repository for the Dokploy Open Source Templates.
How to add a new template
- Fork the repository
- Create a new branch
- Add the template to the
blueprintsfolder (docker-compose.yml,template.toml) - Add the template metadata (name, description, version, logo, links, tags) in a
meta.jsonfile inside your template folder (blueprints/<id>/meta.json) — do NOT create or edit a root-levelmeta.json, it is generated at build time - Add the logo to the template folder
- Commit and push your changes
- Create a pull request (PR)
- Every PR will automatically deploy a preview of the template to Dokploy.
- if anyone want to test the template before merging it, you can enter to the preview URL in the PR description, and search the template, click on the Template Card, scroll down and then copy the BASE64 value, and paste in the advanced section of your compose service, in the Import section or optional you can use the preview URL and paste in the BASE URL when creating a template.
Optional
If you want to run the project locally, you can run the project with the following command:
cd app
pnpm install
pnpm run dev
go to http://localhost:5173/
Example
Let's suppose you want to add the Grafana template to the repository.
- Create a new folder inside the
blueprintsfolder namedgrafana - Add the
docker-compose.ymlfile to the folder
version: "3.8"
services:
grafana:
image: grafana/grafana-enterprise:9.5.20
restart: unless-stopped
volumes:
- grafana-storage:/var/lib/grafana
volumes:
grafana-storage: {}
- Add the
template.tomlfile to the folder, this is where we specify the domains, mounts and env variables, to understand more the structure oftemplate.tomlyou can read here Template.toml structure
[variables]
main_domain = "${domain}"
[config]
[[config.domains]]
serviceName = "grafana"
port = 3000
host = "${main_domain}"
[config.env]
[[config.mounts]]
- Add the meta information in
blueprints/<id>/meta.json(a single JSON object; the rootmeta.jsonis generated automatically at build time)
{
"id": "grafana",
"name": "Grafana",
"version": "9.5.20",
"description": "Grafana is an open source platform for data visualization and monitoring.",
"logo": "grafana.svg",
"links": {
"github": "https://github.com/grafana/grafana",
"website": "https://grafana.com/",
"docs": "https://grafana.com/docs/"
},
"tags": [
"monitoring"
]
},
- Add the logo to the folder
- Commit and push your changes
- Create a pull request
Template.toml structure
Dokploy use a defined structure for the template.toml file, we have 4 sections available:
variables: This is where we define the variables that will be used in thedomains,envandmountssections.domains: This is where we define the configuration for the template.env: This is where we define the environment variables for the template.mounts: This is where we define the mounts for the template.
- The
variables(Optional)structure is the following:
[variables]
main_domain = "${domain}"
my_domain = "https://my-domain.com"
my_password = "${password:32}"
any_helper = "${you-can-use-any-helper}"
- The
configstructure is the following:
[config]
# Optional sections below
[[config.domains]]
serviceName = "grafana" # Required
port = 3000 # Required
host = "${main_domain}" # Required
path = "/" # Optional
env = [
"AP_HOST=${main_domain}",
"AP_API_KEY=${api_key}",
"AP_ENCRYPTION_KEY=${encryption_key}",
"AP_JWT_SECRET=${jwt_secret}",
"AP_POSTGRES_PASSWORD=${postgres_password}"
]
[[config.mounts]]
filePath = "/content/file.txt"
content = """
My content
"""
Important: you can reference any variable in the domains, env and mounts sections. just use the ${variable_name} syntax, in the case you don't want to define a variable, you can use the domain, base64, password, hash, uuid, randomPort, timestamp, jwt, email, or username helpers.
Helpers
We have a few helpers that are very common when creating a template, these are:
domain: This is a helper that will generate a random domain for the template.base64 or base64:length: This is a helper that will encode a string to base64 (lenght is the number of bytes to encode not the encoded string length).password or password:length: This is a helper that will generate a random password for the template.hash or hash:length: This is a helper that will generate a hash for the templateuuid: This is a helper that will generate a uuid for the template.randomPort: This is a helper that will generate a random port for the template.email: This is a helper that will generate a random email for the template.username: This is a helper that will generate a random username in lowercase for the template.timestamp: This is a helper that will generate a timestamp for "now" in milli-second.timestampms or timestampms:datetime: This is a helper that will generate a timestamp in milli-seconds.timestamps or timestamps:datetime: This is a helper that will generate a timestamp in seconds.datetimeparameter fortimestamps/timestampmshelpers must be a valid value for javascript new Date() (ie:timestamps:2030-01-01T00:00:00Z)
jwt: This is a helper that will generate a jwt for the template.jwt:length: will generate a random hex string of bytes length. This should not be used in newer templatesjwt:secret_var_name: will generate a jwt with some default values, secret var name should be the name of the variable holding the secretjwt:secret_var_name:payload_var_name: is the same as above but you can pass partial or full payload for the jwt. Here's a full example[variables] main_domain = "${domain}" mysecret = "cQsdycq1hDLopQonF6jUTqgQc5WEZTwWLL02J6XJ" mypayload = """ { "role": "jwt-tester", "iss": "dokploy-templates", "exp": ${timestamps:2030-01-01T00:00:00Z} } """ jwt = "${jwt:mysecret:mypayload}"
General Requirements when creating a template
- Don't use this way in your docker compose file:
services:
grafana:
image: grafana/grafana-enterprise:9.5.20
restart: unless-stopped
ports:
- 3000:3000
# Instead use this way:
ports:
- 3000
- Don't use this way in your template.toml file, make sure to use the same service name as the one in the docker compose file:
[config]
[[config.domains]]
serviceName = "MyGrafanaService"
# Instead use this way:
serviceName = "grafana" # Make sure to use the same service name as the one in the docker compose file
- Don't use container_name in your docker compose file, make sure to use the same service name as the one in the template.toml file:
services:
grafana:
container_name: grafana # ❌ Remove this
- Don't use dokploy-network in your docker compose file, by default all the templates have this flag enabled https://docs.dokploy.com/docs/core/docker-compose/utilities#isolated-deployments, so by default they have a internal network created, so you don't need to create a new one or use the dokploy-network name.
services:
grafana:
networks:
- dokploy-network # ❌ Remove this or any other network defined
- Please before submit a PR, make sure to test the template in your instance, so the maintainers don't spend time trying to figure out what's wrong.
- Everytime you submit a PR, it will display a Preview Link.
- Enter to the Preview Link and search the template you've submitted.
- Click on the Template Card, and click the Copy Button in the Base64 Configuration.
- Go to your instance, create a new Compose Service, go to Advanced Section -> Scroll Down -> Import Section -> Paste the Base64 Value -> Click on the Import Button
- If everything is correct and set, you should see a modal with all the details (Compose File, Environment Variables, Mounts, Domains, etc)
- Now you can click on the Deploy Button and wait for the deployment to finish, and try to access to the service, if everything is correct you should access to the service and see the template working.
Each template's metadata lives in blueprints/<id>/meta.json; the global meta.json is generated at build time. Use node build-scripts/generate-meta.js --check to validate all template metadata.