Skip to content

Commit 4bea804

Browse files
committed
feature: initial terraform configuration for cloudflare
1 parent 327a58f commit 4bea804

File tree

19 files changed

+441
-0
lines changed

19 files changed

+441
-0
lines changed

shell.nix

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ pkgs.mkShell {
5555
pkgs.xz
5656
pkgs.libxml2
5757
pkgs.pkg-config
58+
59+
# Terraform
60+
pkgs.terraform
61+
pkgs.wrangler
5862
]
5963
++ pkgs.lib.optional with-blackfire pkgs.blackfire
6064
;

terraform/cloudflare/.gitignore

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Terraform state files
2+
*.tfstate
3+
*.tfstate.*
4+
5+
# Terraform variable files with sensitive data
6+
*.auto.tfvars
7+
8+
# Terraform CLI configuration files
9+
.terraformrc
10+
terraform.rc
11+
12+
# Terraform directory
13+
.terraform/
14+
15+
# Wrangler / Workers local development
16+
workers/.dev.vars
17+
workers/.wrangler/
18+
.terraform.lock.hcl
19+
20+
# Crash log files
21+
crash.log
22+
crash.*.log
23+
24+
# Override files
25+
override.tf
26+
override.tf.json
27+
*_override.tf
28+
*_override.tf.json
29+
30+
# Plans
31+
*.tfplan

terraform/cloudflare/README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Cloudflare Terraform
2+
3+
Required Variables:
4+
5+
```
6+
export CLOUDFLARE_API_TOKEN="xxx"
7+
export TF_VAR_account_id="xxx"
8+
export TF_VAR_zone_id="xxx"
9+
```
10+
11+
# Initialization
12+
13+
```
14+
terraform init
15+
```

terraform/cloudflare/dns.tf

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# DNS records for flow-php.com zone
2+
3+
# This file is intentionally minimal - the R2 custom domain resource
4+
# automatically creates the necessary DNS records for playground-snippets.flow-php.com
5+
# via cloudflare_r2_custom_domain resource in r2.tf
6+
7+
# Add additional DNS records below as needed

