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 =>