Health Check
Monitor origin server availability with Cloudflare Health Checks for automatic traffic routing and high availability.
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.