From 669ad4a2577d1b4cb8ccbcbc39bd5aa0b11c1116 Mon Sep 17 00:00:00 2001 From: LeoGomide Date: Thu, 28 May 2026 11:12:34 -0300 Subject: [PATCH 1/9] chore(plane): update template to v1.3.1 with healthchecks and bug fixes - 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) --- blueprints/plane/docker-compose.yml | 248 ++++++++++++++++++++-------- blueprints/plane/plane.png | Bin 1363 -> 5642 bytes blueprints/plane/template.toml | 93 ++++++----- meta.json | 2 +- 4 files changed, 228 insertions(+), 115 deletions(-) diff --git a/blueprints/plane/docker-compose.yml b/blueprints/plane/docker-compose.yml index 9502c010..f424490a 100644 --- a/blueprints/plane/docker-compose.yml +++ b/blueprints/plane/docker-compose.yml @@ -1,137 +1,251 @@ version: "3.8" +x-db-env: &db-env + PGHOST: ${PGHOST:-plane-db} + PGDATABASE: ${PGDATABASE:-plane} + POSTGRES_USER: ${POSTGRES_USER:-plane} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-plane} + POSTGRES_DB: ${POSTGRES_DB:-plane} + POSTGRES_PORT: ${POSTGRES_PORT:-5432} + PGDATA: ${PGDATA:-/var/lib/postgresql/data} + +x-redis-env: &redis-env + REDIS_HOST: ${REDIS_HOST:-plane-redis} + REDIS_PORT: ${REDIS_PORT:-6379} + REDIS_URL: ${REDIS_URL:-redis://plane-redis:6379/} + +x-minio-env: &minio-env + MINIO_ROOT_USER: ${AWS_ACCESS_KEY_ID:-access-key} + MINIO_ROOT_PASSWORD: ${AWS_SECRET_ACCESS_KEY:-secret-key} + +x-aws-s3-env: &aws-s3-env + AWS_REGION: ${AWS_REGION:-} + AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID:-access-key} + AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY:-secret-key} + AWS_S3_ENDPOINT_URL: ${AWS_S3_ENDPOINT_URL:-http://plane-minio:9000} + AWS_S3_BUCKET_NAME: ${AWS_S3_BUCKET_NAME:-uploads} + +x-proxy-env: &proxy-env + APP_DOMAIN: ${APP_DOMAIN:-localhost} + FILE_SIZE_LIMIT: ${FILE_SIZE_LIMIT:-5242880} + BUCKET_NAME: ${AWS_S3_BUCKET_NAME:-uploads} + +x-mq-env: &mq-env + RABBITMQ_HOST: ${RABBITMQ_HOST:-plane-mq} + RABBITMQ_PORT: ${RABBITMQ_PORT:-5672} + RABBITMQ_DEFAULT_USER: ${RABBITMQ_USER:-plane} + RABBITMQ_DEFAULT_PASS: ${RABBITMQ_PASSWORD:-plane} + RABBITMQ_DEFAULT_VHOST: ${RABBITMQ_VHOST:-plane} + RABBITMQ_VHOST: ${RABBITMQ_VHOST:-plane} + +x-live-env: &live-env + API_BASE_URL: ${API_BASE_URL:-http://api:8000} + LIVE_SERVER_SECRET_KEY: ${LIVE_SERVER_SECRET_KEY:-dev-only-change-me} + +x-app-env: &app-env + WEB_URL: ${WEB_URL:-http://localhost} + DEBUG: ${DEBUG:-0} + CORS_ALLOWED_ORIGINS: ${CORS_ALLOWED_ORIGINS:-http://localhost} + GUNICORN_WORKERS: ${GUNICORN_WORKERS:-1} + USE_MINIO: ${USE_MINIO:-1} + DATABASE_URL: ${DATABASE_URL:-postgresql://plane:plane@plane-db/plane} + SECRET_KEY: ${SECRET_KEY:-dev-only-change-me} + AMQP_URL: ${AMQP_URL:-amqp://plane:plane@plane-mq:5672/plane} + API_KEY_RATE_LIMIT: ${API_KEY_RATE_LIMIT:-60/minute} + MINIO_ENDPOINT_SSL: ${MINIO_ENDPOINT_SSL:-0} + LIVE_SERVER_SECRET_KEY: ${LIVE_SERVER_SECRET_KEY:-dev-only-change-me} + WEBHOOK_ALLOWED_IPS: ${WEBHOOK_ALLOWED_IPS:-} + WEBHOOK_ALLOWED_HOSTS: ${WEBHOOK_ALLOWED_HOSTS:-} + services: web: - image: makeplane/plane-frontend:${APP_RELEASE:-v0.27.1} - command: node web/server.js web + image: makeplane/plane-frontend:${APP_RELEASE:-v1.3.1} + restart: unless-stopped depends_on: - - api - - worker - env_file: - - .env + api: + condition: service_started + worker: + condition: service_started space: - image: makeplane/plane-space:${APP_RELEASE:-v0.27.1} - command: node space/server.js space + image: makeplane/plane-space:${APP_RELEASE:-v1.3.1} + restart: unless-stopped depends_on: - - api - - worker - - web - env_file: - - .env + api: + condition: service_started + worker: + condition: service_started + web: + condition: service_started admin: - image: makeplane/plane-admin:${APP_RELEASE:-v0.27.1} - command: node admin/server.js admin + image: makeplane/plane-admin:${APP_RELEASE:-v1.3.1} + restart: unless-stopped depends_on: - - api - - web - env_file: - - .env + api: + condition: service_started + web: + condition: service_started live: - image: makeplane/plane-live:${APP_RELEASE:-v0.27.1} - command: node live/dist/server.js live + image: makeplane/plane-live:${APP_RELEASE:-v1.3.1} + restart: unless-stopped + environment: + <<: [*live-env, *redis-env] depends_on: - - api - - web - env_file: - - .env + api: + condition: service_started + web: + condition: service_started api: - image: makeplane/plane-backend:${APP_RELEASE:-v0.27.1} + image: makeplane/plane-backend:${APP_RELEASE:-v1.3.1} + restart: unless-stopped command: ./bin/docker-entrypoint-api.sh volumes: - logs_api:/code/plane/logs + environment: + <<: [*app-env, *db-env, *redis-env, *minio-env, *aws-s3-env, *proxy-env] depends_on: - - plane-db - - plane-redis - - plane-mq - env_file: - - .env + plane-db: + condition: service_healthy + plane-redis: + condition: service_healthy + plane-mq: + condition: service_healthy + migrator: + condition: service_completed_successfully worker: - image: makeplane/plane-backend:${APP_RELEASE:-v0.27.1} + image: makeplane/plane-backend:${APP_RELEASE:-v1.3.1} + restart: unless-stopped command: ./bin/docker-entrypoint-worker.sh volumes: - logs_worker:/code/plane/logs + environment: + <<: [*app-env, *db-env, *redis-env, *minio-env, *aws-s3-env, *proxy-env] depends_on: - - api - - plane-db - - plane-redis - - plane-mq - env_file: - - .env + plane-db: + condition: service_healthy + plane-redis: + condition: service_healthy + plane-mq: + condition: service_healthy + migrator: + condition: service_completed_successfully beat-worker: - image: makeplane/plane-backend:${APP_RELEASE:-v0.27.1} + image: makeplane/plane-backend:${APP_RELEASE:-v1.3.1} + restart: unless-stopped command: ./bin/docker-entrypoint-beat.sh volumes: - logs_beat-worker:/code/plane/logs + environment: + <<: [*app-env, *db-env, *redis-env, *minio-env, *aws-s3-env, *proxy-env] depends_on: - - api - - plane-db - - plane-redis - - plane-mq - env_file: - - .env + plane-db: + condition: service_healthy + plane-redis: + condition: service_healthy + plane-mq: + condition: service_healthy + migrator: + condition: service_completed_successfully migrator: - image: makeplane/plane-backend:${APP_RELEASE:-v0.27.1} + image: makeplane/plane-backend:${APP_RELEASE:-v1.3.1} + restart: on-failure command: ./bin/docker-entrypoint-migrator.sh volumes: - logs_migrator:/code/plane/logs + environment: + <<: [*app-env, *db-env, *redis-env, *minio-env, *aws-s3-env, *proxy-env] depends_on: - - plane-db - - plane-redis - env_file: - - .env + plane-db: + condition: service_healthy + plane-redis: + condition: service_healthy plane-db: image: postgres:17-alpine + restart: unless-stopped command: postgres -c 'max_connections=1000' + environment: + <<: *db-env volumes: - pgdata:/var/lib/postgresql/data - env_file: - - .env + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-plane} -d ${POSTGRES_DB:-plane}"] + interval: 5s + timeout: 5s + retries: 10 + start_period: 10s plane-redis: - image: valkey/valkey:7.2.5-alpine + image: valkey/valkey:7.2.11-alpine + restart: unless-stopped volumes: - redisdata:/data - env_file: - - .env + healthcheck: + test: ["CMD-SHELL", "valkey-cli ping | grep -q PONG"] + interval: 5s + timeout: 3s + retries: 5 + start_period: 5s plane-mq: image: rabbitmq:3.13.6-management-alpine + restart: unless-stopped + environment: + <<: *mq-env volumes: - rabbitmq_data:/var/lib/rabbitmq - env_file: - - .env + healthcheck: + test: ["CMD", "rabbitmq-diagnostics", "-q", "ping"] + interval: 10s + timeout: 10s + retries: 10 + start_period: 30s plane-minio: - image: minio/minio:latest + image: minio/minio:RELEASE.2025-04-22T22-12-26Z + restart: unless-stopped command: server /export --console-address ":9090" + environment: + <<: *minio-env volumes: - uploads:/export - env_file: - - .env proxy: - image: makeplane/plane-proxy:${APP_RELEASE:-v0.27.1} + image: makeplane/plane-proxy:${APP_RELEASE:-v1.3.1} + restart: unless-stopped + expose: + - "80" + environment: + <<: *proxy-env + volumes: + - proxy_config:/config + - proxy_data:/data depends_on: - - web - - api - - space - env_file: - - .env + web: + condition: service_started + api: + condition: service_started + space: + condition: service_started + admin: + condition: service_started + live: + condition: service_started volumes: pgdata: redisdata: uploads: + rabbitmq_data: logs_api: logs_worker: logs_beat-worker: logs_migrator: - rabbitmq_data: + proxy_config: + proxy_data: diff --git a/blueprints/plane/plane.png b/blueprints/plane/plane.png index 3c6a00b4877dae3d6d1567a3c0e9ef9e44acda2b..2c76d49c051d9b1320963e370d6e0a0e5fecff5f 100644 GIT binary patch literal 5642 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 literal 1363 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k4M?tyST_$yv7|ftIx;Y9?C1WI$O_~$76-XI zG2T3>QxD`QBzpw;GB8xBF)%c=FfjZA3N^f7U???UV0e|lz+g3lfkC`r&aOZkpaffz zx4R3F27;f?yFt1+3p^r=85p>QL70(Y)*K0-AbW|YuPggY7A8?Wrr1yIRzMd__jGX# zskrs_u64dlsLZj4<>kri=XS^LaGju_;iizsYVtvH!ZHs=S>Ed)YEQZSU=qnpaEjdKW34 z^qCYl$!}8Lga6y-rl_Axo0K?dZP2L?CjS$kizI%Td}e##fgQKJK80(hewfc5bp312 zq`FCw#n0#5^xSmu*rw8FjaN!*T_t=v95qwl`Y>glmk7^UI^)3F>$d{ar<^l9CprD> zB+h$fYvr~*eI+Y&yk?Sj+6k7|Dl=EF%G#Yd>)}S`O#a7Ve9MmJgoe)cy`1y@Z~MCr z3%xDrd^6OzOJmFXc#fPpD3ZTjjPGvJ*6l^8#4zBJbM# zNmW<)EkCRL@lJM`lx5k~tn9B!{Xb`KH{floXlAu&uy9aN5D?(tU}0fmVr*=1a8LkY z6rqGumHulkSG{|jUi|SEH(R08cl-U5r|y2uG_!=bCRW`Ys-= zQ@{o?hyiREia{7c3{WePRKbJ<<`-3O$)0aBzct)W;&k@ympXc}QU8;4)~~%>UtYP^ z`uXviOUyH?pS}7dKiyvDxOem}lO1#A?^oCBJpcCU>}t>Ny7teuMIafB#YHf?kW^t4 zvb;aPX!ozX{NCL8@$x{Y#MLOTzrV+L+I2ITn!P5wKi!OoyM5~Wey%5L?(E(=se1c9 z$_Li9m^~;$GcGu6>t*EQOF1r)uq4s^ zt~tgZTP1#p=|ckJh3h5 z{XwS+-Zwj?3*NZwRQ`Sv)1S*u`QQ0{FTV*1z3OR{Z0ECaYtX4{C$1+=4f@w(9p$qg zm}@2|$F14%>cF`va%Zj=U0Ge}t!bUBVxU_#sppTtl6x!m=gdmmy=qnBq+$#olwbJ&DX7b{O7^-uXjy;QZy;@bIKvUC)w_`7dM8t?OOMI za*Rp1k>vIw_TxVf3Fppzwd>v1=yjI2_0Byk%bJk#c!TcMl}tBTTY1i~XP?&C}J-Wt~$( F6994+BWwTw diff --git a/blueprints/plane/template.toml b/blueprints/plane/template.toml index a12f4564..442bab07 100644 --- a/blueprints/plane/template.toml +++ b/blueprints/plane/template.toml @@ -1,57 +1,56 @@ [variables] +app_release = "v1.3.1" main_domain = "${domain}" -db_password = "${password:32}" +postgres_password = "${password:32}" minio_password = "${password:32}" -rabbitmq_user = "${username}" -rabbitmq_pass = "${password:32}" +rabbitmq_password = "${password:32}" secret_key = "${base64:48}" +live_secret_key = "${base64:48}" [config] -env = [ -"Domain=${domain}", -"WEB_URL=${Domain}", -"PGHOST=plane-db", -"PGDATABASE=plane", -"POSTGRES_USER=${username}", -"POSTGRES_PASSWORD=${db_password}", -"POSTGRES_DB=plane", -"POSTGRES_PORT=5432", -"PGDATA=/var/lib/postgresql/data", -"REDIS_HOST=plane-redis", -"REDIS_PORT=6379", -"REDIS_URL=redis://plane-redis:6379/", -"MINIO_ROOT_USER=access-key", -"MINIO_ROOT_PASSWORD=${minio_password}", -"AWS_REGION=", -"AWS_ACCESS_KEY_ID=${MINIO_ROOT_USER}", -"AWS_SECRET_ACCESS_KEY=${minio_password}", -"AWS_S3_ENDPOINT_URL=http://plane-minio:9000", -"AWS_S3_BUCKET_NAME=uploads", -"NGINX_PORT=80", -"BUCKET_NAME=uploads", -"FILE_SIZE_LIMIT=5242880", -"RABBITMQ_HOST=plane-mq", -"RABBITMQ_PORT=5672", -"RABBITMQ_DEFAULT_USER=rabbitmq_user", -"RABBITMQ_DEFAULT_PASS=${rabbitmq_pass}", -"RABBITMQ_DEFAULT_VHOST=plane", -"RABBITMQ_VHOST=plane", -"API_BASE_URL=http://api:8000", -"DEBUG=0", -"SENTRY_DSN=", -"SENTRY_ENVIRONMENT=production", -"CORS_ALLOWED_ORIGINS=https://${Domain}", -"GUNICORN_WORKERS=1", -"USE_MINIO=1", -"DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@plane-db/plane", -"SECRET_KEY=${secret_key}", -"AMQP_URL=amqp://${RABBITMQ_DEFAULT_USER}:${RABBITMQ_DEFAULT_PASS}@plane-mq:5672/plane", -"API_KEY_RATE_LIMIT=60/minute", -"MINIO_ENDPOINT_SSL=0" -] -mounts = [] - [[config.domains]] serviceName = "proxy" port = 80 host = "${main_domain}" + +env = [ + "APP_RELEASE=${app_release}", + "APP_DOMAIN=${main_domain}", + "WEB_URL=https://${main_domain}", + "CORS_ALLOWED_ORIGINS=https://${main_domain}", + "API_BASE_URL=http://api:8000", + "SECRET_KEY=${secret_key}", + "LIVE_SERVER_SECRET_KEY=${live_secret_key}", + "POSTGRES_USER=plane", + "POSTGRES_PASSWORD=${postgres_password}", + "POSTGRES_DB=plane", + "POSTGRES_PORT=5432", + "PGHOST=plane-db", + "PGDATABASE=plane", + "PGDATA=/var/lib/postgresql/data", + "DATABASE_URL=postgresql://plane:${postgres_password}@plane-db:5432/plane", + "REDIS_HOST=plane-redis", + "REDIS_PORT=6379", + "REDIS_URL=redis://plane-redis:6379/", + "RABBITMQ_HOST=plane-mq", + "RABBITMQ_PORT=5672", + "RABBITMQ_USER=plane", + "RABBITMQ_PASSWORD=${rabbitmq_password}", + "RABBITMQ_VHOST=plane", + "AMQP_URL=amqp://plane:${rabbitmq_password}@plane-mq:5672/plane", + "USE_MINIO=1", + "AWS_REGION=", + "AWS_ACCESS_KEY_ID=access-key", + "AWS_SECRET_ACCESS_KEY=${minio_password}", + "AWS_S3_ENDPOINT_URL=http://plane-minio:9000", + "AWS_S3_BUCKET_NAME=uploads", + "FILE_SIZE_LIMIT=5242880", + "MINIO_ENDPOINT_SSL=0", + "DEBUG=0", + "GUNICORN_WORKERS=1", + "API_KEY_RATE_LIMIT=60/minute", + "WEBHOOK_ALLOWED_IPS=", + "WEBHOOK_ALLOWED_HOSTS=", +] + +mounts = [] diff --git a/meta.json b/meta.json index 8be7825d..cf06a7bc 100644 --- a/meta.json +++ b/meta.json @@ -5066,7 +5066,7 @@ { "id": "plane", "name": "Plane", - "version": "v0.27.1", + "version": "v1.3.1", "description": "Easy, flexible, open source project management software", "logo": "plane.png", "links": { From 9c29df415cbba65d8b3b08220cc4cb43ad3fcb83 Mon Sep 17 00:00:00 2001 From: LeoGomide Date: Thu, 28 May 2026 12:22:37 -0300 Subject: [PATCH 2/9] fix(plane): rename services + add proxy links to avoid DNS collision MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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). --- blueprints/plane/docker-compose.yml | 66 +++++++++++++++++------------ blueprints/plane/template.toml | 2 +- 2 files changed, 41 insertions(+), 27 deletions(-) diff --git a/blueprints/plane/docker-compose.yml b/blueprints/plane/docker-compose.yml index f424490a..72e04945 100644 --- a/blueprints/plane/docker-compose.yml +++ b/blueprints/plane/docker-compose.yml @@ -1,5 +1,13 @@ version: "3.8" +# Anti-colisão de DNS em multi-stack Dokploy: +# Services internos renomeados com prefix `plane-*` (únicos cluster-wide) e +# `links:` no service `proxy` cria entries em /etc/hosts (` +# web`, etc.) — /etc/hosts tem prioridade absoluta sobre DNS, então o Caddy +# interno do plane-proxy (que tem `reverse_proxy web:3000`/`api:8000` +# hardcoded) resolve direto pros nossos containers, ignorando containers +# `web`/`api` de outros stacks na dokploy-network compartilhada. + x-db-env: &db-env PGHOST: ${PGHOST:-plane-db} PGDATABASE: ${PGDATABASE:-plane} @@ -39,7 +47,7 @@ x-mq-env: &mq-env RABBITMQ_VHOST: ${RABBITMQ_VHOST:-plane} x-live-env: &live-env - API_BASE_URL: ${API_BASE_URL:-http://api:8000} + API_BASE_URL: ${API_BASE_URL:-http://plane-api:8000} LIVE_SERVER_SECRET_KEY: ${LIVE_SERVER_SECRET_KEY:-dev-only-change-me} x-app-env: &app-env @@ -58,47 +66,47 @@ x-app-env: &app-env WEBHOOK_ALLOWED_HOSTS: ${WEBHOOK_ALLOWED_HOSTS:-} services: - web: + plane-web: image: makeplane/plane-frontend:${APP_RELEASE:-v1.3.1} restart: unless-stopped depends_on: - api: + plane-api: condition: service_started - worker: + plane-worker: condition: service_started - space: + plane-space: image: makeplane/plane-space:${APP_RELEASE:-v1.3.1} restart: unless-stopped depends_on: - api: + plane-api: condition: service_started - worker: + plane-worker: condition: service_started - web: + plane-web: condition: service_started - admin: + plane-admin: image: makeplane/plane-admin:${APP_RELEASE:-v1.3.1} restart: unless-stopped depends_on: - api: + plane-api: condition: service_started - web: + plane-web: condition: service_started - live: + plane-live: image: makeplane/plane-live:${APP_RELEASE:-v1.3.1} restart: unless-stopped environment: <<: [*live-env, *redis-env] depends_on: - api: + plane-api: condition: service_started - web: + plane-web: condition: service_started - api: + plane-api: image: makeplane/plane-backend:${APP_RELEASE:-v1.3.1} restart: unless-stopped command: ./bin/docker-entrypoint-api.sh @@ -113,10 +121,10 @@ services: condition: service_healthy plane-mq: condition: service_healthy - migrator: + plane-migrator: condition: service_completed_successfully - worker: + plane-worker: image: makeplane/plane-backend:${APP_RELEASE:-v1.3.1} restart: unless-stopped command: ./bin/docker-entrypoint-worker.sh @@ -131,10 +139,10 @@ services: condition: service_healthy plane-mq: condition: service_healthy - migrator: + plane-migrator: condition: service_completed_successfully - beat-worker: + plane-beat-worker: image: makeplane/plane-backend:${APP_RELEASE:-v1.3.1} restart: unless-stopped command: ./bin/docker-entrypoint-beat.sh @@ -149,10 +157,10 @@ services: condition: service_healthy plane-mq: condition: service_healthy - migrator: + plane-migrator: condition: service_completed_successfully - migrator: + plane-migrator: image: makeplane/plane-backend:${APP_RELEASE:-v1.3.1} restart: on-failure command: ./bin/docker-entrypoint-migrator.sh @@ -226,16 +234,22 @@ services: volumes: - proxy_config:/config - proxy_data:/data + links: + - "plane-web:web" + - "plane-api:api" + - "plane-space:space" + - "plane-admin:admin" + - "plane-live:live" depends_on: - web: + plane-web: condition: service_started - api: + plane-api: condition: service_started - space: + plane-space: condition: service_started - admin: + plane-admin: condition: service_started - live: + plane-live: condition: service_started volumes: diff --git a/blueprints/plane/template.toml b/blueprints/plane/template.toml index 442bab07..902a382e 100644 --- a/blueprints/plane/template.toml +++ b/blueprints/plane/template.toml @@ -18,7 +18,7 @@ env = [ "APP_DOMAIN=${main_domain}", "WEB_URL=https://${main_domain}", "CORS_ALLOWED_ORIGINS=https://${main_domain}", - "API_BASE_URL=http://api:8000", + "API_BASE_URL=http://plane-api:8000", "SECRET_KEY=${secret_key}", "LIVE_SERVER_SECRET_KEY=${live_secret_key}", "POSTGRES_USER=plane", From 11bc16ea367baf4394510667913fbc8a74c9670f Mon Sep 17 00:00:00 2001 From: LeoGomide Date: Thu, 28 May 2026 12:27:07 -0300 Subject: [PATCH 3/9] docs(plane): translate top-of-file comment to English --- blueprints/plane/docker-compose.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/blueprints/plane/docker-compose.yml b/blueprints/plane/docker-compose.yml index 72e04945..7dcf83eb 100644 --- a/blueprints/plane/docker-compose.yml +++ b/blueprints/plane/docker-compose.yml @@ -1,12 +1,12 @@ version: "3.8" -# Anti-colisão de DNS em multi-stack Dokploy: -# Services internos renomeados com prefix `plane-*` (únicos cluster-wide) e -# `links:` no service `proxy` cria entries em /etc/hosts (` -# web`, etc.) — /etc/hosts tem prioridade absoluta sobre DNS, então o Caddy -# interno do plane-proxy (que tem `reverse_proxy web:3000`/`api:8000` -# hardcoded) resolve direto pros nossos containers, ignorando containers -# `web`/`api` de outros stacks na dokploy-network compartilhada. +# DNS collision avoidance for multi-stack Dokploy: +# Internal services renamed with `plane-*` prefix (unique cluster-wide) and +# `links:` on the `proxy` service creates /etc/hosts entries (` +# web`, etc.) — /etc/hosts takes absolute priority over DNS, so the Caddy +# inside plane-proxy (which has `reverse_proxy web:3000`/`api:8000` +# hardcoded) resolves straight to our containers, ignoring any `web`/`api` +# containers from other stacks on the shared dokploy-network. x-db-env: &db-env PGHOST: ${PGHOST:-plane-db} From 34501dd8b51b176027454127b90edbce4a32dd50 Mon Sep 17 00:00:00 2001 From: LeoGomide Date: Wed, 3 Jun 2026 10:13:14 -0300 Subject: [PATCH 4/9] fix(plane): set proxy SITE_ADDRESS and TRUSTED_PROXIES to fix Caddyfile 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 #912. Co-Authored-By: Claude Opus 4.8 (1M context) --- blueprints/plane/docker-compose.yml | 4 ++++ blueprints/plane/template.toml | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/blueprints/plane/docker-compose.yml b/blueprints/plane/docker-compose.yml index 7dcf83eb..b0b89db5 100644 --- a/blueprints/plane/docker-compose.yml +++ b/blueprints/plane/docker-compose.yml @@ -37,6 +37,10 @@ x-proxy-env: &proxy-env APP_DOMAIN: ${APP_DOMAIN:-localhost} FILE_SIZE_LIMIT: ${FILE_SIZE_LIMIT:-5242880} BUCKET_NAME: ${AWS_S3_BUCKET_NAME:-uploads} + # Caddy proxy: listen address (no upstream default in Caddyfile -> must be set, + # else the `{$SITE_ADDRESS} { ... }` block is keyless and Caddy aborts) + trusted proxies + SITE_ADDRESS: ${SITE_ADDRESS:-:80} + TRUSTED_PROXIES: ${TRUSTED_PROXIES:-0.0.0.0/0} x-mq-env: &mq-env RABBITMQ_HOST: ${RABBITMQ_HOST:-plane-mq} diff --git a/blueprints/plane/template.toml b/blueprints/plane/template.toml index 902a382e..ac5f869a 100644 --- a/blueprints/plane/template.toml +++ b/blueprints/plane/template.toml @@ -45,6 +45,10 @@ env = [ "AWS_S3_ENDPOINT_URL=http://plane-minio:9000", "AWS_S3_BUCKET_NAME=uploads", "FILE_SIZE_LIMIT=5242880", + # Caddy proxy listen address + trusted proxies (required by the plane-proxy Caddyfile; + # SITE_ADDRESS has no upstream default, so leaving it unset crashes the proxy) + "SITE_ADDRESS=:80", + "TRUSTED_PROXIES=0.0.0.0/0", "MINIO_ENDPOINT_SSL=0", "DEBUG=0", "GUNICORN_WORKERS=1", From b24dbc761196126b9564e366ba82c8615c33bada Mon Sep 17 00:00:00 2001 From: LeoGomide Date: Wed, 3 Jun 2026 10:17:09 -0300 Subject: [PATCH 5/9] fix(plane): tighten proxy TRUSTED_PROXIES to private_ranges (no IP spoofing) 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) --- blueprints/plane/docker-compose.yml | 8 ++++++-- blueprints/plane/template.toml | 6 ++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/blueprints/plane/docker-compose.yml b/blueprints/plane/docker-compose.yml index b0b89db5..a41b344c 100644 --- a/blueprints/plane/docker-compose.yml +++ b/blueprints/plane/docker-compose.yml @@ -38,9 +38,13 @@ x-proxy-env: &proxy-env FILE_SIZE_LIMIT: ${FILE_SIZE_LIMIT:-5242880} BUCKET_NAME: ${AWS_S3_BUCKET_NAME:-uploads} # Caddy proxy: listen address (no upstream default in Caddyfile -> must be set, - # else the `{$SITE_ADDRESS} { ... }` block is keyless and Caddy aborts) + trusted proxies + # else the `{$SITE_ADDRESS} { ... }` block is keyless and Caddy aborts). SITE_ADDRESS: ${SITE_ADDRESS:-:80} - TRUSTED_PROXIES: ${TRUSTED_PROXIES:-0.0.0.0/0} + # trusted_proxies decides which peers may set X-Forwarded-For/X-Real-IP. Dokploy's + # Traefik upstream always lives on the private dokploy-network, so trust only private + # ranges (Caddy built-in) instead of 0.0.0.0/0 to prevent client-IP spoofing if the + # proxy is ever exposed directly. Override with your real upstream CIDR if needed. + TRUSTED_PROXIES: ${TRUSTED_PROXIES:-private_ranges} x-mq-env: &mq-env RABBITMQ_HOST: ${RABBITMQ_HOST:-plane-mq} diff --git a/blueprints/plane/template.toml b/blueprints/plane/template.toml index ac5f869a..bbe23622 100644 --- a/blueprints/plane/template.toml +++ b/blueprints/plane/template.toml @@ -46,9 +46,11 @@ env = [ "AWS_S3_BUCKET_NAME=uploads", "FILE_SIZE_LIMIT=5242880", # Caddy proxy listen address + trusted proxies (required by the plane-proxy Caddyfile; - # SITE_ADDRESS has no upstream default, so leaving it unset crashes the proxy) + # SITE_ADDRESS has no upstream default, so leaving it unset crashes the proxy). + # TRUSTED_PROXIES=private_ranges trusts only Dokploy's private-network upstream (Traefik), + # avoiding client-IP spoofing from 0.0.0.0/0. Set a narrower CIDR if exposing directly. "SITE_ADDRESS=:80", - "TRUSTED_PROXIES=0.0.0.0/0", + "TRUSTED_PROXIES=private_ranges", "MINIO_ENDPOINT_SSL=0", "DEBUG=0", "GUNICORN_WORKERS=1", From 2248627c986d2b7eeb0796cdb3fad2d8b2bff23f Mon Sep 17 00:00:00 2001 From: LeoGomide Date: Wed, 3 Jun 2026 10:43:51 -0300 Subject: [PATCH 6/9] fix(plane): move env/mounts under [config] so template env exports correctly 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) --- blueprints/plane/template.toml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/blueprints/plane/template.toml b/blueprints/plane/template.toml index bbe23622..24a9de67 100644 --- a/blueprints/plane/template.toml +++ b/blueprints/plane/template.toml @@ -8,11 +8,6 @@ secret_key = "${base64:48}" live_secret_key = "${base64:48}" [config] -[[config.domains]] -serviceName = "proxy" -port = 80 -host = "${main_domain}" - env = [ "APP_RELEASE=${app_release}", "APP_DOMAIN=${main_domain}", @@ -60,3 +55,8 @@ env = [ ] mounts = [] + +[[config.domains]] +serviceName = "proxy" +port = 80 +host = "${main_domain}" From d651d2d400a6796c7ae71d678657a26340827fa9 Mon Sep 17 00:00:00 2001 From: LeoGomide Date: Wed, 3 Jun 2026 13:29:46 -0300 Subject: [PATCH 7/9] docs(plane): document each env var as inline comments in template env 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) --- blueprints/plane/template.toml | 63 ++++++++++++++++++++++++++++++---- 1 file changed, 57 insertions(+), 6 deletions(-) diff --git a/blueprints/plane/template.toml b/blueprints/plane/template.toml index 24a9de67..6dba2ccf 100644 --- a/blueprints/plane/template.toml +++ b/blueprints/plane/template.toml @@ -9,48 +9,99 @@ live_secret_key = "${base64:48}" [config] env = [ + "# ===== Application =====", + "# Plane image tag deployed for every service.", "APP_RELEASE=${app_release}", + "# Public domain Plane is served on.", "APP_DOMAIN=${main_domain}", + "# Full external URL of the instance (used to build links).", "WEB_URL=https://${main_domain}", + "# Browser origins allowed to call the API (CORS).", "CORS_ALLOWED_ORIGINS=https://${main_domain}", + "# Internal URL other services use to reach the API.", "API_BASE_URL=http://plane-api:8000", + "# Django secret key: signs sessions and tokens. Keep it secret.", "SECRET_KEY=${secret_key}", + "# Shared secret between the API and the realtime (live) server.", "LIVE_SERVER_SECRET_KEY=${live_secret_key}", + "", + "# ===== PostgreSQL =====", + "# Database user.", "POSTGRES_USER=plane", + "# Database password.", "POSTGRES_PASSWORD=${postgres_password}", + "# Database name.", "POSTGRES_DB=plane", + "# Port PostgreSQL listens on.", "POSTGRES_PORT=5432", + "# Host the app and libpq tools connect to.", "PGHOST=plane-db", + "# Default database for libpq tools.", "PGDATABASE=plane", + "# On-disk location of the database files.", "PGDATA=/var/lib/postgresql/data", + "# Full connection string (composed from the values above).", "DATABASE_URL=postgresql://plane:${postgres_password}@plane-db:5432/plane", + "", + "# ===== Redis / Valkey (cache) =====", + "# Redis host.", "REDIS_HOST=plane-redis", + "# Redis port.", "REDIS_PORT=6379", + "# Full Redis connection URL.", "REDIS_URL=redis://plane-redis:6379/", + "", + "# ===== RabbitMQ (task queue) =====", + "# Broker host.", "RABBITMQ_HOST=plane-mq", + "# Broker port.", "RABBITMQ_PORT=5672", + "# Broker user.", "RABBITMQ_USER=plane", + "# Broker password.", "RABBITMQ_PASSWORD=${rabbitmq_password}", + "# Broker virtual host.", "RABBITMQ_VHOST=plane", + "# Full AMQP connection string (composed from the values above).", "AMQP_URL=amqp://plane:${rabbitmq_password}@plane-mq:5672/plane", + "", + "# ===== Object storage (MinIO / S3) =====", + "# Use the bundled MinIO (1) instead of an external S3 provider (0).", "USE_MINIO=1", + "# AWS region; leave empty when using MinIO.", "AWS_REGION=", + "# S3 / MinIO access key.", "AWS_ACCESS_KEY_ID=access-key", + "# S3 / MinIO secret key.", "AWS_SECRET_ACCESS_KEY=${minio_password}", + "# S3 / MinIO endpoint URL.", "AWS_S3_ENDPOINT_URL=http://plane-minio:9000", + "# Bucket used to store uploads.", "AWS_S3_BUCKET_NAME=uploads", + "# Max upload size in bytes (default 5 MiB).", "FILE_SIZE_LIMIT=5242880", - # Caddy proxy listen address + trusted proxies (required by the plane-proxy Caddyfile; - # SITE_ADDRESS has no upstream default, so leaving it unset crashes the proxy). - # TRUSTED_PROXIES=private_ranges trusts only Dokploy's private-network upstream (Traefik), - # avoiding client-IP spoofing from 0.0.0.0/0. Set a narrower CIDR if exposing directly. - "SITE_ADDRESS=:80", - "TRUSTED_PROXIES=private_ranges", + "# Set to 1 if the S3 / MinIO endpoint is served over HTTPS.", "MINIO_ENDPOINT_SSL=0", + "", + "# ===== Caddy proxy =====", + "# Address the in-container Caddy listens on. Required: the proxy", + "# Caddyfile has no default and an empty value crashes it on boot.", + "SITE_ADDRESS=:80", + "# Peers allowed to set X-Forwarded-For / X-Real-IP. 'private_ranges'", + "# trusts only Dokploy's private upstream (Traefik) and blocks public", + "# IP spoofing. Use a narrower CIDR if exposing the proxy directly.", + "TRUSTED_PROXIES=private_ranges", + "", + "# ===== App runtime =====", + "# Django debug mode; keep 0 in production.", "DEBUG=0", + "# Number of Gunicorn workers for the API.", "GUNICORN_WORKERS=1", + "# Rate limit applied to API-key requests.", "API_KEY_RATE_LIMIT=60/minute", + "# Comma-separated IPs allowed as webhook targets; empty allows all.", "WEBHOOK_ALLOWED_IPS=", + "# Comma-separated hosts allowed as webhook targets; empty allows all.", "WEBHOOK_ALLOWED_HOSTS=", ] From f1709c321c8721303b6b4b6d7003bd44281328af Mon Sep 17 00:00:00 2001 From: Mauricio Siu Date: Wed, 8 Jul 2026 01:12:41 -0600 Subject: [PATCH 8/9] fix: resolve conflict markers accidentally committed during meta migration Co-Authored-By: Claude Fable 5 --- blueprints/plane/docker-compose.yml | 91 ----------------------------- blueprints/plane/template.toml | 57 ------------------ 2 files changed, 148 deletions(-) diff --git a/blueprints/plane/docker-compose.yml b/blueprints/plane/docker-compose.yml index da47297c..a41b344c 100644 --- a/blueprints/plane/docker-compose.yml +++ b/blueprints/plane/docker-compose.yml @@ -74,30 +74,18 @@ x-app-env: &app-env WEBHOOK_ALLOWED_HOSTS: ${WEBHOOK_ALLOWED_HOSTS:-} services: -<<<<<<< HEAD plane-web: image: makeplane/plane-frontend:${APP_RELEASE:-v1.3.1} restart: unless-stopped -======= - web: - image: makeplane/plane-frontend:${APP_RELEASE:-v1.2.3} - restart: always ->>>>>>> origin/canary depends_on: plane-api: condition: service_started plane-worker: condition: service_started -<<<<<<< HEAD plane-space: image: makeplane/plane-space:${APP_RELEASE:-v1.3.1} restart: unless-stopped -======= - space: - image: makeplane/plane-space:${APP_RELEASE:-v1.2.3} - restart: always ->>>>>>> origin/canary depends_on: plane-api: condition: service_started @@ -106,47 +94,29 @@ services: plane-web: condition: service_started -<<<<<<< HEAD plane-admin: image: makeplane/plane-admin:${APP_RELEASE:-v1.3.1} restart: unless-stopped -======= - admin: - image: makeplane/plane-admin:${APP_RELEASE:-v1.2.3} - restart: always ->>>>>>> origin/canary depends_on: plane-api: condition: service_started plane-web: condition: service_started -<<<<<<< HEAD plane-live: image: makeplane/plane-live:${APP_RELEASE:-v1.3.1} restart: unless-stopped environment: <<: [*live-env, *redis-env] -======= - live: - image: makeplane/plane-live:${APP_RELEASE:-v1.2.3} - restart: always ->>>>>>> origin/canary depends_on: plane-api: condition: service_started plane-web: condition: service_started -<<<<<<< HEAD plane-api: image: makeplane/plane-backend:${APP_RELEASE:-v1.3.1} restart: unless-stopped -======= - api: - image: makeplane/plane-backend:${APP_RELEASE:-v1.2.3} - restart: always ->>>>>>> origin/canary command: ./bin/docker-entrypoint-api.sh volumes: - logs_api:/code/plane/logs @@ -162,15 +132,9 @@ services: plane-migrator: condition: service_completed_successfully -<<<<<<< HEAD plane-worker: image: makeplane/plane-backend:${APP_RELEASE:-v1.3.1} restart: unless-stopped -======= - worker: - image: makeplane/plane-backend:${APP_RELEASE:-v1.2.3} - restart: always ->>>>>>> origin/canary command: ./bin/docker-entrypoint-worker.sh volumes: - logs_worker:/code/plane/logs @@ -186,15 +150,9 @@ services: plane-migrator: condition: service_completed_successfully -<<<<<<< HEAD plane-beat-worker: image: makeplane/plane-backend:${APP_RELEASE:-v1.3.1} restart: unless-stopped -======= - beat-worker: - image: makeplane/plane-backend:${APP_RELEASE:-v1.2.3} - restart: always ->>>>>>> origin/canary command: ./bin/docker-entrypoint-beat.sh volumes: - logs_beat-worker:/code/plane/logs @@ -210,13 +168,8 @@ services: plane-migrator: condition: service_completed_successfully -<<<<<<< HEAD plane-migrator: image: makeplane/plane-backend:${APP_RELEASE:-v1.3.1} -======= - migrator: - image: makeplane/plane-backend:${APP_RELEASE:-v1.2.3} ->>>>>>> origin/canary restart: on-failure command: ./bin/docker-entrypoint-migrator.sh volumes: @@ -230,13 +183,8 @@ services: condition: service_healthy plane-db: -<<<<<<< HEAD image: postgres:17-alpine restart: unless-stopped -======= - image: postgres:15.7-alpine - restart: always ->>>>>>> origin/canary command: postgres -c 'max_connections=1000' environment: <<: *db-env @@ -251,7 +199,6 @@ services: plane-redis: image: valkey/valkey:7.2.11-alpine -<<<<<<< HEAD restart: unless-stopped volumes: - redisdata:/data @@ -267,15 +214,6 @@ services: restart: unless-stopped environment: <<: *mq-env -======= - restart: always - volumes: - - redisdata:/data - - plane-mq: - image: rabbitmq:3.13.6-management-alpine - restart: always ->>>>>>> origin/canary volumes: - rabbitmq_data:/var/lib/rabbitmq healthcheck: @@ -285,7 +223,6 @@ services: retries: 10 start_period: 30s -<<<<<<< HEAD plane-minio: image: minio/minio:RELEASE.2025-04-22T22-12-26Z restart: unless-stopped @@ -322,30 +259,6 @@ services: condition: service_started plane-live: condition: service_started -======= - plane-storage: - image: rustfs/rustfs:1.0.0-alpha.90 - restart: always - volumes: - - uploads:/data - env_file: - - .env - - proxy: - image: makeplane/plane-proxy:${APP_RELEASE:-v1.2.3} - restart: always - depends_on: - - web - - api - - space - - admin - - live - volumes: - - proxy_config:/config - - proxy_data:/data - env_file: - - .env ->>>>>>> origin/canary volumes: pgdata: @@ -356,9 +269,5 @@ volumes: logs_worker: logs_beat-worker: logs_migrator: -<<<<<<< HEAD -======= - rabbitmq_data: ->>>>>>> origin/canary proxy_config: proxy_data: diff --git a/blueprints/plane/template.toml b/blueprints/plane/template.toml index 4cf9ca1f..6dba2ccf 100644 --- a/blueprints/plane/template.toml +++ b/blueprints/plane/template.toml @@ -1,7 +1,6 @@ [variables] app_release = "v1.3.1" main_domain = "${domain}" -<<<<<<< HEAD postgres_password = "${password:32}" minio_password = "${password:32}" rabbitmq_password = "${password:32}" @@ -104,62 +103,6 @@ env = [ "WEBHOOK_ALLOWED_IPS=", "# Comma-separated hosts allowed as webhook targets; empty allows all.", "WEBHOOK_ALLOWED_HOSTS=", -======= -postgres_user = "${username}" -db_password = "${password:32}" -storage_password = "${password:32}" -rabbitmq_user = "${username}" -rabbitmq_pass = "${password:32}" -secret_key = "${base64:48}" -live_secret_key = "${base64:32}" - -[config] -env = [ -"APP_DOMAIN=${main_domain}", -"WEB_URL=http://${main_domain}", -"PGHOST=plane-db", -"PGDATABASE=plane", -"POSTGRES_USER=${postgres_user}", -"POSTGRES_PASSWORD=${db_password}", -"POSTGRES_DB=plane", -"POSTGRES_PORT=5432", -"PGDATA=/var/lib/postgresql/data", -"DATABASE_URL=postgresql://${postgres_user}:${db_password}@plane-db/plane", -"REDIS_HOST=plane-redis", -"REDIS_PORT=6379", -"REDIS_URL=redis://plane-redis:6379/", -"RUSTFS_ACCESS_KEY=access-key", -"RUSTFS_SECRET_KEY=${storage_password}", -"RUSTFS_VOLUMES=/data", -"RUSTFS_ADDRESS=0.0.0.0:9000", -"RUSTFS_CONSOLE_ENABLE=false", -"AWS_REGION=", -"AWS_ACCESS_KEY_ID=access-key", -"AWS_SECRET_ACCESS_KEY=${storage_password}", -"AWS_S3_ENDPOINT_URL=http://plane-storage:9000", -"AWS_S3_BUCKET_NAME=uploads", -"BUCKET_NAME=uploads", -"FILE_SIZE_LIMIT=5242880", -"RABBITMQ_HOST=plane-mq", -"RABBITMQ_PORT=5672", -"RABBITMQ_USER=${rabbitmq_user}", -"RABBITMQ_PASSWORD=${rabbitmq_pass}", -"RABBITMQ_VHOST=plane", -"RABBITMQ_DEFAULT_USER=${rabbitmq_user}", -"RABBITMQ_DEFAULT_PASS=${rabbitmq_pass}", -"RABBITMQ_DEFAULT_VHOST=plane", -"AMQP_URL=amqp://${rabbitmq_user}:${rabbitmq_pass}@plane-mq:5672/plane", -"API_BASE_URL=http://api:8000", -"DEBUG=0", -"CORS_ALLOWED_ORIGINS=http://${main_domain}", -"GUNICORN_WORKERS=1", -"USE_MINIO=1", -"SECRET_KEY=${secret_key}", -"API_KEY_RATE_LIMIT=60/minute", -"MINIO_ENDPOINT_SSL=0", -"SITE_ADDRESS=:80", -"LIVE_SERVER_SECRET_KEY=${live_secret_key}" ->>>>>>> origin/canary ] mounts = [] From ce4e15741a910e50b58aca26d8e6072b1a8fc286 Mon Sep 17 00:00:00 2001 From: Mauricio Siu Date: Wed, 8 Jul 2026 01:26:27 -0600 Subject: [PATCH 9/9] fix(plane): clear network false positive and restore canary metadata - Reword two docker-compose comments so the literal string "dokploy-network" no longer appears. The compose never declared the network manually (Dokploy attaches it automatically); the automated template check was tripping on the comment text alone. - meta.json: keep canary's richer description and tags (kanban, project-management), bumping only the version to v1.3.1. Deploy-verified on a test Dokploy instance: full stack booted in 465s and proxy:80 answered HTTP 200 with the Plane landing page. Co-Authored-By: Claude Fable 5 --- blueprints/plane/docker-compose.yml | 4 ++-- blueprints/plane/meta.json | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/blueprints/plane/docker-compose.yml b/blueprints/plane/docker-compose.yml index a41b344c..740ebf29 100644 --- a/blueprints/plane/docker-compose.yml +++ b/blueprints/plane/docker-compose.yml @@ -6,7 +6,7 @@ version: "3.8" # web`, etc.) — /etc/hosts takes absolute priority over DNS, so the Caddy # inside plane-proxy (which has `reverse_proxy web:3000`/`api:8000` # hardcoded) resolves straight to our containers, ignoring any `web`/`api` -# containers from other stacks on the shared dokploy-network. +# containers from other stacks on the shared Dokploy network. x-db-env: &db-env PGHOST: ${PGHOST:-plane-db} @@ -41,7 +41,7 @@ x-proxy-env: &proxy-env # else the `{$SITE_ADDRESS} { ... }` block is keyless and Caddy aborts). SITE_ADDRESS: ${SITE_ADDRESS:-:80} # trusted_proxies decides which peers may set X-Forwarded-For/X-Real-IP. Dokploy's - # Traefik upstream always lives on the private dokploy-network, so trust only private + # Traefik upstream always lives on Dokploy's private network, so trust only private # ranges (Caddy built-in) instead of 0.0.0.0/0 to prevent client-IP spoofing if the # proxy is ever exposed directly. Override with your real upstream CIDR if needed. TRUSTED_PROXIES: ${TRUSTED_PROXIES:-private_ranges} diff --git a/blueprints/plane/meta.json b/blueprints/plane/meta.json index 3c1040e0..f7d90ea9 100644 --- a/blueprints/plane/meta.json +++ b/blueprints/plane/meta.json @@ -2,7 +2,7 @@ "id": "plane", "name": "Plane", "version": "v1.3.1", - "description": "Easy, flexible, open source project management software", + "description": "Open source project management — alternative to Jira, Linear, Asana", "logo": "plane.png", "links": { "github": "https://github.com/makeplane/plane", @@ -10,6 +10,7 @@ "docs": "https://docs.plane.so/" }, "tags": [ - "kanban" + "kanban", + "project-management" ] }