This skill guides provisioning Cloudflare infrastructure with OpenTofu/Terraform. Use when managing zones, DNS records, WAF rules, SSL settings, Page Rules, or cache configuration.
Provisions Cloudflare infrastructure using OpenTofu/Terraform. Use when configuring DNS records, SSL/TLS settings, WAF rules, cache rules, redirects, or zone settings.
/plugin marketplace add majesticlabs-dev/majestic-marketplace/plugin install majestic-devops@majestic-marketplaceThis skill is limited to using the following tools:
resources/load-balancer.mdresources/production-zone.mdresources/waf.mdCloudflare provides CDN, DNS, security, and edge computing services. This skill covers OpenTofu/Terraform patterns for Cloudflare resources.
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
}
# 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):
| Resource | Permission | Use Case |
|---|---|---|
| Zone | Read | List zones, read settings |
| Zone | Edit | Modify zone settings |
| DNS | Edit | Manage DNS records |
| Firewall | Edit | WAF, firewall rules |
| SSL | Edit | Certificate management |
| Cache | Purge | Cache invalidation |
data "cloudflare_zone" "main" {
name = "example.com"
}
# Use in resources
resource "cloudflare_record" "www" {
zone_id = data.cloudflare_zone.main.id
# ...
}
data "cloudflare_accounts" "main" {
name = "My Account"
}
output "account_id" {
value = data.cloudflare_accounts.main.accounts[0].id
}
# 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
}
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
}
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"
}
}
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
}
See resources/waf.md for IP access rules, WAF custom rules with rate limiting, and managed rulesets (Cloudflare + OWASP).
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
}
}
# 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
}
}
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
}
}
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
# }
}
}
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"
}
}
See resources/load-balancer.md for Argo Smart Routing and Load Balancer configuration with origin pools, health checks, and session affinity.
# 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
}
}
See resources/production-zone.md for a complete Terraform configuration with DNS, SSL/TLS, WAF, caching, redirects, and variables template.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.