chore(plane): update template to v1.3.1 with healthchecks and bug fixes#912
chore(plane): update template to v1.3.1 with healthchecks and bug fixes#912leogomide wants to merge 7 commits into
Conversation
- Bump makeplane/* images v0.27.1 -> v1.3.1 - Pin minio to RELEASE.2025-04-22T22-12-26Z (last release with full admin console before community-edition feature removal) - Add YAML anchors (x-*-env) for env reuse across backend services - Add healthchecks for postgres, valkey, rabbitmq - api/worker/beat-worker wait for migrator via service_completed_successfully (fixes race where backend booted before schema was migrated) - Add restart policies (unless-stopped for long-running, on-failure for migrator) - Migrate env_file -> inline environment (matches repo convention) - Expose APP_RELEASE in template.toml [variables] for UI override Bug fixes in template.toml: - RABBITMQ_DEFAULT_USER was the literal string "rabbitmq_user" instead of a variable reference; AMQP_URL was inconsistent with the broker user - WEB_URL was missing the https:// scheme (broke OAuth/email links) - DATABASE_URL/AMQP_URL referenced inline vars that Dokploy does not resolve inside [config.env]; now use [variables] directly - Remove dead vars: NGINX_PORT (Plane v1.x uses Caddy), SENTRY_DSN, SENTRY_ENVIRONMENT - Add WEBHOOK_ALLOWED_IPS/WEBHOOK_ALLOWED_HOSTS (SSRF guard default introduced in Plane v1.x)
built with Refined Cloudflare Pages Action⚡ Cloudflare Pages Deployment
|
The plane-proxy image has hardcoded `reverse_proxy web:3000`/`api:8000`
in its Caddyfile with generic service names. In multi-stack Dokploy
deployments, those names collide with other stacks' containers (Next.js
apps frequently have a `web` service) on the shared dokploy-network —
the Plane domain ends up serving content from unrelated stacks.
Two-step fix:
1. Rename internal services with `plane-*` prefix (unique cluster-wide):
web/space/admin/live/api/worker/beat-worker/migrator → plane-*
2. Add `links:` block to the `proxy` service mapping the new names back
to the generic ones the Caddyfile expects (`plane-web:web` etc.).
Docker injects these into /etc/hosts, which has absolute priority
over DNS — Caddy resolves `web`/`api`/etc. directly to our renamed
containers, ignoring any collision on dokploy-network.
Also updates `API_BASE_URL` in template.toml and the `x-live-env` anchor
from `http://api:8000` → `http://plane-api:8000`.
No `networks:` declarations added (repo validator rejects them; Dokploy
manages networking automatically).
|
Pushed a fix for a DNS collision bug in the internal proxy (commits Problem: the Fix (two layers):
No Local validation (all 0 errors):
|
|
Hello! Thank you for your work! I tried this on our instance, and got the following error in the "level":"info","ts":1780489811.5198905,"msg":"maxprocs: Leaving GOMAXPROCS=8: CPU quota undefined"}
{"level":"info","ts":1780489811.5205202,"msg":"GOMEMLIMIT is updated","package":"github.com/KimMachineGun/automemlimit/memlimit","GOMEMLIMIT":60627279052,"previous":9223372036854775807}
{"level":"info","ts":1780489811.520733,"msg":"using config from file","file":"/etc/caddy/Caddyfile"}
{"level":"info","ts":1780489811.521703,"msg":"maxprocs: No GOMAXPROCS change to reset"}
Error: adapting config using caddyfile: server block without any key is global configuration, and if used, it must be first
{"level":"info","ts":1780489813.504255,"msg":"maxprocs: Leaving GOMAXPROCS=8: CPU quota undefined"}
{"level":"info","ts":1780489813.5045652,"msg":"GOMEMLIMIT is updated","package":"github.com/KimMachineGun/automemlimit/memlimit","GOMEMLIMIT":60627279052,"previous":9223372036854775807}
{"level":"info","ts":1780489813.5053725,"msg":"using config from file","file":"/etc/caddy/Caddyfile"}
{"level":"info","ts":1780489813.5109265,"msg":"maxprocs: No GOMAXPROCS change to reset"}
Error: adapting config using caddyfile: server block without any key is global configuration, and if used, it must be first
{"level":"info","ts":1780489815.0965083,"msg":"maxprocs: Leaving GOMAXPROCS=8: CPU quota undefined"}
{"level":"info","ts":1780489815.0969374,"msg":"GOMEMLIMIT is updated","package":"github.com/KimMachineGun/automemlimit/memlimit","GOMEMLIMIT":60627279052,"previous":9223372036854775807}
{"level":"info","ts":1780489815.0970578,"msg":"using config from file","file":"/etc/caddy/Caddyfile"}
{"level":"info","ts":1780489815.099546,"msg":"maxprocs: No GOMAXPROCS change to reset"}
Error: adapting config using caddyfile: server block without any key is global configuration, and if used, it must be first
{"level":"info","ts":1780489817.7271638,"msg":"maxprocs: Leaving GOMAXPROCS=8: CPU quota undefined"}
{"level":"info","ts":1780489817.7275689,"msg":"GOMEMLIMIT is updated","package":"github.com/KimMachineGun/automemlimit/memlimit","GOMEMLIMIT":Claude helped me pinpoint this to missing env variables in the proxy service. Here are the changes I made: x-proxy-env: &proxy-env
APP_DOMAIN: ${APP_DOMAIN:-localhost}
FILE_SIZE_LIMIT: ${FILE_SIZE_LIMIT:-5242880}
BUCKET_NAME: ${AWS_S3_BUCKET_NAME:-uploads}
SITE_ADDRESS: ${SITE_ADDRESS:-:80} # ← added
TRUSTED_PROXIES: ${TRUSTED_PROXIES:-0.0.0.0/0} # ← addedAnd in my environment file I added Things are now working correctly. Btw, and I'm unsure how to go about that, but I feel like a default env file with all the variables listed + comments, allowing the user to quickly fill them out would be nice. I used Claude again for this job (extracting the necessary variables) |
…le crash
The plane-proxy Caddyfile.ce ends with a `{$SITE_ADDRESS} { import plane_proxy }`
block. SITE_ADDRESS has no inline default upstream, so when it is unset the block
becomes keyless and Caddy aborts with:
adapting config using caddyfile: server block without any key is global
configuration, and if used, it must be first
Expose SITE_ADDRESS (:80, matching the proxy `expose: ["80"]` + domain port 80,
since Dokploy terminates TLS upstream) and TRUSTED_PROXIES (0.0.0.0/0, matching
the Caddyfile inline default) on the proxy env, and document both in template.toml
so they render into the generated env. Reported and verified by @RDeluxe in Dokploy#912.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Thanks a lot for testing on a real instance and pinpointing this, @RDeluxe! 🙏 You're exactly right. The {$SITE_ADDRESS} {
import plane_proxy
}
I've applied your fix in
Re: the default env file with comments — agreed it'd be a nice DX improvement, but I'll keep it out of this PR to stay focused on the version bump + fixes. Worth a follow-up. Thanks again! |
…oofing) Defaulting TRUSTED_PROXIES to 0.0.0.0/0 makes Caddy trust X-Forwarded-For / X-Real-IP from any peer, allowing client-IP spoofing (CWE-348 / CWE-290) that poisons rate-limiting and audit logs. In Dokploy the only upstream is Traefik on the private dokploy-network, so trust Caddy's built-in `private_ranges` token instead. Legitimate forwarded client IPs (Traefik is a private peer) still resolve correctly; XFF from public-IP peers is rejected if the proxy is ever exposed directly. Overridable via env for custom topologies. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Small follow-up / hardening on the I changed the default from Since Dokploy's only upstream is Traefik on the private |
…rrectly The v1.3.1 rewrite (669ad4a) reordered template.toml so that [[config.domains]] preceded the bare `env = [...]` and `mounts = []` keys. In TOML those keys then attach to the first config.domains table element instead of [config], leaving config.env undefined. Dokploy reads env from config.env, so the base64 export / deploy shipped with no environment variables at all. Move env/mounts back above [[config.domains]] (matching the original template and other blueprints like documenso). config.env now resolves to all 39 entries; the domain table keeps only serviceName/port/host. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Pushed one more fix to this branch. While testing the base64 template export, I noticed it shipped with no environment variables at all. Root cause was a TOML structure regression in the v1.3.1 rewrite: Fix: moved |
Add a "# ..." comment string before every entry in config.env, grouped into labelled sections (Application, PostgreSQL, Redis, RabbitMQ, storage, proxy, runtime) with blank-line separators. Because Dokploy renders config.env entries verbatim into the generated .env, these comment strings carry the documentation into the deployed .env file (TOML # comments would be stripped at parse time and never reach it). Same pattern already used by discord-tickets, garage-with-ui, tooljet and rustfs. No variable values changed; all 39 vars preserved. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
What is this PR about?
Update the Plane template from v0.27.1 to v1.3.1 (latest stable), refactor the compose file for reliability, and fix several bugs in the current
template.toml.Image bumps
makeplane/plane-frontend,plane-space,plane-admin,plane-live,plane-backend,plane-proxy:v0.27.1→v1.3.1valkey/valkey:7.2.5-alpine→7.2.11-alpineminio/minio:latest→RELEASE.2025-04-22T22-12-26Z(pinned to the last release before MinIO removed the admin console from the community edition)postgres,rabbitmq: kept (17-alpine,3.13.6-management-alpine) to avoid breaking existing deploymentsdocker-compose.ymlimprovementsx-db-env,x-redis-env,x-app-env, ...) and<<: [*anchor]merges to eliminate duplicated env acrossapi/worker/beat-worker/migrator/liveenv_file: [.env]to inlineenvironment:(matches the repo convention; Dokploy injects env viatemplate.toml)restart: unless-stoppedto every long-running service;restart: on-failureonmigratorhealthchecktoplane-db,plane-redis,plane-mqapi/worker/beat-workernow wait formigratorviacondition: service_completed_successfully— fixes a race where the backend booted before the Django schema was migratedproxyusesexpose: ["80"](no host port mapping, per the validator rule)template.tomlimprovements (bug fixes)RABBITMQ_DEFAULT_USERwas the literal string"rabbitmq_user"instead of a variable reference, so the broker user ended up asrabbitmq_userwhileAMQP_URLexpected something else. Now fixed toplaneconsistently.WEB_URL=${Domain}was missing thehttps://scheme, which broke OAuth callback URLs and email links emitted by the backend. NowWEB_URL=https://${main_domain}.DATABASE_URL/AMQP_URLreferenced inline vars (${POSTGRES_USER},${MINIO_ROOT_USER}) that Dokploy does not resolve inside[config.env]— only[variables]references and helpers work. Now built directly from[variables].NGINX_PORT(Plane uses Caddy in v1.x),SENTRY_DSN,SENTRY_ENVIRONMENT.WEBHOOK_ALLOWED_IPS=""andWEBHOOK_ALLOWED_HOSTS=""— Plane v1.x ships an SSRF guard for webhooks that blocks private IPs by default; exposing these as empty strings makes the intended posture explicit and discoverable.APP_RELEASEto[variables]so users can pick the image tag via the Dokploy UI without editing env directly.Logo
blueprints/plane/plane.pngupdated to the current Plane brand logo.Checklist
docker compose config,validate-docker-compose.ts,validate-template.tsall pass with zero errors)meta.jsonprocessed withnode build-scripts/process-meta.js(only the version bump appears in the diff)Issues related
N/A — proactive maintenance update.
Testing notes
Validated locally with the repo's own scripts:
docker compose -f blueprints/plane/docker-compose.yml config→ exit 0tsx build-scripts/validate-docker-compose.ts→ 13 services detected, structure validtsx build-scripts/validate-template.ts→ 7 variables processed, structure validA full end-to-end smoke test (admin signup, project + issue + MinIO upload, live WebSocket "users online") can be run from the auto-generated PR preview.