thermograph/terraform/terraform.tfvars.example
Emi Griffith a26ca72834 Self-host the ERA5 archive via Open-Meteo (object storage) (#224)
Get the 45-year historical record off the rate-limited public Open-Meteo
archive API by running a private Open-Meteo instance that serves the
era5_seamless blend (0.1° ERA5-Land + 0.25° ERA5 for gusts) from the
compressed .om archive in object storage, mounted on the host with rclone.

- climate.py: make ARCHIVE_URL env-driven (THERMOGRAPH_ARCHIVE_URL) and pin
  models=era5_seamless on the archive fetches only, so a self-hosted instance
  serves the same 0.1° resolution; forecast path unchanged. The public API's
  default is already seamless, so dev/beta (URL unset) behave identically.
- docker-compose.openmeteo.yml: open-meteo-api + two rolling sync workers
  (era5_land 0.1°, era5 0.25° for gusts), bind-mounting the object-storage
  mount; the overlay points the app at the local instance.
- Makefile: om-up / om-down / om-backfill (one-time full-history backfill).
- Terraform: per-host openmeteo flag layers the overlay, renders OM_DATA_DIR,
  and provisions the host rclone systemd mount from the bucket credentials.
- deploy/openmeteo: operator runbook + rclone mount unit template.
2026-07-20 13:16:56 +00:00

106 lines
4.6 KiB
Text

# Copy to terraform.tfvars and fill in real IPs + secrets.
# cp terraform.tfvars.example terraform.tfvars
# terraform.tfvars is gitignored (it holds secrets, and those land in local state).
# NEVER commit real values.
# ---------------------------------------------------------------------------------
# Hosts
# ---------------------------------------------------------------------------------
# Two VPS hosts. (The `dev` branch deploys to the LAN dev server via
# deploy/deploy-dev.sh — that box is NOT managed by Terraform.)
hosts = {
# Production: the NEW 48 GB / 12-core VPS serving thermograph.org (branch `release`).
prod = {
host = "REPLACE_WITH_NEW_VPS_IP" # <-- the new prod VPS IP/hostname
ssh_user = "deploy"
ssh_private_key_path = "~/.ssh/id_ed25519" # key that can log in as deploy@ and sudo
role = "prod"
git_branch = "release"
domain = "thermograph.org" # Caddy TLS in front, app on loopback
compose_files = ["docker-compose.yml"]
app_dir = "/opt/thermograph"
# Sized up for the big box — tune freely. Also raise the Postgres internal budget
# in deploy/db/init/20-tuning.sql (shared_buffers etc.) to actually use the RAM.
workers = 8
app_cpus = 8
db_cpus = 4
db_memory = "16g"
# Self-host the ERA5 archive here: layers docker-compose.openmeteo.yml and
# provisions the rclone mount of the object-storage bucket (om_* vars below).
openmeteo = true
om_data_dir = "/mnt/om-archive"
}
# Beta / testing: the OLD VPS, repurposed (branch `main`).
beta = {
host = "75.119.132.91"
ssh_user = "deploy"
ssh_private_key_path = "~/.ssh/id_ed25519"
role = "beta"
git_branch = "main"
# No public domain by default: no Caddy/TLS, firewall opens the app port. NOTE:
# with compose_files = ["docker-compose.yml"] the app binds 127.0.0.1 only, so
# until you either set a domain (e.g. "beta.thermograph.org", which fronts it with
# Caddy) or add the 0.0.0.0-publishing dev overlay, reach it via an SSH tunnel.
domain = ""
compose_files = ["docker-compose.yml"]
app_dir = "/opt/thermograph"
workers = 4
app_cpus = 4
db_cpus = 2
db_memory = "8g"
}
}
# Optional overrides (shown with their defaults):
# repo_url = "https://github.com/griffemi/thermograph.git"
# app_port = 8137
# ---------------------------------------------------------------------------------
# Self-hosted Open-Meteo archive (only used by hosts with openmeteo = true) --------
# ---------------------------------------------------------------------------------
# The ERA5 .om archive lives in an object-storage bucket, rclone-mounted on the host.
# om_rclone_conf holds bucket credentials (sensitive; lands in state — keep out of git).
# See deploy/openmeteo/README.md for the bucket + mount setup.
om_bucket_remote = "om-archive:REPLACE_WITH_BUCKET_NAME"
om_vfs_cache_max = "80G"
om_rclone_conf = <<-RCLONE
[om-archive]
type = s3
provider = Cloudflare
endpoint = https://REPLACE.r2.cloudflarestorage.com
access_key_id = REPLACE_WITH_ACCESS_KEY
secret_access_key = REPLACE_WITH_SECRET_KEY
RCLONE
# ---------------------------------------------------------------------------------
# Shared secrets (DUMMY values — replace, and keep this file out of git)
# ---------------------------------------------------------------------------------
postgres_password = "REPLACE_WITH_A_STRONG_DB_PASSWORD"
# python -c "import secrets; print(secrets.token_urlsafe(48))"
auth_secret = "REPLACE_WITH_A_LONG_RANDOM_STRING"
# cd backend && ../.venv/bin/python -c "import push,json;k=push._generate();print(k['private_key']);print(k['public_key'])"
vapid_private_key = "REPLACE_WITH_VAPID_PRIVATE_KEY"
vapid_public_key = "REPLACE_WITH_VAPID_PUBLIC_KEY"
vapid_contact = "mailto:you@example.com"
# ---- Optional: search-engine verification (leave "" to omit) --------------------
# google_verify = ""
# bing_verify = ""
# ---- Optional: outbound email (leave "" to omit) --------------------------------
# mail_backend = "smtp"
# smtp_host = "127.0.0.1"
# smtp_port = "25"
# smtp_user = ""
# smtp_password = ""
# smtp_starttls = ""
# mail_from = "Thermograph <no-reply@thermograph.org>"
# mail_reply_to = ""
# ---- Optional: Discord (leave "" to omit) ---------------------------------------
# discord_webhook = ""
# discord_public_key = ""
# discord_app_id = ""
# discord_bot_token = ""
# discord_client_secret = ""