Marketplace

cloudflare-coder

This skill guides provisioning Cloudflare infrastructure with OpenTofu/Terraform. Use when managing zones, DNS records, WAF rules, SSL settings, Page Rules, or cache configuration.

allowed_tools: Read, Write, Edit, Grep, Glob, Bash

$ Installer

git clone https://github.com/majesticlabs-dev/majestic-marketplace /tmp/majestic-marketplace && cp -r /tmp/majestic-marketplace/plugins/majestic-devops/skills/cloudflare-coder ~/.claude/skills/majestic-marketplace

// tip: Run this command in your terminal to install the skill


name: cloudflare-coder description: This skill guides provisioning Cloudflare infrastructure with OpenTofu/Terraform. Use when managing zones, DNS records, WAF rules, SSL settings, Page Rules, or cache configuration. allowed-tools: Read, Write, Edit, Grep, Glob, Bash

Cloudflare Coder

Overview

Cloudflare provides CDN, DNS, security, and edge computing services. This skill covers OpenTofu/Terraform patterns for Cloudflare resources.

Provider Setup

terraform {
  required_providers {
    cloudflare = {
      source  = "cloudflare/cloudflare"
      version = "~> 4.0"
    }
  }
}

provider "cloudflare" {
  # API Token from environment: CLOUDFLARE_API_TOKEN
  # Or explicitly (not recommended):
  # api_token = var.cloudflare_api_token
}

Authentication

# Preferred: API Token (scoped permissions)
export CLOUDFLARE_API_TOKEN="your-api-token"

# Or with 1Password
CLOUDFLARE_API_TOKEN=op://Infrastructure/Cloudflare/api_token

# Legacy: Global API Key (full access - avoid if possible)
export CLOUDFLARE_API_KEY="your-global-api-key"
export CLOUDFLARE_EMAIL="your-email@example.com"

API Token Permissions (minimum required):

ResourcePermissionUse Case
ZoneReadList zones, read settings
ZoneEditModify zone settings
DNSEditManage DNS records
FirewallEditWAF, firewall rules
SSLEditCertificate management
CachePurgeCache invalidation

Data Sources

Get Zone by Name

data "cloudflare_zone" "main" {
  name = "example.com"
}

# Use in resources
resource "cloudflare_record" "www" {
  zone_id = data.cloudflare_zone.main.id
  # ...
}

Get Account ID

data "cloudflare_accounts" "main" {
  name = "My Account"
}

output "account_id" {
  value = data.cloudflare_accounts.main.accounts[0].id
}

DNS Records

Basic Records

# A Record
resource "cloudflare_record" "root" {
  zone_id = data.cloudflare_zone.main.id
  name    = "@"
  type    = "A"
  content = var.server_ip
  ttl     = 1  # 1 = automatic
  proxied = true
}

# CNAME Record
resource "cloudflare_record" "www" {
  zone_id = data.cloudflare_zone.main.id
  name    = "www"
  type    = "CNAME"
  content = "@"
  ttl     = 1
  proxied = true
}

# MX Records
resource "cloudflare_record" "mx_primary" {
  zone_id  = data.cloudflare_zone.main.id
  name     = "@"
  type     = "MX"
  content  = "mail.example.com"
  ttl      = 3600
  priority = 10
  proxied  = false  # MX cannot be proxied
}

# TXT Record (SPF)
resource "cloudflare_record" "spf" {
  zone_id = data.cloudflare_zone.main.id
  name    = "@"
  type    = "TXT"
  content = "v=spf1 include:_spf.google.com ~all"
  ttl     = 3600
}

DNS Records with for_each

locals {
  dns_records = {
    api = {
      type    = "A"
      content = var.api_server_ip
      proxied = true
    }
    staging = {
      type    = "A"
      content = var.staging_server_ip
      proxied = true
    }
    mail = {
      type    = "A"
      content = var.mail_server_ip
      proxied = false
    }
  }
}

resource "cloudflare_record" "subdomain" {
  for_each = local.dns_records

  zone_id = data.cloudflare_zone.main.id
  name    = each.key
  type    = each.value.type
  content = each.value.content
  ttl     = 1
  proxied = each.value.proxied
}