terraform/cloudflare/main.tf

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
resource "cloudflare_account" "account" {
2+
3+
type = "standard"
4+
}
5+
6+
import {
7+
id = var.account_id
8+
to = cloudflare_account.account
9+
}
10+
11+
resource "cloudflare_zone" "flow_php" {
12+
account = cloudflare_account.account
13+
name = "flow-php.com"
14+
15+
paused = false
16+
}
17+
18+
import {
19+
id = var.zone_id
20+
to = cloudflare_zone.flow_php
21+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
locals {
2+
k = 1000
3+
m = 1000 * local.k
4+
mb = 1024 * 1024
5+
gb = 1024 * 1024 * 1024
6+
7+
r2_storage_free_tier = 10 * local.gb # 10 GB
8+
r2_class_a_operations_free_tier = 1 * local.m # 1 million requests
9+
r2_class_b_operations_free_tier = 10 * local.m # 10 million requests
10+
11+
thresholds = [10, 20, 30, 40, 50, 60, 70, 80, 90, 95]
12+
13+
notification_configs = merge(
14+
{
15+
for threshold in local.thresholds :
16+
"r2_storage_${threshold}" => {
17+
name = "R2 Storage - ${threshold}% of Free Tier"
18+
product = "r2_storage"
19+
limit = local.r2_storage_free_tier * (threshold / 100)
20+
description = "Alert when R2 storage usage reaches ${threshold}% of free tier (${threshold / 10} GB)"
21+
}
22+
},
23+
{
24+
for threshold in local.thresholds :
25+
"r2_class_a_${threshold}" => {
26+
name = "R2 Class A Operations - ${threshold}% of Free Tier"
27+
product = "r2_class_a_operations"
28+
limit = local.r2_class_a_operations_free_tier * (threshold / 100)
29+
description = "Alert when R2 Class A operations reach ${threshold}% of free tier (${threshold * 10000} requests)"
30+
}
31+
},
32+
{
33+
for threshold in local.thresholds :
34+
"r2_class_b_${threshold}" => {
35+
name = "R2 Class B Operations - ${threshold}% of Free Tier"
36+
product = "r2_class_b_operations"
37+
limit = local.r2_class_b_operations_free_tier * (threshold / 100)
38+
description = "Alert when R2 Class B operations reach ${threshold}% of free tier (${threshold * 100000} requests)"
39+
}
40+
}
41+
)
42+
}
43+
44+
resource "cloudflare_notification_policy" "r2_notifications" {
45+
for_each = local.notification_configs
46+
47+
account_id = cloudflare_account.account.id
48+
name = each.value.name
49+
enabled = true
50+
alert_type = "billing_usage_alert"
51+
52+
filters = {
53+
limit = [each.value.limit]
54+
product = [each.value.product]
55+
}
56+
57+
mechanisms = {
58+
email = [{
59+
id = var.notification_email
60+
}]
61+
}
62+
}

terraform/cloudflare/outputs.tf

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
output "turnstile_site_key" {
2+
description = "Turnstile site key for Flow PHP Playground (public, use in frontend)"
3+
value = cloudflare_turnstile_widget.flow_php.id
4+
}
5+
6+
output "turnstile_secret_key" {
7+
description = "Turnstile secret key for Flow PHP Playground (private, use in backend)"
8+
value = cloudflare_turnstile_widget.flow_php.secret
9+
sensitive = true
10+
}
11+
12+
output "r2_playground_snippets_bucket_name" {
13+
description = "Name of the R2 bucket for playground snippets"
14+
value = cloudflare_r2_bucket.playground_snippets.name
15+
}
16+
17+
output "r2_playground_snippets_bucket_id" {
18+
description = "ID of the R2 bucket for playground snippets"
19+
value = cloudflare_r2_bucket.playground_snippets.id
20+
}
21+
22+
output "r2_playground_snippets_custom_domain" {
23+
description = "Custom domain URL for R2 playground snippets bucket"
24+
value = "https://playground-snippets.flow-php.com"
25+
}

terraform/cloudflare/provider.tf

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
provider "cloudflare" {
2+
}

terraform/cloudflare/r2.tf

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
resource "cloudflare_r2_bucket" "playground_snippets" {
2+
account_id = cloudflare_account.account.id
3+
name = "flow-php-playground-snippets"
4+
location = "eeur"
5+
}
6+
7+
resource "cloudflare_r2_bucket_cors" "playground_snippets_cors" {
8+
account_id = cloudflare_account.account.id
9+
bucket_name = cloudflare_r2_bucket.playground_snippets.name
10+
11+
rules = [{
12+
allowed = {
13+
methods = ["GET", "PUT", "POST", "DELETE", "HEAD"]
14+
origins = ["https://flow-php.com"]
15+
headers = ["*"]
16+
}
17+
id = "playground-snippets-cors"
18+
expose_headers = ["ETag"]
19+
max_age_seconds = 3600
20+
}]
21+
}
22+
23+
resource "cloudflare_r2_custom_domain" "playground_snippets" {
24+
account_id = cloudflare_account.account.id
25+
bucket_name = cloudflare_r2_bucket.playground_snippets.name
26+
domain = "playground-snippets.flow-php.com"
27+
zone_id = cloudflare_zone.flow_php.id
28+
enabled = true
29+
}

terraform/cloudflare/turnstile.tf

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
resource "cloudflare_turnstile_widget" "flow_php" {
2+
account_id = cloudflare_account.account.id
3+
name = "Flow PHP"
4+
domains = ["flow-php.com", "www.flow-php.com"]
5+
mode = "managed"
6+
region = "world"
7+
}

0 commit comments

Comments
 (0)