{"id":17744069,"url":"https://github.com/thomasvincent/terraform-cloudflare-maintenance","last_synced_at":"2026-01-20T20:33:27.974Z","repository":{"id":288129350,"uuid":"938422950","full_name":"thomasvincent/terraform-cloudflare-maintenance","owner":"thomasvincent","description":"🚧 Enterprise-grade maintenance mode solution for Cloudflare with Terraform. Features IP allowlisting, scheduled windows, analytics \u0026 multi-language support","archived":false,"fork":false,"pushed_at":"2026-01-02T09:13:02.000Z","size":683,"stargazers_count":1,"open_issues_count":27,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-01-08T07:26:33.691Z","etag":null,"topics":["automation","cdn","cloudflare","cloudflare-workers","devops","disaster-recovery","edge-computing","high-availability","incident-response","infrastructure-as-code","maintenance-mode","maintenance-page","site-reliability","terraform","terraform-cloudflare","terraform-module","zero-downtime"],"latest_commit_sha":null,"homepage":"https://github.com/thomasvincent/terraform-cloudflare-maintenance","language":"HCL","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/thomasvincent.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-02-24T23:45:42.000Z","updated_at":"2026-01-02T09:13:05.000Z","dependencies_parsed_at":"2025-10-04T11:24:59.148Z","dependency_job_id":null,"html_url":"https://github.com/thomasvincent/terraform-cloudflare-maintenance","commit_stats":null,"previous_names":["thomasvincent/terraform-cloudflare-maintenance"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/thomasvincent/terraform-cloudflare-maintenance","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thomasvincent%2Fterraform-cloudflare-maintenance","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thomasvincent%2Fterraform-cloudflare-maintenance/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thomasvincent%2Fterraform-cloudflare-maintenance/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thomasvincent%2Fterraform-cloudflare-maintenance/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/thomasvincent","download_url":"https://codeload.github.com/thomasvincent/terraform-cloudflare-maintenance/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thomasvincent%2Fterraform-cloudflare-maintenance/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28612964,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-20T18:56:40.769Z","status":"ssl_error","status_checked_at":"2026-01-20T18:54:26.653Z","response_time":117,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["automation","cdn","cloudflare","cloudflare-workers","devops","disaster-recovery","edge-computing","high-availability","incident-response","infrastructure-as-code","maintenance-mode","maintenance-page","site-reliability","terraform","terraform-cloudflare","terraform-module","zero-downtime"],"created_at":"2024-10-26T06:41:51.447Z","updated_at":"2026-01-20T20:33:27.964Z","avatar_url":"https://github.com/thomasvincent.png","language":"HCL","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Terraform Cloudflare Maintenance\n\n[![License](https://img.shields.io/github/license/thomasvincent/terraform-cloudflare-maintenance.svg)](LICENSE)\n[![standard-readme compliant](https://img.shields.io/badge/readme%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme)\n[![OpenTofu Version](https://img.shields.io/badge/OpenTofu-%3E%3D1.6.0-blue)](versions.tf)\n[![Cloudflare Provider](https://img.shields.io/badge/provider-cloudflare%20v5.2-1e90ff)](versions.tf)\n[![Test Coverage](https://img.shields.io/badge/coverage-100%25-brightgreen)](tests/)\n\nEnterprise-grade maintenance mode solution for Cloudflare infrastructure with OpenTofu.\n\n\u003e **Note**: This module has been migrated from Terraform to [OpenTofu](https://opentofu.org/), the open-source fork of Terraform. OpenTofu is a drop-in replacement and is fully compatible with existing Terraform configurations.\n\n## Table of Contents\n\n- [Overview](#overview)\n- [Features](#features)\n- [Security](#security)\n- [Requirements](#requirements)\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Basic Usage](#basic-usage)\n  - [Advanced Configuration](#advanced-configuration)\n- [Architecture](#architecture)\n- [Input Variables](#input-variables)\n- [Outputs](#outputs)\n- [Testing](#testing)\n- [Contributing](#contributing)\n- [License](#license)\n\n## Overview\n\nThis Terraform module provides a robust, enterprise-ready maintenance mode solution for Cloudflare-hosted applications. It deploys a customizable maintenance page using Cloudflare Workers, with features like IP allowlisting, scheduled maintenance windows, and detailed analytics.\n\n## Features\n\n- 🛡️ **Customizable Maintenance Page**: Fully customizable HTML/CSS with support for logos and branding\n- 🔒 **IP Allowlisting**: Allow specific IPs to bypass maintenance mode (e.g., for testing or monitoring)\n- ⏱️ **Scheduled Maintenance Windows**: Set specific time windows for maintenance mode to be active with RFC3339 timestamps\n- 📅 **Cron-based Scheduling**: Configure recurring maintenance windows with cron expressions\n- 📊 **Analytics Integration**: Built-in logging and monitoring with Cloudflare Analytics Engine\n- 🌍 **Geo-based Routing**: Optional geo-based traffic routing for region-specific maintenance\n- 🔄 **Zero-Downtime Toggle**: Enable/disable maintenance mode without redeployment\n- 🔍 **SEO Friendly**: Proper HTTP status codes and headers for search engines\n- 🔔 **Notification Support**: Slack, PagerDuty, and webhook integrations for maintenance alerts\n- 🏷️ **Environment-Aware**: Support for multiple environments (production, staging, development)\n\n## Security\n\n### Compliance Features\n\n- **GDPR Compliance**: All access logs are anonymized through Cloudflare's privacy features\n- **SOC2 Compatibility**: Changes enforced through Terraform Cloud audit trails\n- **Secret Management**: API tokens stored as sensitive variables\n\n### Access Controls\n\n```hcl\nprovider \"cloudflare\" {\n  api_token = var.cloudflare_api_token # Stored as sensitive variable\n  account_id = var.cloudflare_account_id\n}\n```\n\n## Requirements\n\n- OpenTofu \u003e= 1.6.0 (or Terraform \u003e= 1.5.0)\n- Cloudflare Provider \u003e= 5.2\n- Cloudflare Account with Workers enabled\n- Cloudflare API Token with appropriate permissions:\n  - Account.Workers Scripts:Edit\n  - Zone.Workers Routes:Edit\n  - Zone.DNS:Edit (if using custom DNS records)\n  - Zone.Firewall Services:Edit (if using IP allowlisting)\n\n## Installation\n\n### Standard Installation\n\n1. Add the module to your Terraform configuration:\n\n```hcl\nmodule \"maintenance\" {\n  source  = \"github.com/thomasvincent/terraform-cloudflare-maintenance\"\n  version = \"2.0.0\"\n  \n  cloudflare_api_token = var.cloudflare_api_token\n  cloudflare_account_id = var.cloudflare_account_id\n  cloudflare_zone_id = var.cloudflare_zone_id\n}\n```\n\n2. Initialize your OpenTofu workspace:\n\n```bash\ntofu init\n```\n\n\n## Usage\n\n### Basic Usage\n\n```hcl\nmodule \"maintenance\" {\n  source = \"github.com/thomasvincent/terraform-cloudflare-maintenance\"\n  \n  cloudflare_api_token = var.cloudflare_api_token\n  cloudflare_account_id = var.cloudflare_account_id\n  cloudflare_zone_id = var.cloudflare_zone_id\n  \n  enabled = true\n  maintenance_title = \"System Upgrade in Progress\"\n  contact_email = \"support@example.com\"\n  worker_route = \"*.example.com/*\"\n  \n  allowed_ips = [\n    \"192.168.1.1\",\n    \"10.0.0.1\"\n  ]\n}\n```\n\n### Advanced Configuration\n\nFor more advanced usage with scheduled maintenance windows, custom styling, and monitoring integration, see the [advanced example](examples/advanced-config/).\n\n```hcl\nmodule \"maintenance\" {\n  source = \"github.com/thomasvincent/terraform-cloudflare-maintenance\"\n  \n  cloudflare_api_token = var.cloudflare_api_token\n  cloudflare_account_id = var.cloudflare_account_id\n  cloudflare_zone_id = var.cloudflare_zone_id\n  \n  # Environment configuration\n  environment = \"production\"\n  \n  # Enable maintenance mode only for specific paths\n  worker_route = \"example.com/api/*\"\n  \n  # Toggle maintenance mode based on environment\n  enabled = var.environment == \"production\" ? false : true\n  \n  # Custom maintenance page content\n  maintenance_title = \"Scheduled System Maintenance\"\n  contact_email = \"support@example.com\"\n  \n  # Allow internal IPs to bypass maintenance\n  allowed_ips = var.office_ip_ranges\n  \n  # Allow specific regions to bypass maintenance\n  allowed_regions = [\"US\", \"CA\"]\n  \n  # Schedule maintenance window\n  maintenance_window = {\n    start_time = \"2025-04-06T08:00:00Z\"\n    end_time = \"2025-04-06T10:00:00Z\"\n  }\n  \n  # Custom styling\n  custom_css = file(\"${path.module}/custom-styles.css\")\n  logo_url = \"https://example.com/logo.png\"\n  \n  # Cron-based scheduling (for documentation/future automation)\n  schedules = [\n    {\n      name     = \"weekly-maintenance\"\n      cron     = \"0 2 * * SUN\"  # Every Sunday at 2 AM\n      duration = \"2h\"\n      timezone = \"America/Los_Angeles\"\n      notify   = [\"slack://webhook\", \"pagerduty://service\"]\n    }\n  ]\n}\n```\n\n### Scheduled Maintenance with Notifications\n\nSee the [scheduled maintenance example](examples/scheduled-maintenance/) for a complete example with notification support.\n\n```hcl\nmodule \"maintenance\" {\n  source = \"github.com/thomasvincent/terraform-cloudflare-maintenance\"\n  \n  cloudflare_api_token  = var.cloudflare_api_token\n  cloudflare_account_id = var.cloudflare_account_id\n  cloudflare_zone_id    = var.cloudflare_zone_id\n  \n  environment = \"production\"\n  enabled     = true\n  \n  # Time-based maintenance window\n  maintenance_window = {\n    start_time = \"2025-04-06T08:00:00Z\"\n    end_time   = \"2025-04-06T10:00:00Z\"\n  }\n  \n  # Custom branding\n  custom_css = \"body { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); }\"\n  logo_url   = \"https://example.com/logo.png\"\n  \n  # Cron schedules for recurring maintenance\n  schedules = [\n    {\n      name     = \"weekly-maintenance\"\n      cron     = \"0 2 * * SUN\"\n      duration = \"2h\"\n      timezone = \"America/Los_Angeles\"\n      notify   = [\"slack://T00000000/B00000000/XXXXXXXXXXXXXXXXXXXX\"]\n    }\n  ]\n}\n\n# Optional: Configure notifications\nmodule \"maintenance_notifications\" {\n  source = \"github.com/thomasvincent/terraform-cloudflare-maintenance//modules/notifications\"\n  \n  notification_urls = [\n    \"slack://T00000000/B00000000/XXXXXXXXXXXXXXXXXXXX\",\n    \"pagerduty://your-routing-key\"\n  ]\n  \n  maintenance_status = module.maintenance.maintenance_status\n  schedule_name      = \"scheduled-maintenance\"\n  environment        = \"production\"\n  \n  maintenance_window = {\n    start_time = \"2025-04-06T08:00:00Z\"\n    end_time   = \"2025-04-06T10:00:00Z\"\n  }\n}\n```\n\n## Architecture\n\nThe module deploys the following components:\n\n![Architecture Diagram](architecture.png)\n\n```mermaid\ngraph TD\n    A[Client Request] --\u003e B{Maintenance Active?}\n    B --\u003e|Yes| C[Maintenance Worker]\n    B --\u003e|No| D[Origin Server]\n    C --\u003e E[Custom HTML Page]\n    \n    F[Allowed IPs] --\u003e G{IP Check}\n    G --\u003e|Match| D\n    G --\u003e|No Match| C\n    \n    H[Maintenance Window] --\u003e I{Time Check}\n    I --\u003e|Within Window| C\n    I --\u003e|Outside Window| D\n```\n\n## Input Variables\n\n| Name | Description | Type | Default | Required |\n|------|-------------|------|---------|:--------:|\n| cloudflare_api_token | Cloudflare API token with least privileges | `string` | n/a | yes |\n| cloudflare_account_id | Cloudflare account ID | `string` | n/a | yes |\n| cloudflare_zone_id | Cloudflare zone ID for the domain | `string` | n/a | yes |\n| worker_route | URL pattern to trigger the maintenance worker | `string` | `\"*.example.com/*\"` | no |\n| enabled | Toggle maintenance mode on/off | `bool` | `false` | no |\n| environment | Environment name (e.g., production, staging) | `string` | `\"production\"` | no |\n| maintenance_title | Title for the maintenance page | `string` | `\"System Maintenance in Progress\"` | no |\n| maintenance_message | Message to display on the maintenance page | `string` | `\"We are currently performing...\"` | no |\n| contact_email | Contact email to display on the maintenance page | `string` | `\"\"` | no |\n| allowed_ips | List of IP addresses that can bypass the maintenance page | `list(string)` | `[]` | no |\n| allowed_regions | List of ISO 3166-1 alpha-2 country codes that can bypass maintenance | `list(string)` | `[]` | no |\n| maintenance_window | Scheduled maintenance window in RFC3339 format | `object({start_time=string, end_time=string})` | `null` | no |\n| schedules | List of cron-based scheduled maintenance windows | `list(object)` | `[]` | no |\n| custom_css | Custom CSS for the maintenance page | `string` | `\"\"` | no |\n| logo_url | URL to the logo to display on the maintenance page | `string` | `\"\"` | no |\n\nFor a complete list of variables, see [variables.tf](variables.tf).\n\n## Outputs\n\n| Name | Description |\n|------|-------------|\n| worker_id | The ID of the deployed worker script |\n| worker_name | The name of the deployed worker script |\n| worker_script_name | The name of the deployed worker script (alias) |\n| worker_route_pattern | Cloudflare route pattern for the maintenance page |\n| maintenance_status | Current status of the maintenance mode (ENABLED/DISABLED) |\n| maintenance_enabled | Whether maintenance mode is currently enabled |\n| maintenance_page_url | URL to access the maintenance page directly |\n| environment | Environment name |\n| maintenance_window | Scheduled maintenance window if configured |\n| dns_record_id | ID of the DNS record for the maintenance status page |\n| ruleset_id | ID of the firewall ruleset for IP/region allowlisting |\n| allowed_regions | List of allowed regions that can bypass maintenance |\n\nFor a complete list of outputs, see [outputs.tf](outputs.tf).\n\n## Cron Expression Reference\n\nThe `schedules` variable supports standard cron expressions:\n\n```\n ┌───────────── minute (0 - 59)\n │ ┌───────────── hour (0 - 23)\n │ │ ┌───────────── day of month (1 - 31)\n │ │ │ ┌───────────── month (1 - 12)\n │ │ │ │ ┌───────────── day of week (0 - 6) (Sunday to Saturday)\n │ │ │ │ │\n * * * * *\n```\n\nCommon examples:\n- `0 2 * * SUN` - Every Sunday at 2 AM\n- `0 3 1 * *` - First day of every month at 3 AM\n- `0 0 * * 0,6` - Every Saturday and Sunday at midnight\n- `30 4 * * 1-5` - Weekdays at 4:30 AM\n\n## Notification Integrations\n\nThe module supports multiple notification channels through the `modules/notifications` submodule:\n\n### Slack\nSend notifications to Slack channels via incoming webhooks:\n```hcl\nnotification_urls = [\"slack://T00000000/B00000000/XXXXXXXXXXXXXXXXXXXX\"]\n```\n\n### PagerDuty\nCreate incidents or events in PagerDuty:\n```hcl\nnotification_urls = [\"pagerduty://your-routing-key\"]\n```\n\n### Generic Webhooks\nSend JSON payloads to any webhook endpoint:\n```hcl\nnotification_urls = [\"webhook://https://example.com/webhook\"]\n```\n\nSee the [notifications module documentation](modules/notifications/README.md) for more details.\n\n## Testing\n\nThis module includes comprehensive tests to ensure functionality and prevent regressions:\n\n- **Unit Tests**: Test individual components of the worker script\n- **Integration Tests**: Verify the entire module works as expected\n\nTo run the tests:\n\n```bash\n# Run unit tests for the worker\ncd worker \u0026\u0026 npm test\n\n# Run integration tests for the Terraform module\ncd tests/integration \u0026\u0026 go test -v\n```\n\n## Contributing\n\nContributions are welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feat/amazing-feature`)\n3. Commit changes using Conventional Commits with emojis\n4. Push to the branch (`git push origin feat/amazing-feature`)\n5. Open a Pull Request\n\n## License\n\n[MIT © Thomas Vincent](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthomasvincent%2Fterraform-cloudflare-maintenance","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthomasvincent%2Fterraform-cloudflare-maintenance","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthomasvincent%2Fterraform-cloudflare-maintenance/lists"}