vole
Clone
Read only, no credentials:
https://rodent.software/vole.git
Write over SSH with a registered key:
git clone ssh://git@rodent.software:2222/vole.git
A free and open-source forge that lives in your Git repo.
|
b8e7a567
Keenan Nemetz
3d ago
|
1 | # Vole on Hetzner Cloud |
| 2 | ||
|
942c93cd
Keenan Nemetz
3d ago
|
3 | One server, configured on its first boot by a file you paste into the console. No |
| 4 | API token, nothing to install locally: a rendered file, a server, a firewall, and | |
| 5 | one DNS record. | |
|
b8e7a567
Keenan Nemetz
3d ago
|
6 | |
| 7 | ## What you need | |
| 8 | ||
|
942c93cd
Keenan Nemetz
3d ago
|
9 | - A Hetzner Cloud account and a project. |
| 10 | - A DNS name, such as `forge.example.com`. | |
| 11 | - Your SSH public key. | |
|
c1edfd3c
Keenan Nemetz
3d ago
|
12 | - The URL of a Vole `.deb` for `amd64` — or `arm64` on a CAX server type — from |
|
b7396a11
Keenan Nemetz
6h ago
|
13 | [Vole's releases](https://rodent.software/vole/releases). |
|
b8e7a567
Keenan Nemetz
3d ago
|
14 | |
|
942c93cd
Keenan Nemetz
3d ago
|
15 | ## Render the first-boot file |
|
b8e7a567
Keenan Nemetz
3d ago
|
16 | |
|
942c93cd
Keenan Nemetz
3d ago
|
17 | From a clone of the Vole repository, on your own computer: |
|
b8e7a567
Keenan Nemetz
3d ago
|
18 | |
| 19 | ```sh | |
|
942c93cd
Keenan Nemetz
3d ago
|
20 | cd deploy/cloud-init |
| 21 | ||
| 22 | HOSTNAME=forge.example.com \ | |
| 23 | ADMIN_ACCOUNT=admin \ | |
| 24 | ADMIN_EMAIL=you@example.com \ | |
| 25 | ADMIN_SSH_KEY="$(cat ~/.ssh/id_ed25519.pub)" \ | |
|
b7396a11
Keenan Nemetz
6h ago
|
26 | VOLE_PACKAGE_URL=https://rodent.software/vole/releases/v0.2.0/artifacts/vole_0.2.0-1_amd64.deb \ |
|
942c93cd
Keenan Nemetz
3d ago
|
27 | ./render.sh > user-data.yaml |
|
b8e7a567
Keenan Nemetz
3d ago
|
28 | ``` |
| 29 | ||
|
942c93cd
Keenan Nemetz
3d ago
|
30 | Open `user-data.yaml` before you paste it. It is the whole setup, and it is the |
| 31 | last chance to notice a wrong account name: names are permanent. | |
|
b8e7a567
Keenan Nemetz
3d ago
|
32 | |
|
942c93cd
Keenan Nemetz
3d ago
|
33 | ## Create the server |
|
b8e7a567
Keenan Nemetz
3d ago
|
34 | |
|
942c93cd
Keenan Nemetz
3d ago
|
35 | In the Hetzner console, **Add Server**: |
| 36 | ||
| 37 | | Field | What to choose | | |
| 38 | |---|---| | |
| 39 | | Location | wherever your team is | | |
| 40 | | Image | Ubuntu 24.04 (Debian 13 works too) | | |
| 41 | | Type | CX22 — 2 vCPU, 4 GB, 40 GB. Raise it if you expect big pushes or LFS | | |
| 42 | | Networking | public IPv4 | | |
| 43 | | SSH key | yours, the same one you put in the file | | |
| 44 | | Backups | on. It is a snapshot, not a backup of the instance — see [Backups](README.md#backups-are-still-your-job) | | |
| 45 | | **Cloud config** | paste the contents of `user-data.yaml` | | |
| 46 | ||
| 47 | Before or after creating it, add a **Firewall** in the same project and apply it to | |
| 48 | the server. Hetzner leaves a new server open if you do not: | |
| 49 | ||
| 50 | | Direction | Protocol | Port | Source | | |
| 51 | |---|---|---|---| | |
| 52 | | in | tcp | 22 | your team's addresses, for shell access | | |
| 53 | | in | tcp | 2222 | your team's addresses. This is Git over SSH, the write transport | | |
| 54 | | in | tcp | 80 | anywhere, for the certificate challenge | | |
| 55 | | in | tcp | 443 | anywhere | | |
| 56 | | out | any | any | anywhere, so the server can fetch its package and certificate | | |
| 57 | ||
| 58 | Restricting 2222 to your team is the cheapest way to keep the write side private. | |
| 59 | If you leave it open, Vole still authenticates every connection by key. | |
|
b8e7a567
Keenan Nemetz
3d ago
|
60 | |
|
942c93cd
Keenan Nemetz
3d ago
|
61 | ## Point the name at it |
| 62 | ||
| 63 | Create an `A` record for `forge.example.com` pointing at the server's IPv4 | |
| 64 | address. Vole cannot obtain a certificate for a name that does not resolve to it | |
| 65 | yet, and it retries, so a record created a few minutes after the server is fine. | |
| 66 | ||
| 67 | ## Check it works | |
| 68 | ||
| 69 | Open `https://forge.example.com`. The first request may take a few seconds while | |
| 70 | the certificate is issued; if it fails, wait a minute and reload. | |
| 71 | ||
| 72 | Issue a passkey for the admin account from your laptop: | |
|
b8e7a567
Keenan Nemetz
3d ago
|
73 | |
| 74 | ```sh | |
| 75 | vole admin --remote ssh://git@forge.example.com:2222 account invite admin | |
| 76 | ``` | |
| 77 | ||
|
942c93cd
Keenan Nemetz
3d ago
|
78 | Then create a repository, and clone it: |
| 79 | ||
| 80 | ```sh | |
| 81 | vole admin --remote ssh://git@forge.example.com:2222 repo create demo --owner admin | |
| 82 | vole admin --remote ssh://git@forge.example.com:2222 acl set-default-role demo read | |
| 83 | git clone ssh://git@forge.example.com:2222/demo.git | |
| 84 | ``` | |
| 85 | ||
| 86 | ## Adding a CI runner | |
| 87 | ||
| 88 | Create a second server the same way, but give it the runner's file: | |
| 89 | ||
| 90 | ```sh | |
| 91 | ./render.sh runner > runner-user-data.yaml # FORGE_HOST=forge.example.com and VOLE_PACKAGE_URL | |
| 92 | ``` | |
| 93 | ||
| 94 | It needs no inbound ports except 22. It needs one more step per repository before | |
| 95 | it takes work; see [CI runners](runner.md). | |
| 96 | ||
|
b8e7a567
Keenan Nemetz
3d ago
|
97 | ## The settings worth changing |
| 98 | ||
|
942c93cd
Keenan Nemetz
3d ago
|
99 | The values you pass to `render.sh`. Everything else has a working default. |
|
b8e7a567
Keenan Nemetz
3d ago
|
100 | |
|
942c93cd
Keenan Nemetz
3d ago
|
101 | | Variable | Default | What it does | |
|
b8e7a567
Keenan Nemetz
3d ago
|
102 | |---|---|---| |
|
942c93cd
Keenan Nemetz
3d ago
|
103 | | `HOSTNAME` | required | The name the instance answers on. It becomes `public_url`, and passkeys bind to it | |
| 104 | | `ADMIN_ACCOUNT` | required | The first account, made an instance admin. Permanent | | |
| 105 | | `ADMIN_SSH_KEY` | required | That account's public key | | |
| 106 | | `VOLE_PACKAGE_URL` | required | The `.deb` for the machine's architecture | | |
| 107 | | `ADMIN_EMAIL` | empty | Contact address for the certificate authority | | |
| 108 | | `INSTANCE_NAME` | `Vole` | What the landing page calls this forge | | |
| 109 | | `TLS_MODE` | `acme` | `proxy` leaves TLS to a proxy you run, and serves plain HTTP on loopback | | |
|
e21f6c5e
Keenan Nemetz
3d ago
|
110 | |
|
b8e7a567
Keenan Nemetz
3d ago
|
111 | ## If something is not right |
| 112 | ||
| 113 | - **The browser shows a certificate warning.** DNS is not answering with the | |
|
942c93cd
Keenan Nemetz
3d ago
|
114 | server's address yet, or ports 80 and 443 are blocked by the firewall. Check |
| 115 | `dig +short forge.example.com`, then `journalctl -u vole | grep -i acme`. | |
| 116 | - **The server is up but the forge is not.** First-boot output is in | |
| 117 | `/var/log/vole-first-boot.log`; the service log is `journalctl -u vole`. The | |
| 118 | usual cause is a package URL that 404s or is for the other architecture. | |
| 119 | - **Nothing listens on 2222.** The firewall is not applied to the server, or its | |
| 120 | source addresses do not include where you are pushing from. | |
| 121 | - **Pushing is refused.** `vole whoami --remote ssh://git@forge.example.com:2222` | |
| 122 | says which account your key is; if it is not the one you expected, the key was | |
| 123 | not the one in `user-data.yaml`. | |
|
b8e7a567
Keenan Nemetz
3d ago
|
124 | |
| 125 | ## Next | |
| 126 | ||
|
942c93cd
Keenan Nemetz
3d ago
|
127 | - [Deploying Vole](README.md) — what first boot does, backups, and upgrades |
|
b8e7a567
Keenan Nemetz
3d ago
|
128 | - [Packages](../packaging.md) — the `.deb`, the unit file, and upgrades on the machine |
| 129 | - [Accounts and access](../accounts-and-access.md) — the first accounts, roles, and passkeys |