Route Coolify through a scanned Comfy proxy instead of pinning hopped listen ports.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Towsty
2026-09-02 08:04:11 -05:00
co-authored by Cursor
parent 2ae5f6fb2e
commit bdec8872b6
5 changed files with 99 additions and 36 deletions
+52 -11
View File
@@ -7,18 +7,58 @@ export function setComfyHostOverride(url: string) {
comfyHostOverride = String(url || '').replace(/\/$/, '')
}
function controlUrl() {
const config = useRuntimeConfig()
return String(config.comfyControlUrl || process.env.COMFY_CONTROL_URL || '').trim()
}
export function agentFrontDoorOrigin() {
const raw = controlUrl()
if (!raw) return ''
const config = useRuntimeConfig()
const proxyPort = String(config.comfyProxyPort || process.env.COMFY_PROXY_PORT || '8198').trim() || '8198'
try {
const control = new URL(raw.includes('://') ? raw : `http://${raw}`)
control.port = proxyPort
control.pathname = ''
control.search = ''
control.hash = ''
return control.origin
} catch {
return ''
}
}
/** Beast HTTP goes through the host-agent proxy so hopped 8188/8189/8190 never reach Coolify. */
export function viaAgentFrontDoor(host: string) {
const door = agentFrontDoorOrigin()
if (!door || !host) return host
try {
const url = new URL(host)
const front = new URL(door)
if (url.hostname !== front.hostname) return host
return front.origin
} catch {
return host
}
}
export function comfyConfigured() {
if (comfyHostOverride) return true
const config = useRuntimeConfig()
return Boolean(String(config.comfyHost || process.env.COMFY_HOST || '').trim())
return Boolean(
String(config.comfyHost || process.env.COMFY_HOST || '').trim()
|| controlUrl()
)
}
function comfyBase() {
if (comfyHostOverride) return comfyHostOverride
function configuredComfyBase() {
const config = useRuntimeConfig()
let host = String(process.env.COMFY_HOST || config.comfyHost || '').trim().replace(/\/$/, '')
const port = String(process.env.COMFY_PORT || config.comfyPort || '').trim()
const door = agentFrontDoorOrigin()
if (!host) {
if (door) return door
throw createError({ statusCode: 500, statusMessage: 'COMFY_HOST is not configured' })
}
if (!/^https?:\/\//i.test(host)) host = `http://${host}`
@@ -32,21 +72,22 @@ function comfyBase() {
}
export function getComfyHost() {
return comfyBase()
if (comfyHostOverride) return viaAgentFrontDoor(comfyHostOverride) || comfyHostOverride
return viaAgentFrontDoor(configuredComfyBase()) || configuredComfyBase()
}
export function comfyWsUrl(clientId: string) {
return `${comfyBase().replace(/^http/, 'ws')}/ws?clientId=${encodeURIComponent(clientId)}`
return `${getComfyHost().replace(/^http/, 'ws')}/ws?clientId=${encodeURIComponent(clientId)}`
}
export async function comfyFetch(path: string, init?: RequestInit) {
const url = `${comfyBase()}${path}`
const url = `${getComfyHost()}${path}`
try {
return await fetch(url, init)
} catch (error) {
throw createError({
statusCode: 502,
statusMessage: `ComfyUI host unreachable (${comfyBase()})`,
statusMessage: `ComfyUI host unreachable (${getComfyHost()})`,
data: { cause: error instanceof Error ? error.message : String(error) }
})
}
@@ -306,12 +347,12 @@ export function inspectHistory(history: Record<string, unknown> | null, promptId
export async function probeComfy() {
try {
const res = await fetch(`${comfyBase()}/system_stats`, { signal: AbortSignal.timeout(2500) })
if (!res.ok) return { ok: false, host: comfyBase() }
const res = await fetch(`${getComfyHost()}/system_stats`, { signal: AbortSignal.timeout(2500) })
if (!res.ok) return { ok: false, host: getComfyHost() }
const stats = await res.json()
return { ok: true, host: comfyBase(), stats }
return { ok: true, host: getComfyHost(), stats }
} catch {
return { ok: false, host: comfyBase() }
return { ok: false, host: getComfyHost() }
}
}
+5 -5
View File
@@ -1,5 +1,5 @@
import { AsyncLocalStorage } from 'node:async_hooks'
import { getComfyHost } from '~/server/utils/comfy'
import { getComfyHost, viaAgentFrontDoor } from '~/server/utils/comfy'
import { comfyJobPrefix } from '~/utils/outputNames'
const imageHostAls = new AsyncLocalStorage<string>()
@@ -31,7 +31,7 @@ function normalizeHost(raw: string, port = '') {
export function getBeastImageHost() {
const config = useRuntimeConfig()
const explicit = String(config.imageComfyPrimaryHost || process.env.IMAGE_COMFY_PRIMARY_HOST || '').trim()
if (explicit) return normalizeHost(explicit)
if (explicit) return viaAgentFrontDoor(normalizeHost(explicit))
try {
return getComfyHost()
} catch {
@@ -53,7 +53,7 @@ export function getSidecarImageHost() {
]
for (const [raw, extraPort] of candidates) {
if (!raw || isRetiredSidecarHost(raw)) continue
const host = normalizeHost(raw, extraPort)
const host = viaAgentFrontDoor(normalizeHost(raw, extraPort))
if (host && !isRetiredSidecarHost(host)) return host
}
return getBeastImageHost()
@@ -61,8 +61,8 @@ export function getSidecarImageHost() {
export function getImageComfyHost() {
const fromAls = imageHostAls.getStore()
if (fromAls) return fromAls
if (imageComfyHostOverride) return imageComfyHostOverride
if (fromAls) return viaAgentFrontDoor(fromAls) || fromAls
if (imageComfyHostOverride) return viaAgentFrontDoor(imageComfyHostOverride) || imageComfyHostOverride
return getBeastImageHost() || getSidecarImageHost()
}