vole
Clone
Read only, no credentials:
https://rodent.software/git/vole.git
Write over SSH with a registered key:
git clone ssh://git@0.0.0.0:2222/vole.git
A free and open-source forge that lives in your Git repo.
Turn a fresh machine into an instance on first boot
04e063ca5d73b8f57f45d7c8bb07b0fdaa91b5b8 · Keenan Nemetz · 3d ago · parent ea21f923
Turn a fresh machine into an instance on first boot A new instance is one package, one configuration, one directory, and one account. Assembling that by hand is where a first deployment goes wrong: the capability the hardened unit needs for ports 80 and 443, the order that makes the package's own init harmless, and the fact that the first instance admin has to be granted on the host. deploy/cloud-init/vole.yaml is that assembly. It stages two configurations, one that lets Vole hold its own certificate and one that leaves TLS to a proxy, then installs the package, writes the configuration, creates the instance admin, and starts the service. Running it again changes nothing. render.sh renders it for providers that take user data without Terraform, using the placeholder list as the contract with the template. The three Terraform configurations create the machine, its firewall, its address, and optionally the DNS record, and hand it that same file. They are root modules: init and apply, three variables, no other file to edit. First boot is not configuration management. apply does not upgrade an instance or touch its data, because users.db migrates in place and cannot be rolled back.
deploy/README.md +34
| @@ -0,0 +1,34 @@ | |||
| 1 | # Deployment files | ||
| 2 | |||
| 3 | The files here put a Vole instance on a fresh machine. The guides are in | ||
| 4 | [docs/deploy](../docs/deploy/README.md); this page is what is in the box. | ||
| 5 | |||
| 6 | | Path | What it is | | ||
| 7 | |---|---| | ||
| 8 | | `cloud-init/vole.yaml` | The first-boot file. Installs the package, writes the configuration, creates the instance admin, starts the service. Used by every path below | | ||
| 9 | | `cloud-init/render.sh` | Renders that file for a machine you create by hand, with no Terraform | | ||
| 10 | | `terraform/hetzner`, `terraform/digitalocean`, `terraform/aws` | One complete Terraform configuration per cloud: machine, firewall, address, and optional DNS record. Each is used as a root module | | ||
| 11 | | `docker/Dockerfile` | The server in one image, built from this repository | | ||
| 12 | | `docker/compose.yaml` | That image, with a volume for the instance and a health check | | ||
| 13 | | `docker/vole.toml` | The configuration the image starts with, and the file to copy for a deployment | | ||
| 14 | | `docker/entrypoint.sh` | Runs `vole admin init` once, then the command you asked for | | ||
| 15 | |||
| 16 | Two things are deliberate: | ||
| 17 | |||
| 18 | - **The cloud-init file is the single source of truth.** The Terraform | ||
| 19 | configurations render it with `templatefile()`; `render.sh` renders it with | ||
| 20 | `envsubst`. Neither has its own copy of the setup steps, so a fix lands | ||
| 21 | everywhere at once. | ||
| 22 | - **There are no machine images.** A golden image per cloud would need a | ||
| 23 | publishing pipeline and a per-cloud import, and it would go stale between | ||
| 24 | releases. Installing a `.deb` during first boot takes about thirty seconds and | ||
| 25 | always installs the version you named. | ||
| 26 | |||
| 27 | Nothing here configures a machine after that first boot. Upgrades are a package | ||
| 28 | install on the machine, because a plan that replaces a server holding a team's | ||
| 29 | repositories is not a safe default. See [Packages](../docs/packaging.md). | ||
| 30 | |||
| 31 | `scripts/check-deploy.py` and the `deployment files` step in | ||
| 32 | `.vole/workflows/verify.yaml` check these files on every push: the YAML parses, | ||
| 33 | the template renders with no placeholder left behind, the boot script is valid | ||
| 34 | `sh`, and the Terraform is formatted. | ||