128 lines
3.2 KiB
Terraform
128 lines
3.2 KiB
Terraform
# The site on Railway: one project, with an environment each for prod and dev,
|
|
# and one service that runs the repo's Dockerfile. server.py does the routing,
|
|
# as it does locally; Railway holds the certificates.
|
|
#
|
|
# Terraform makes the project, the service and the domains, and puts their
|
|
# records on Cloudflare. It never deploys: deploy.sh uploads the site with
|
|
# Railway's CLI. State is local (terraform.tfstate here, gitignored).
|
|
|
|
terraform {
|
|
required_version = ">= 1.10"
|
|
required_providers {
|
|
railway = { source = "terraform-community-providers/railway", version = "~> 0.6.2" }
|
|
cloudflare = { source = "cloudflare/cloudflare", version = "~> 5.25" }
|
|
}
|
|
}
|
|
|
|
# Reads RAILWAY_TOKEN (compose.yaml sets it from RAILWAY_API_TOKEN in .env):
|
|
# a workspace token.
|
|
provider "railway" {}
|
|
|
|
# Reads CLOUDFLARE_API_TOKEN: DNS edit and zone read, on aerlinn.net only.
|
|
provider "cloudflare" {}
|
|
|
|
locals {
|
|
zone = "aerlinn.net"
|
|
# Railway Metal, Virginia.
|
|
region = "us-east4-eqdc4a"
|
|
}
|
|
|
|
resource "railway_project" "bible" {
|
|
name = "bible"
|
|
description = "Offline Bible reader"
|
|
default_environment = {
|
|
name = "production"
|
|
}
|
|
}
|
|
|
|
resource "railway_environment" "dev" {
|
|
name = "dev"
|
|
project_id = railway_project.bible.id
|
|
}
|
|
|
|
resource "railway_service" "site" {
|
|
name = "site"
|
|
project_id = railway_project.bible.id
|
|
regions = [{
|
|
region = local.region
|
|
num_replicas = 1
|
|
}]
|
|
|
|
# Made after both environments, so it is in both.
|
|
depends_on = [railway_environment.dev]
|
|
}
|
|
|
|
locals {
|
|
environments = {
|
|
production = {
|
|
id = railway_project.bible.default_environment.id
|
|
domain = "bible-2.${local.zone}"
|
|
}
|
|
dev = {
|
|
id = railway_environment.dev.id
|
|
domain = "bible-dev.${local.zone}"
|
|
}
|
|
}
|
|
}
|
|
|
|
resource "railway_custom_domain" "site" {
|
|
for_each = local.environments
|
|
|
|
domain = each.value.domain
|
|
environment_id = each.value.id
|
|
service_id = railway_service.site.id
|
|
}
|
|
|
|
data "cloudflare_zone" "site" {
|
|
filter = {
|
|
name = local.zone
|
|
}
|
|
}
|
|
|
|
# DNS only, not proxied: Railway issues the certificate itself and has to see
|
|
# the CNAME as it is.
|
|
resource "cloudflare_dns_record" "site" {
|
|
for_each = railway_custom_domain.site
|
|
|
|
zone_id = data.cloudflare_zone.site.id
|
|
name = each.value.domain
|
|
type = "CNAME"
|
|
content = each.value.dns_record_value
|
|
ttl = 1
|
|
proxied = false
|
|
comment = "terraform: railway bible ${each.key}"
|
|
}
|
|
|
|
# Railway's proof that the domain is ours.
|
|
resource "cloudflare_dns_record" "verification" {
|
|
for_each = railway_custom_domain.site
|
|
|
|
zone_id = data.cloudflare_zone.site.id
|
|
name = "${each.value.verification_host_label}.${each.value.zone}"
|
|
type = "TXT"
|
|
content = "\"${each.value.verification_record_value}\""
|
|
ttl = 1
|
|
comment = "terraform: railway bible ${each.key} verification"
|
|
}
|
|
|
|
output "project_id" {
|
|
value = railway_project.bible.id
|
|
}
|
|
|
|
output "service" {
|
|
value = railway_service.site.name
|
|
}
|
|
|
|
output "domains" {
|
|
value = {
|
|
for name, d in railway_custom_domain.site : name => {
|
|
domain = d.domain
|
|
host_label = d.host_label
|
|
zone = d.zone
|
|
target = d.dns_record_value
|
|
verification_host = d.verification_host_label
|
|
verification = d.verification_record_value
|
|
}
|
|
}
|
|
}
|