```js
// Cloudflare Worker Load Balancer with Health Check
// Configure your tunnel URLs here
const SERVERS = [
{
url: 'https://your-tunnel-1.yourdomain.com',
name: 'Server 1',
healthCheckPath: '/health' // or '/' if you don't have a specific endpoint
},
{
url: 'https://your-tunnel-2.yourdomain.com',
name: 'Server 2',
healthCheckPath: '/health'
}
]
// Settings
const HEALTH_CHECK_TIMEOUT = 5000 // 5 seconds
const HEALTH_CHECK_INTERVAL = 30000 // Check every 30 seconds
// Server status cache (kept by the Worker)
let serverHealth = {}
// Health check
async function checkHealth(server) {
try {
const controller = new AbortController()
const timeoutId = setTimeout(() => controller.abort(), HEALTH_CHECK_TIMEOUT)
const response = await fetch(server.url + server.healthCheckPath, {
method: 'GET',
signal: controller.signal,
headers: {
'User-Agent': 'Cloudflare-Worker-HealthCheck'
}
})
clearTimeout(timeoutId)
// Healthy if 2xx or 3xx
return response.status >= 200 && response.status < 400
} catch (error) {
console.log(`Health check failed for ${server.name}:`, error.message)
return false
}
}
// Pick an available server
async function getAvailableServer() {
// Refresh health check if needed
for (const server of SERVERS) {
const lastCheck = serverHealth[server.url]?.lastCheck || 0
const now = Date.now()
if (now - lastCheck > HEALTH_CHECK_INTERVAL) {
const isHealthy = await checkHealth(server)
serverHealth[server.url] = {
healthy: isHealthy,
lastCheck: now
}
}
}
// Pick the first healthy server
for (const server of SERVERS) {
if (serverHealth[server.url]?.healthy) {
return server
}
}
// If none are healthy, use the first as fallback
console.log('No healthy server found, using fallback')
return SERVERS[0]
}
// Main handler
export default {
async fetch(request, env, ctx) {
// Pick server
const server = await getAvailableServer()
// Build target URL keeping original path
const url = new URL(request.url)
const targetUrl = new URL(url.pathname + url.search, server.url)
// Clone request for the chosen server
const modifiedRequest = new Request(targetUrl, {
method: request.method,
headers: request.headers,
body: request.body,
redirect: 'follow'
})
// Debug header (optional)
modifiedRequest.headers.set('X-Served-By', server.name)
try {
// Proxy request
const response = await fetch(modifiedRequest)
// Clone response to add headers
const newResponse = new Response(response.body, response)
newResponse.headers.set('X-Served-By', server.name)
return newResponse
} catch (error) {
// If it fails, try the other server
console.log(`Error while accessing ${server.name}, trying fallback`)
const fallbackServer = SERVERS.find((s) => s.url !== server.url)
if (fallbackServer) {
const fallbackUrl = new URL(url.pathname + url.search, fallbackServer.url)
const fallbackRequest = new Request(fallbackUrl, {
method: request.method,
headers: request.headers,
body: request.body,
redirect: 'follow'
})
return fetch(fallbackRequest)
}
return new Response('All servers are unavailable', { status: 503 })
}
}
}