skills/terraform/SKILL.md
Instructions for managing the Cloudflare infrastructure with Terraform. Use this when you need to work with Terraform or Cloudflare resources.
npx skillsauth add nikoheikkila/nikoheikkila.fi terraformInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Infrastructure is managed in the infra/ directory using Terraform with Cloudflare provider:
nikoheikkila.fidns.yml) for easier maintenanceAll commands must be run within the infra/ directory:
cd infra/
# Initialize Terraform providers and backend
task init
# Format Terraform code
task format
# Validate configuration
task validate
# Plan infrastructure changes
task plan
# Apply changes (after careful review)
task deploy
See all commands by running task -a in the infra/ directory.
Terraform variables are configured in infra/cloudflare.tfvars:
account_id (required): CloudFlare account ID (32-char hex)domain (optional): Primary domain (default: nikoheikkila.fi)r2_bucket_name (optional): R2 bucket name (default: blog)r2_bucket_location (optional): Bucket location (default: EEUR)r2_storage_class (optional): Storage class (default: Standard)worker_service_name (optional): Worker service name (default: blog)All variables have sensible defaults except account_id.
infra/dns.ymltask plan (from infra directory)task deployImportant DNS Considerations:
task format before committingtask plan before task deploy.tfstate files (state is always stored remotely)task run -- force-unlock <LOCK_ID>Subdomain redirects are managed via infra/redirects.yml and applied automatically through infra/locals.tf and infra/dns.tf. To add a redirect, append an entry to redirects.yml and run task plan then task deploy — no HCL changes needed.
redirects.yml schema:
redirects:
- from: subdomain # subdomain prefix, e.g. "cv" → cv.nikoheikkila.fi
to: "https://..." # redirect target URL
status: 301 # HTTP status code
preserve_path: true # optional: appends request path to target (default: false)
Key constraints to be aware of:
cloudflare_ruleset resource per phase. All redirect rules (including the www→root redirect) are merged into the single cloudflare_ruleset.www_redirect resource via local.redirect_rules in locals.tf. Never create a second ruleset for the same phase.redirects.yml by cloudflare_dns_record.redirects in dns.tf.from key already exists in dns_config.dns_records (i.e. dns.yml) are excluded from cloudflare_dns_record.redirects to prevent duplicate record conflicts. This is how the www entry coexists in both files.target_url form: Use { value = "..." } for static external URLs. Use { expression = "concat(\"...\", http.request.uri.path)" } when preserve_path: true to forward the request path. The preserve_path field in the YAML controls which form is used.task format to fix formatting issues.tf filesdns.ymlcloudflare.tfvarsgh run listtask run -- force-unlock <LOCK_ID>op account get.env file contains correct 1Password referencesCLOUDFLARE_API_TOKEN has sufficient permissionsView infrastructure outputs:
cd infra/
task run -- output
Available outputs:
zone_id: CloudFlare zone IDzone_name: Domain namer2_bucket_id: R2 bucket identifierr2_bucket_name: R2 bucket namer2_custom_domain: Custom domain for R2 accessworker_custom_domain: Worker hostnamedns_record_count: Number of managed DNS recordstesting
Instructions for running project tasks. Use this when you need to run a project-specific command or workflow.
testing
Review blog posts and pages for grammar, style, frontmatter validity, technical accuracy, and SEO. Use this when asked to review, proofread, or validate Markdown content.
development
Instructions for using Playwright to test the blog. Use this when you need to write, run or debug Playwright tests for the blog.
devops
Local text-to-speech via sherpa-onnx (offline, no cloud)