Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

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.

Code

394 commit(s) on main

Default the run verbs to origin Keenan Nemetz · 16m ago 2e6aa96e
source preview history blame raw 5.1 KiB

Vole on Hetzner Cloud

One server, configured on its first boot by a file you paste into the console. No API token, nothing to install locally: a rendered file, a server, a firewall, and one DNS record.

What you need

  • A Hetzner Cloud account and a project.
  • A DNS name, such as forge.example.com.
  • Your SSH public key.
  • The URL of a Vole .deb for amd64 — or arm64 on a CAX server type — from Vole’s releases.

Render the first-boot file

From a clone of the Vole repository, on your own computer:

cd deploy/cloud-init

HOSTNAME=forge.example.com \
ADMIN_ACCOUNT=admin \
ADMIN_EMAIL=you@example.com \
ADMIN_SSH_KEY="$(cat ~/.ssh/id_ed25519.pub)" \
VOLE_PACKAGE_URL=https://rodent.software/vole/releases/v0.2.0/artifacts/vole_0.2.0-1_amd64.deb \
  ./render.sh > user-data.yaml

Open user-data.yaml before you paste it. It is the whole setup, and it is the last chance to notice a wrong account name: names are permanent.

Create the server

In the Hetzner console, Add Server:

Field What to choose
Location wherever your team is
Image Ubuntu 24.04 (Debian 13 works too)
Type CX22 — 2 vCPU, 4 GB, 40 GB. Raise it if you expect big pushes or LFS
Networking public IPv4
SSH key yours, the same one you put in the file
Backups on. It is a snapshot, not a backup of the instance — see Backups
Cloud config paste the contents of user-data.yaml

Before or after creating it, add a Firewall in the same project and apply it to the server. Hetzner leaves a new server open if you do not:

Direction Protocol Port Source
in tcp 22 your team’s addresses, for shell access
in tcp 2222 your team’s addresses. This is Git over SSH, the write transport
in tcp 80 anywhere, for the certificate challenge
in tcp 443 anywhere
out any any anywhere, so the server can fetch its package and certificate

Restricting 2222 to your team is the cheapest way to keep the write side private. If you leave it open, Vole still authenticates every connection by key.

Point the name at it

Create an A record for forge.example.com pointing at the server’s IPv4 address. Vole cannot obtain a certificate for a name that does not resolve to it yet, and it retries, so a record created a few minutes after the server is fine.

Check it works

Open https://forge.example.com. The first request may take a few seconds while the certificate is issued; if it fails, wait a minute and reload.

Issue a passkey for the admin account from your laptop:

vole admin --remote ssh://git@forge.example.com:2222 account invite admin

Then create a repository, and clone it:

vole admin --remote ssh://git@forge.example.com:2222 repo create demo --owner admin
vole admin --remote ssh://git@forge.example.com:2222 acl set-default-role demo read
git clone ssh://git@forge.example.com:2222/demo.git

Adding a CI runner

Create a second server the same way, but give it the runner’s file:

./render.sh runner > runner-user-data.yaml    # FORGE_HOST=forge.example.com and VOLE_PACKAGE_URL

It needs no inbound ports except 22. It needs one more step per repository before it takes work; see CI runners.

The settings worth changing

The values you pass to render.sh. Everything else has a working default.

Variable Default What it does
HOSTNAME required The name the instance answers on. It becomes public_url, and passkeys bind to it
ADMIN_ACCOUNT required The first account, made an instance admin. Permanent
ADMIN_SSH_KEY required That account’s public key
VOLE_PACKAGE_URL required The .deb for the machine’s architecture
ADMIN_EMAIL empty Contact address for the certificate authority
INSTANCE_NAME Vole What the landing page calls this forge
TLS_MODE acme proxy leaves TLS to a proxy you run, and serves plain HTTP on loopback

If something is not right

  • The browser shows a certificate warning. DNS is not answering with the server’s address yet, or ports 80 and 443 are blocked by the firewall. Check dig +short forge.example.com, then journalctl -u vole | grep -i acme.
  • The server is up but the forge is not. First-boot output is in /var/log/vole-first-boot.log; the service log is journalctl -u vole. The usual cause is a package URL that 404s or is for the other architecture.
  • Nothing listens on 2222. The firewall is not applied to the server, or its source addresses do not include where you are pushing from.
  • Pushing is refused. vole whoami --remote ssh://git@forge.example.com:2222 says which account your key is; if it is not the one you expected, the key was not the one in user-data.yaml.

Next