Health Check
Stop guessing if your origins are up. Cloudflare Health Checks ping your servers and report back. Pair them with Load Balancers to auto-route traffic away from unhealthy origins.
Quick Start
Section titled “Quick Start”Get a basic health check running:
import { HealthCheck } from "alchemy/cloudflare";
const healthCheck = await HealthCheck("api-health", { zone: "023e105f4ecef8ad9ca31a8372d0c353", address: "api.example.com", name: "api-server-check"});
This creates a health check that:
- Performs HTTP checks every 60 seconds (default)
- Marks the origin unhealthy after 1 consecutive failure (default)
- Marks the origin healthy after 1 consecutive success (default)
Health Check Configuration
Section titled “Health Check Configuration”Dial in your monitoring protocol; timing, response & validation:
import { HealthCheck } from "alchemy/cloudflare";
const healthCheck = await HealthCheck("backend-health", { zone: "023e105f4ecef8ad9ca31a8372d0c353", // Zone ID or Zone resource address: "backend.example.com", // Origin server hostname or IP name: "backend-server-check", // Health check identifier type: "HTTPS", // Protocol: "HTTP", "HTTPS", or "TCP"
// Timing configuration interval: 30, // Check every 30 seconds timeout: 10, // Timeout after 10 seconds retries: 3, // Retry 3 times on timeout
// Threshold configuration consecutiveFails: 2, // Mark unhealthy after 2 failures consecutiveSuccesses: 2, // Mark healthy after 2 successes
// HTTP/HTTPS specific configuration httpConfig: { path: "/health", // Health check endpoint method: "GET", // HTTP method: "GET" or "HEAD" expectedCodes: ["200", "201"], // Expected status codes expectedBody: "OK", // Expected response body substring followRedirects: true, // Follow 3xx redirects allowInsecure: false, // Validate SSL certificates port: 443, // Port (defaults: 80 for HTTP, 443 for HTTPS) header: { // Custom headers "Host": ["backend.example.com"], "X-Health-Check": ["true"] } },
// Monitoring configuration checkRegions: ["WNAM", "ENAM", "WEU"], // Regions to check from suspended: false, // Enable/disable checks description: "Backend server health monitoring"});
HTTP/HTTPS Health Checks
Section titled “HTTP/HTTPS Health Checks”Monitor web servers and APIs with HTTP or HTTPS health checks:
Basic HTTP Check
Section titled “Basic HTTP Check”const webHealthCheck = await HealthCheck("web-health", { zone: "023e105f4ecef8ad9ca31a8372d0c353", address: "web.example.com", name: "web-server-check", type: "HTTP", httpConfig: { path: "/", expectedCodes: ["200"] }});
HTTPS with Custom Path and Headers
Section titled “HTTPS with Custom Path and Headers”const apiHealthCheck = await HealthCheck("api-health", { zone: "023e105f4ecef8ad9ca31a8372d0c353", address: "api.example.com", name: "api-endpoint-check", type: "HTTPS", httpConfig: { path: "/api/health", method: "GET", expectedCodes: ["200", "201"], expectedBody: "healthy", header: { "Host": ["api.example.com"], "User-Agent": ["Cloudflare-Health-Check"], "X-API-Key": [alchemy.secret.env.HEALTH_CHECK_API_KEY] }, port: 443, allowInsecure: false }});
Response Code Ranges
Section titled “Response Code Ranges”Use ranges to match multiple status codes:
const flexibleHealthCheck = await HealthCheck("flexible-health", { zone: "023e105f4ecef8ad9ca31a8372d0c353", address: "app.example.com", name: "app-health-check", httpConfig: { path: "/health", expectedCodes: ["2xx", "3xx"] // Accept any 2xx or 3xx response }});
TCP Health Checks
Section titled “TCP Health Checks”For databases, mail servers, or anything that speaks TCP:
const databaseHealthCheck = await HealthCheck("db-health", { zone: "023e105f4ecef8ad9ca31a8372d0c353", address: "db.example.com", name: "database-connection-check", type: "TCP", tcpConfig: { port: 5432, // PostgreSQL port method: "connection_established" }, interval: 60, timeout: 5, retries: 2});
Common TCP ports:
- PostgreSQL:
5432
- MySQL:
3306
- Redis:
6379
- MongoDB:
27017
- SMTP:
25
,587
,465
- SSH:
22
Regional Distribution
Section titled “Regional Distribution”Configure which regions run health checks for geographic distribution:
const globalHealthCheck = await HealthCheck("global-health", { zone: "023e105f4ecef8ad9ca31a8372d0c353", address: "global.example.com", name: "global-origin-check", checkRegions: [ "WNAM", // Western North America "ENAM", // Eastern North America "WEU", // Western Europe "EEU", // Eastern Europe "SEAS", // South East Asia "OC" // Oceania ]});
Available regions:
WNAM
- Western North AmericaENAM
- Eastern North AmericaWEU
- Western EuropeEEU
- Eastern EuropeNSAM
- Northern South AmericaSSAM
- Southern South AmericaOC
- OceaniaME
- Middle EastNAF
- Northern AfricaSAF
- Southern AfricaIN
- IndiaSEAS
- South East AsiaNEAS
- North East AsiaALL_REGIONS
- All available regions
Timing & Thresholds
Section titled “Timing & Thresholds”Fine-tune health check timing and failure thresholds:
const sensitiveHealthCheck = await HealthCheck("sensitive-health", { zone: "023e105f4ecef8ad9ca31a8372d0c353", address: "critical.example.com", name: "critical-service-check",
// Check frequently for fast detection interval: 15, // Check every 15 seconds timeout: 3, // 3 second timeout retries: 5, // Retry 5 times on timeout
// Conservative thresholds to avoid false positives consecutiveFails: 3, // 3 failures before marking unhealthy consecutiveSuccesses: 3, // 3 successes before marking healthy
httpConfig: { path: "/health", expectedCodes: ["200"] }});
Timing guidelines:
- High availability services: Use shorter intervals (15-30s) with higher thresholds (2-3)
- Normal services: Use default intervals (60s) with default thresholds (1-2)
- Low priority services: Use longer intervals (120s+) with lower thresholds (1)
Calculation example:
With interval: 30
, consecutiveFails: 3
:
- Time to detect failure: 90 seconds (3 × 30s)
- Time to recover: 90 seconds (3 × 30s)
Secure Headers with Secrets
Section titled “Secure Headers with Secrets”Use secrets for sensitive header values:
const secureHealthCheck = await HealthCheck("secure-health", { zone: "023e105f4ecef8ad9ca31a8372d0c353", address: "api.example.com", name: "secure-api-check", httpConfig: { path: "/internal/health", header: { "Host": ["api.example.com"], "Authorization": [alchemy.secret.env.HEALTH_CHECK_TOKEN], "X-API-Key": [alchemy.secret.env.API_KEY] } }});
Adopting Existing Checks
Section titled “Adopting Existing Checks”Already have health checks? Adopt them by name instead of failing:
const existingHealthCheck = await HealthCheck("existing-health", { zone: "023e105f4ecef8ad9ca31a8372d0c353", address: "existing.example.com", name: "existing-health-check", adopt: true // Adopt if health check with this name exists});
Suspending Health Checks
Section titled “Suspending Health Checks”Pause checks during maintenance without deleting:
const suspendedHealthCheck = await HealthCheck("maintenance-health", { zone: "023e105f4ecef8ad9ca31a8372d0c353", address: "maintenance.example.com", name: "maintenance-server-check", suspended: true // Don't send health checks});
When to suspend:
- During planned maintenance
- When origin is intentionally offline
- When debugging health check configuration
- When origin can’t handle health check load
Load Balancer Integration
Section titled “Load Balancer Integration”Real power: automatic failover when origins go down.
import { HealthCheck, LoadBalancer, Pool } from "alchemy/cloudflare";
// Create health checks for each originconst primaryHealthCheck = await HealthCheck("primary-health", { zone: "023e105f4ecef8ad9ca31a8372d0c353", address: "primary.example.com", name: "primary-origin-check", httpConfig: { path: "/health", expectedCodes: ["200"] }});
const secondaryHealthCheck = await HealthCheck("secondary-health", { zone: "023e105f4ecef8ad9ca31a8372d0c353", address: "secondary.example.com", name: "secondary-origin-check", httpConfig: { path: "/health", expectedCodes: ["200"] }});
// Create a pool with origins and health checksconst pool = await Pool("main-pool", { name: "main-origin-pool", origins: [ { name: "primary", address: "primary.example.com", enabled: true }, { name: "secondary", address: "secondary.example.com", enabled: true } ], monitor: primaryHealthCheck // Attach health check to pool});
// Create load balancerconst loadBalancer = await LoadBalancer("main-lb", { zone: "023e105f4ecef8ad9ca31a8372d0c353", name: "app.example.com", defaultPools: [pool]});
Status Monitoring
Section titled “Status Monitoring”Access health check status programmatically:
const healthCheck = await HealthCheck("monitored-health", { zone: "023e105f4ecef8ad9ca31a8372d0c353", address: "app.example.com", name: "app-health-check"});
// Health check status is available after creationconsole.log(healthCheck.status); // "unknown" | "healthy" | "unhealthy" | "suspended"console.log(healthCheck.failureReason); // Reason if unhealthyconsole.log(healthCheck.createdOn); // Creation timestampconsole.log(healthCheck.modifiedOn); // Last modification timestamp
Status values:
unknown
- Health check hasn’t run yethealthy
- Origin is responding correctlyunhealthy
- Origin is not responding or failing checkssuspended
- Health checks are suspended
Advanced Patterns
Section titled “Advanced Patterns”Multi-Region Monitoring
Section titled “Multi-Region Monitoring”Check all your geographic origins:
const regions = [ { region: "us-west", address: "us-west.example.com" }, { region: "us-east", address: "us-east.example.com" }, { region: "eu-west", address: "eu-west.example.com" }, { region: "ap-southeast", address: "ap-southeast.example.com" }];
const healthChecks = await Promise.all( regions.map(({ region, address }) => HealthCheck(`${region}-health`, { zone: "023e105f4ecef8ad9ca31a8372d0c353", address, name: `${region}-origin-check`, httpConfig: { path: "/health", expectedCodes: ["200"], header: { "X-Region": [region] } } }) ));
Deep Health Validation
Section titled “Deep Health Validation”Check more than “is it up”, validate the whole stack:
const comprehensiveHealthCheck = await HealthCheck("comprehensive-health", { zone: "023e105f4ecef8ad9ca31a8372d0c353", address: "api.example.com", name: "comprehensive-check", httpConfig: { path: "/health/comprehensive", method: "GET", expectedCodes: ["200"], expectedBody: "all_systems_operational", // Custom validation header: { "X-Health-Check-Version": ["v2"] } }, interval: 30, timeout: 10, consecutiveFails: 2, consecutiveSuccesses: 2});
Your health endpoint should validate:
- Database connectivity
- External service availability
- Disk space
- Memory usage
- Critical background jobs
Gradual Traffic Restoration
Section titled “Gradual Traffic Restoration”Fast to kill, slow to restore - avoid thundering herd:
const cautiousHealthCheck = await HealthCheck("cautious-health", { zone: "023e105f4ecef8ad9ca31a8372d0c353", address: "recovering.example.com", name: "recovering-origin-check",
// Quick to mark unhealthy consecutiveFails: 1,
// Slow to mark healthy (wait for stability) consecutiveSuccesses: 5,
interval: 15, httpConfig: { path: "/health", expectedCodes: ["200"] }});
This pattern:
- ✅ Quickly removes unhealthy origins from rotation (1 failure)
- ✅ Waits for sustained health before restoration (5 successes)
- ✅ Reduces risk of cascading failures
- ✅ Protects recovering origins from traffic spikes
Troubleshooting
Section titled “Troubleshooting”Always Unhealthy
Section titled “Always Unhealthy”Origin is up, but health check says it’s down:
Common causes:
- Incorrect path or port:
// ❌ Wrong pathhttpConfig: { path: "/healthcheck" // Origin expects "/health"}
// ✅ Correct pathhttpConfig: { path: "/health"}
- Missing or incorrect headers:
// ❌ Missing Host headerhttpConfig: { path: "/health"}
// ✅ Include Host headerhttpConfig: { path: "/health", header: { "Host": ["api.example.com"] }}
- Firewall blocking health checks:
- Ensure your firewall allows Cloudflare IP ranges
- Check your origin’s access logs for health check requests
- Verify security groups allow traffic from Cloudflare
- SSL certificate validation:
// ❌ Self-signed certificate with validation enabledtype: "HTTPS",httpConfig: { allowInsecure: false}
// ✅ Allow self-signed for developmenttype: "HTTPS",httpConfig: { allowInsecure: true // Only for development!}
Health Check Flapping
Section titled “Health Check Flapping”Health bouncing between healthy/unhealthy?
Fix: Require sustained changes:
// ❌ Too sensitiveconsecutiveFails: 1,consecutiveSuccesses: 1,
// ✅ More stableconsecutiveFails: 3,consecutiveSuccesses: 3,
Timeout Errors
Section titled “Timeout Errors”Health checks timing out but origin is responding?
Try these:
- Increase timeout:
timeout: 10, // Increase from default 5 seconds
- Optimize health endpoint:
- Return cached responses
- Avoid expensive database queries
- Use in-memory checks
- Return early on first successful check
- Increase retries:
retries: 5, // Retry more times before marking unhealthy
Expected Body Mismatch
Section titled “Expected Body Mismatch”Getting “expected body not found”?
Debug it:
// Temporarily remove expectedBody to see what's being returnedhttpConfig: { path: "/health", expectedCodes: ["200"], // expectedBody: "OK" // Comment out to debug}
Check your origin’s health endpoint response format:
- Ensure it returns plain text if using simple string matching
- Check for leading/trailing whitespace
- Verify the response isn’t JSON-encoded
- Use a substring that definitely appears in the response
Next Steps
Section titled “Next Steps”- Load Balancers: See Load Balancer
- Monitoring: See Cloudflare Analytics
- Zones: See Zone
- Join our Discord for support and updates.