From d6b8ba4d67329d4a200d9761c7e2904aea0f7e2e Mon Sep 17 00:00:00 2001 From: Mark Henderson Date: Mon, 27 Apr 2026 12:36:44 -0700 Subject: [PATCH] fix(mcp v2.4.4): only attach traefik-enabled containers to coolify proxy net MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v2.4.3 attached every stack container to the `coolify` network so Traefik could reach the public container. But that network also hosts coolify-db (alias `postgres`) and coolify-redis (alias `redis`). Docker's embedded DNS resolves unqualified hostnames to the first container with that name on the network, so once Twenty's `postgres-` joined the coolify network, Twenty's connection string `postgres://postgres:5432/...` started resolving to coolify-db and auth-failing in a tight restart loop. Coolify's own pipeline only attaches the proxied container — filter by the `traefik.enable=true` label so internal stack members (db, redis, worker) stay isolated on the project network. Made-with: Cursor --- app/api/mcp/route.ts | 2 +- lib/coolify-compose.ts | 30 ++++++++++++++++++++++-------- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/app/api/mcp/route.ts b/app/api/mcp/route.ts index 7722d46e..96f1a699 100644 --- a/app/api/mcp/route.ts +++ b/app/api/mcp/route.ts @@ -91,7 +91,7 @@ const GITEA_API_URL = process.env.GITEA_API_URL ?? 'https://git.vibnai.com'; export async function GET() { return NextResponse.json({ name: 'vibn-mcp', - version: '2.4.3', + version: '2.4.4', authentication: { scheme: 'Bearer', tokenPrefix: 'vibn_sk_', diff --git a/lib/coolify-compose.ts b/lib/coolify-compose.ts index a4b9413f..99f922fa 100644 --- a/lib/coolify-compose.ts +++ b/lib/coolify-compose.ts @@ -104,24 +104,38 @@ export async function composeUp( } /** - * Attach every container belonging to this Coolify resource to the - * `coolify` proxy network. Idempotent — `network connect` errors when - * the container is already attached, which we ignore. + * Attach the public-facing containers of a Coolify resource to the + * `coolify` proxy network so Traefik can reach them. + * + * IMPORTANT: only attach containers that have Traefik labels. The + * coolify network is shared across the whole platform (it hosts + * coolify-db, coolify-redis, etc.) and Docker's embedded DNS resolves + * unqualified hostnames like `postgres` and `redis` to the FIRST + * container with that name on the network. If we attach Twenty's + * `postgres-` container to coolify, Twenty's + * `postgres://postgres:5432/...` connection string starts resolving + * to `coolify-db` instead, which fails auth (different password). + * + * Coolify's own deploy pipeline does the same selective attach — only + * the proxied container goes on the proxy network. Idempotent — + * already-attached containers are no-ops. */ export async function attachToCoolifyProxyNetwork( uuid: string, ): Promise { - // List containers on the resource's project network. Coolify names - // the bridge network after the resource UUID, so all stack members - // are reachable through it. + // List running containers on the resource's project network with + // their `traefik.enable` label. Only those with `traefik.enable=true` + // need to be reachable by the proxy. const ls = await runOnCoolifyHost( - `docker ps --filter network=${uuid} --format '{{.Names}}'`, + `docker ps --filter network=${uuid} --format '{{.Names}}|{{.Label "traefik.enable"}}'`, { timeoutMs: 10_000 }, ); const names = ls.stdout .split('\n') .map(s => s.trim()) - .filter(Boolean); + .filter(Boolean) + .filter(line => line.endsWith('|true')) + .map(line => line.split('|')[0]); if (names.length === 0) return; // Attach each one. `|| true` so already-connected returns 0. const attaches = names.map(n =>