SSL/TLS Settings

Zone SSL Settings

resource "cloudflare_zone_settings_override" "ssl" {
  zone_id = data.cloudflare_zone.main.id

  settings {
    # SSL mode: off, flexible, full, strict (recommended)
    ssl = "strict"

    # Minimum TLS version
    min_tls_version = "1.2"

    # Always use HTTPS
    always_use_https = "on"

    # Automatic HTTPS Rewrites
    automatic_https_rewrites = "on"

    # HTTP Strict Transport Security
    security_header {
      enabled            = true
      max_age            = 31536000  # 1 year
      include_subdomains = true
      preload            = true
      nosniff            = true
    }

    # TLS 1.3
    tls_1_3 = "on"

    # Opportunistic Encryption
    opportunistic_encryption = "on"
  }
}

Origin Certificates

resource "cloudflare_origin_ca_certificate" "origin" {
  csr                = tls_cert_request.origin.cert_request_pem
  hostnames          = ["example.com", "*.example.com"]
  request_type       = "origin-rsa"
  requested_validity = 5475  # 15 years (max)
}

# Generate private key and CSR
resource "tls_private_key" "origin" {
  algorithm = "RSA"
  rsa_bits  = 2048
}

resource "tls_cert_request" "origin" {
  private_key_pem = tls_private_key.origin.private_key_pem

  subject {
    common_name  = "example.com"
    organization = "Example Inc"
  }
}

output "origin_certificate" {
  value     = cloudflare_origin_ca_certificate.origin.certificate
  sensitive = true
}

Firewall & WAF

See resources/waf.md for IP access rules, WAF custom rules with rate limiting, and managed rulesets (Cloudflare + OWASP).

Cache Rules

Modern Cache Rules (Rulesets)

resource "cloudflare_ruleset" "cache" {
  zone_id     = data.cloudflare_zone.main.id
  name        = "Cache Rules"
  description = "Caching configuration"
  kind        = "zone"
  phase       = "http_request_cache_settings"

  # Cache static assets aggressively
  rules {
    action = "set_cache_settings"
    action_parameters {
      cache = true
      edge_ttl {
        mode    = "override_origin"
        default = 2592000  # 30 days
      }
      browser_ttl {
        mode    = "override_origin"
        default = 86400  # 1 day
      }
    }
    expression  = "(http.request.uri.path.extension in {\"css\" \"js\" \"jpg\" \"jpeg\" \"png\" \"gif\" \"svg\" \"woff\" \"woff2\"})"
    description = "Cache static assets"
    enabled     = true
  }

  # Bypass cache for API
  rules {
    action = "set_cache_settings"
    action_parameters {
      cache = false
    }
    expression  = "(starts_with(http.request.uri.path, \"/api/\"))"
    description = "Bypass cache for API"
    enabled     = true
  }

  # Bypass cache for admin
  rules {
    action = "set_cache_settings"
    action_parameters {
      cache = false
    }
    expression  = "(starts_with(http.request.uri.path, \"/admin\"))"
    description = "Bypass cache for admin"
    enabled     = true
  }
}

Legacy Page Rules

# Cache everything for static paths
resource "cloudflare_page_rule" "cache_static" {
  zone_id  = data.cloudflare_zone.main.id
  target   = "example.com/assets/*"
  priority = 1

  actions {
    cache_level = "cache_everything"
    edge_cache_ttl = 2592000  # 30 days
  }
}

# Bypass cache for API
resource "cloudflare_page_rule" "bypass_api" {
  zone_id  = data.cloudflare_zone.main.id
  target   = "example.com/api/*"
  priority = 2

  actions {
    cache_level = "bypass"
  }
}

# Force HTTPS
resource "cloudflare_page_rule" "force_https" {
  zone_id  = data.cloudflare_zone.main.id
  target   = "http://example.com/*"
  priority = 3

  actions {
    always_use_https = true
  }
}

Redirect Rules

