Skip to content

Instantly share code, notes, and snippets.

@aldoborrero
Created November 25, 2022 21:03
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aldoborrero/d77d4744c68bb14395d4bf17b5d829a7 to your computer and use it in GitHub Desktop.
Save aldoborrero/d77d4744c68bb14395d4bf17b5d829a7 to your computer and use it in GitHub Desktop.
How to setup a Nix binary cache with Terraform in DigitalOcean Spaces + CDN and custom subdomain in Cloudflare
locals {
domain = "example.com"
}
data "cloudflare_zone" "domain" {
name = local.domain
}
resource "tls_private_key" "nix_store_origin_key" {
algorithm = "RSA"
rsa_bits = 2048
}
resource "tls_cert_request" "nix_store_origin_cert" {
private_key_pem = tls_private_key.nix_store_origin_key.private_key_pem
subject {
common_name = "cache.${local.domain}"
organization = "Willy Wonka LTD"
country = "USA"
locality = "Los Angeles"
}
}
resource "cloudflare_origin_ca_certificate" "nix_store_origin_cert" {
# See: https://github.com/cloudflare/terraform-provider-cloudflare/issues/1919#issuecomment-1270722657
provider = cloudflare.cf-user-service-auth
csr = tls_cert_request.nix_store_origin_cert.cert_request_pem
hostnames = ["cache.${local.domain}"]
request_type = "origin-rsa"
requested_validity = 365
}
resource "digitalocean_certificate" "nix_store_origin_cert" {
name = "cf-origin-cert"
type = "custom"
private_key = tls_private_key.nix_store_origin_key.private_key_pem
leaf_certificate = cloudflare_origin_ca_certificate.nix_store_origin_cert.certificate
}
resource "digitalocean_cdn" "nix_store_cdn" {
origin = digitalocean_spaces_bucket.nix_store.bucket_domain_name
certificate_name = digitalocean_certificate.nix_store_origin_cert.name
custom_domain = "cache.${local.domain}"
}
resource "cloudflare_record" "nix_store_cache" {
name = "cache"
value = digitalocean_cdn.nix_store_cdn.endpoint
type = "CNAME"
ttl = 1 # Auto
proxied = true
zone_id = data.cloudflare_zone.domain.id
}
resource "digitalocean_spaces_bucket" "nix_store" {
name = "nix-store"
region = "fra1"
acl = "private"
lifecycle_rule {
id = "ttl"
enabled = true
abort_incomplete_multipart_upload_days = 1
expiration {
days = 30
}
}
versioning {
enabled = true
}
}
# See: https://fzakaria.com/2021/08/12/a-nix-binary-cache-specification.html
# See `NixCacheInfo Schema` to understand each parameter https://fzakaria.github.io/nix-http-binary-cache-api-spec/#/
resource "digitalocean_spaces_bucket_object" "nix_cache_info" {
region = digitalocean_spaces_bucket.nix_store.region
bucket = digitalocean_spaces_bucket.nix_store.name
content_type = "text/html"
key = "nix-cache-info"
content = <<EOF
StoreDir: /nix/store
WantMassQuery: 1
Priority: 10
EOF
}
# See: https://nixos.org/manual/nix/stable/package-management/s3-substituter.html#anonymous-reads-to-your-s3-compatible-binary-cache
resource "digitalocean_spaces_bucket_policy" "nix_cache_anonymous_reads" {
region = digitalocean_spaces_bucket.nix_store.region
bucket = digitalocean_spaces_bucket.nix_store.name
policy = jsonencode({
"Id" : "DirectReads",
"Version" : "2012-10-17",
"Statement" : [
{
"Sid" : "AllowDirectReads",
"Action" : [
"s3:GetObject",
"s3:GetBucketLocation"
],
"Effect" : "Allow",
"Resource" : [
"arn:aws:s3:::${digitalocean_spaces_bucket.nix_store.name}",
"arn:aws:s3:::${digitalocean_spaces_bucket.nix_store.name}/*"
],
"Principal" : "*"
}
]
})
}
terraform {
required_providers {
cloudflare = { source = "cloudflare/cloudflare" }
digitalocean = { source = "digitalocean/digitalocean" }
tls = { source = "hashicorp/tls" }
}
}
## Special configuration for Cloudflare Provider
## Some resources like 'cloudflare_origin_ca_certificate' needs to use special tokens. With recent work
## performed on the new Cloudflare Provider, the suggested solution is to configure provider aliases.
## See more info: https://github.com/cloudflare/terraform-provider-cloudflare/issues/1919
variable "CF_API_TOKEN" {
type = string
sensitive = true
}
variable "CF_API_USER_SERVICE_KEY" {
type = string
sensitive = true
}
provider "cloudflare" {
api_token = var.CF_API_TOKEN
}
provider "cloudflare" {
alias = "cf-user-service-auth"
api_user_service_key = var.CF_API_USER_SERVICE_KEY
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment