72 lines
2.6 KiB
Markdown
72 lines
2.6 KiB
Markdown
# Infra (OpenTofu → Vultr)
|
|
|
|
Provisions a single Vultr instance for the dev_blog:
|
|
|
|
| Setting | Value |
|
|
| -------------- | ---------------------------------- |
|
|
| Region | `sea` (Seattle) |
|
|
| Plan | `vc2-1c-2gb` |
|
|
| OS | AlmaLinux 10 (looked up via `data "vultr_os"`) |
|
|
| Backups | Automated, daily |
|
|
| IPv6 | Enabled |
|
|
|
|
State is stored in **Cloudflare R2** via OpenTofu's S3-compatible backend.
|
|
|
|
## One-time setup
|
|
|
|
### 1. R2 bucket
|
|
|
|
In the Cloudflare dashboard:
|
|
|
|
1. Create an R2 bucket, e.g. `dev-blog-tfstate`.
|
|
2. Create an R2 API token (Account → R2 → Manage API tokens) with **Object Read & Write** scoped to that bucket. Note the access key ID + secret.
|
|
3. Note your Cloudflare **Account ID** (R2 endpoint host).
|
|
|
|
### 2. GitHub repository secrets
|
|
|
|
Add these in *Settings → Secrets and variables → Actions*:
|
|
|
|
| Secret | Value |
|
|
| ----------------------- | ------------------------------------ |
|
|
| `VULTR_API_KEY` | Vultr API key |
|
|
| `R2_ACCESS_KEY_ID` | R2 token access key ID |
|
|
| `R2_SECRET_ACCESS_KEY` | R2 token secret access key |
|
|
| `R2_ACCOUNT_ID` | Cloudflare account ID |
|
|
| `R2_BUCKET` | `dev-blog-tfstate` |
|
|
|
|
## Running locally
|
|
|
|
```sh
|
|
cd infra
|
|
cp backend.hcl.example backend.hcl # fill in bucket + endpoint
|
|
cp terraform.tfvars.example terraform.tfvars
|
|
|
|
export AWS_ACCESS_KEY_ID=<r2-key-id>
|
|
export AWS_SECRET_ACCESS_KEY=<r2-secret>
|
|
export TF_VAR_vultr_api_key=<vultr-key>
|
|
|
|
tofu init -backend-config=backend.hcl
|
|
tofu plan
|
|
tofu apply
|
|
```
|
|
|
|
## CI/CD
|
|
|
|
The workflow [`.github/workflows/infra.yml`](../.github/workflows/infra.yml) runs:
|
|
|
|
- **`pull_request`** touching `infra/**` → `tofu plan` (read-only).
|
|
- **`workflow_dispatch`** → choose `plan`, `apply`, or `destroy`.
|
|
|
|
Backend init uses `-backend-config` flags so the bucket and R2 endpoint are
|
|
injected from secrets at runtime — no account-specific values are committed.
|
|
|
|
## Notes
|
|
|
|
- The Vultr provider's `vultr_instance` resource enables daily backups via
|
|
`backups = "enabled"` and a `backups_schedule { type = "daily" }` block.
|
|
- AlmaLinux 10 is resolved by name through `data "vultr_os"` so we don't have
|
|
to hard-code an OS ID that may change. Adjust `os_name_filter` in
|
|
`variables.tf` if Vultr renames it.
|
|
- The R2 backend uses `region = "auto"` and skips AWS-specific validations,
|
|
which is the standard configuration for R2 as an OpenTofu/Terraform S3 backend.
|