This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

Manage openletter.pub and openletter.vote DNS with Terraform

Linode DNS for both domains, organized by domain (openletter.pub/domain.tf and
openletter.vote/domain.tf) with a small root module so a single terraform plan
from the repo root covers both. State lives in a Linode Object Storage bucket.

openletter.pub carries the _atproto handle attestation and the _lexicon
resolution record, both pointing at the dedicated openletter.pub account
(did:plc:vrxdl7yd3vz2hzdosqaywvb3). Secrets come from a gitignored
.envrc.private; see .envrc.private.example.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

+125
+1
.envrc
··· 1 + source_env_if_exists .envrc.private
+4
.envrc.private.example
··· 1 + # Copy to .envrc.private (gitignored) and fill in the values. 2 + export LINODE_TOKEN="" # Linode API token (DNS provider) 3 + export AWS_ACCESS_KEY_ID="" # Linode Object Storage key (Terraform state) 4 + export AWS_SECRET_ACCESS_KEY="" # Linode Object Storage secret (Terraform state)
+10
.gitignore
··· 8 8 .idea/ 9 9 .vscode/ 10 10 *~ 11 + 12 + # direnv 13 + .envrc.private 14 + 15 + # Terraform 16 + .terraform/ 17 + *.tfstate 18 + *.tfstate.* 19 + crash.log 20 + *.tfvars
+23
.terraform.lock.hcl
··· 1 + # This file is maintained automatically by "terraform init". 2 + # Manual edits may be lost in future updates. 3 + 4 + provider "registry.terraform.io/linode/linode" { 5 + version = "3.14.1" 6 + constraints = "~> 3.0" 7 + hashes = [ 8 + "h1:XNfCTg85vEWjIvcM2RL8q4/JEarrs3BWffo99PozYfE=", 9 + "zh:300fe0d5791527485e7e1dfda3a81283ecdabef4b48e5ba29f29d6cd1936eab7", 10 + "zh:3d7c36946b4be99bf4c2c341f7124118803af3d09b5e36fc3f2ba450b0a4bfab", 11 + "zh:425768f3b409d868db05e79100c8032d20db7d7aa316ace20d76d5996e2a9f36", 12 + "zh:4332ebbc4ebe871b735fa5117abb77dcfae68152f82571e279141027d0b5d0ab", 13 + "zh:73fece9bce0100f136b7dd7286f578fadb97395d9fb25c0121e39d8801497db2", 14 + "zh:763ac2cd1bba91210228ba98ba21abd74ab62877e38ec2793bbeb1f1d28327ad", 15 + "zh:8dd2b605d762243343bec0d5c402d0940c6f84f0168c7a1c69dbda7a4096b64c", 16 + "zh:918085d3ebcbd4bc173a65431a684fb10179c9279c3c8426b49a7fa2af410042", 17 + "zh:9b362a78ab55724305a8d87c7e50311f63dd6267ebf5e4ca935fcdffb02833d5", 18 + "zh:9f856cb32278b20bfd49c4c9c50bfabc83990f611fe32469708bef735069970a", 19 + "zh:a0ed3d8552a2fc5d49d0daa0c1da23c354f4a37317532ff8219ded8ef248446e", 20 + "zh:af984f79fe1379aa19fdbcfa0a5453cbb41de80b9d46d477bfafdbee8224db3e", 21 + "zh:ff5e98cb470d36eacbac293dbcb7ae327e64d66a1d02d7453389d8fdaf5e7f03", 22 + ] 23 + }
+33
main.tf
··· 1 + terraform { 2 + required_providers { 3 + linode = { 4 + source = "linode/linode" 5 + version = "~> 3.0" 6 + } 7 + } 8 + 9 + backend "s3" { 10 + bucket = "openletter-terraform-state" 11 + key = "openletter.tfstate" 12 + region = "us-east-1" 13 + 14 + endpoints = { 15 + s3 = "https://us-east-1.linodeobjects.com" 16 + } 17 + 18 + skip_credentials_validation = true 19 + skip_region_validation = true 20 + skip_requesting_account_id = true 21 + skip_metadata_api_check = true 22 + } 23 + } 24 + 25 + provider "linode" {} 26 + 27 + module "openletter_pub" { 28 + source = "./openletter.pub" 29 + } 30 + 31 + module "openletter_vote" { 32 + source = "./openletter.vote" 33 + }
+37
openletter.pub/domain.tf
··· 1 + terraform { 2 + required_providers { 3 + linode = { 4 + source = "linode/linode" 5 + } 6 + } 7 + } 8 + 9 + variable "openletter_did" { 10 + type = string 11 + description = "DID of the dedicated openletter.pub account (hosted on Bluesky). Used for both the handle attestation and lexicon resolution." 12 + default = "did:plc:vrxdl7yd3vz2hzdosqaywvb3" 13 + } 14 + 15 + resource "linode_domain" "openletter_pub" { 16 + domain = "openletter.pub" 17 + type = "master" 18 + soa_email = "c@guid.foo" 19 + ttl_sec = 300 20 + } 21 + 22 + # Handle attestation: lets the account claim openletter.pub as its handle. 23 + resource "linode_domain_record" "atproto_handle" { 24 + domain_id = linode_domain.openletter_pub.id 25 + name = "_atproto" 26 + record_type = "TXT" 27 + target = "did=${var.openletter_did}" 28 + } 29 + 30 + # Lexicon resolution: points the pub.openletter NSID authority at the repo that 31 + # holds the published com.atproto.lexicon.schema records. 32 + resource "linode_domain_record" "lexicon" { 33 + domain_id = linode_domain.openletter_pub.id 34 + name = "_lexicon" 35 + record_type = "TXT" 36 + target = "did=${var.openletter_did}" 37 + }
+17
openletter.vote/domain.tf
··· 1 + terraform { 2 + required_providers { 3 + linode = { 4 + source = "linode/linode" 5 + } 6 + } 7 + } 8 + 9 + resource "linode_domain" "openletter_vote" { 10 + domain = "openletter.vote" 11 + type = "master" 12 + soa_email = "c@guid.foo" 13 + ttl_sec = 300 14 + } 15 + 16 + # Records for the openletter.vote web app will be added here once there is 17 + # something to point them at.