resource "cloudflare_ruleset" "redirects" {
  zone_id     = data.cloudflare_zone.main.id
  name        = "Redirects"
  description = "URL redirects"
  kind        = "zone"
  phase       = "http_request_dynamic_redirect"

  # www to apex redirect
  rules {
    action = "redirect"
    action_parameters {
      from_value {
        status_code = 301
        target_url {
          expression = "concat(\"https://example.com\", http.request.uri.path)"
        }
        preserve_query_string = true
      }
    }
    expression  = "(http.host eq \"www.example.com\")"
    description = "Redirect www to apex"
    enabled     = true
  }

  # Old URL to new URL
  rules {
    action = "redirect"
    action_parameters {
      from_value {
        status_code = 301
        target_url {
          value = "https://example.com/new-page"
        }
      }
    }
    expression  = "(http.request.uri.path eq \"/old-page\")"
    description = "Redirect old page to new"
    enabled     = true
  }
}

Zone Settings

Performance Settings

resource "cloudflare_zone_settings_override" "performance" {
  zone_id = data.cloudflare_zone.main.id

  settings {
    # Compression
    brotli = "on"

    # Speed optimizations
    minify {
      css  = "on"
      html = "on"
      js   = "on"
    }

    # Early Hints
    early_hints = "on"

    # HTTP/2 and HTTP/3
    http2 = "on"
    http3 = "on"

    # 0-RTT
    zero_rtt = "on"

    # Rocket Loader (async JS loading)
    rocket_loader = "on"

    # Image optimization (requires Pro+)
    # polish = "lossless"
    # mirage = "on"

    # Mobile redirect (if needed)
    # mobile_redirect {
    #   mobile_subdomain = "m"
    #   status           = "on"
    #   strip_uri        = false
    # }
  }
}

Security Settings

resource "cloudflare_zone_settings_override" "security" {
  zone_id = data.cloudflare_zone.main.id

  settings {
    # Security level: off, essentially_off, low, medium, high, under_attack
    security_level = "medium"

    # Challenge Passage TTL
    challenge_ttl = 1800

    # Browser Integrity Check
    browser_check = "on"

    # Email Obfuscation
    email_obfuscation = "on"

    # Server Side Excludes
    server_side_exclude = "on"

    # Hotlink Protection
    hotlink_protection = "on"

    # IP Geolocation
    ip_geolocation = "on"
  }
}

Argo & Load Balancing

See resources/load-balancer.md for Argo Smart Routing and Load Balancer configuration with origin pools, health checks, and session affinity.

Workers Routes

# Deploy Worker via Terraform (see wrangler-coder for full Worker management)
resource "cloudflare_worker_route" "api" {
  zone_id     = data.cloudflare_zone.main.id
  pattern     = "example.com/api/*"
  script_name = cloudflare_worker_script.api.name
}

resource "cloudflare_worker_script" "api" {
  account_id = var.cloudflare_account_id
  name       = "api-worker"
  content    = file("${path.module}/workers/api.js")
  module     = true

  plain_text_binding {
    name = "ENVIRONMENT"
    text = var.environment
  }

  secret_text_binding {
    name = "API_KEY"
    text = var.api_key
  }
}

Complete Production Zone

See resources/production-zone.md for a complete Terraform configuration with DNS, SSL/TLS, WAF, caching, redirects, and variables template.

Best Practices

  • Use API Tokens - Scoped permissions over global API key
  • Enable Strict SSL - Always use Full (Strict) mode with valid origin certs
  • Use Rulesets - Modern rulesets over legacy Page Rules
  • Cache Strategically - Static assets cached, dynamic bypassed
  • Rate Limit APIs - Protect endpoints from abuse
  • Enable WAF - Deploy managed rulesets as baseline
  • HSTS Preload - Add to browser preload list for max security
  • Terraform State - Store state securely, not in version control

Repository

majesticlabs-dev
majesticlabs-dev
Author
majesticlabs-dev/majestic-marketplace/plugins/majestic-devops/skills/cloudflare-coder
13
Stars
0
Forks
Updated4d ago
Added6d ago