| Crates.io | gitlab_hcloud |
| lib.rs | gitlab_hcloud |
| version | 0.1.0 |
| created_at | 2026-01-21 15:09:22.790126+00 |
| updated_at | 2026-01-21 15:09:22.790126+00 |
| description | Automatic Hetzner server provisioning for GitLab CI runners |
| homepage | |
| repository | |
| max_upload_size | |
| id | 2059528 |
| size | 119,392 |
Automatic provisioning of Hetzner Cloud servers as GitLab CI runners - pay only when you need it.
flowchart TB
subgraph main [Main Loop]
Poll[Polling Loop]
Poll --> FetchProjects[GitLab: Fetch all projects]
FetchProjects --> CheckPipelines[Per project: Pending/Running pipelines?]
CheckPipelines -->|Yes + No server| LogStart[CSV: Log reason]
LogStart --> CreateServer[Hetzner: Create server]
CheckPipelines -->|No everywhere + Server exists| CheckDelete[Check delete logic]
CheckDelete -->|Conditions met| LogStop[CSV: Log usage]
LogStop --> DeleteServer[Hetzner: Delete server]
end
subgraph config [Config]
ConfigToml[config/config.toml]
RunnerToml[config/runner.toml]
end
subgraph logs [Logging]
CSV[logs/runner_usage.csv]
LogFile[logs/orchestrator.log]
end
ConfigToml --> main
RunnerToml --> CreateServer
main --> CSV
main --> LogFile
cargo build --release
On first start, config/config.example.toml is automatically created. Copy and customize it:
cp config/config.example.toml config/config.toml
# Edit config/config.toml with your API keys
Create config/runner.toml with your GitLab Runner configuration.
You can register the GitLab Runner with the following command:
docker run -it -v /var/run/docker.sock:/var/run/docker.sock -v ./config:/etc/gitlab-runner gitlab/gitlab-runner:latest register --url https://gitlab.example.com --token YOUR_TOKEN
IMPORTANT:
Under [runners.docker] there is a pull_policy setting.
Set it to:
pull_policy = ["if-not-present"]
Otherwise the runner will do too many docker image pull requests and your IP will be banned!
cargo run --release
# or
./target/release/hetzner_gitlab_runner
[gitlab]
url = "https://gitlab.example.com"
token = "glpat-xxxxxxxxxxxxxxxxxxxx" # read_api scope
[hetzner]
token = "xxxxxxxxxxxxxxxxxxxxxxxx"
server_type = "ccx23" # AMD dedicated CPU
location = "nbg1" # Nuremberg
image = "ubuntu-24.04"
ssh_key_name = "my-ssh-key"
[runner]
name = "flexi-runner"
min_lifetime_minutes = 20 # Minimum runtime
poll_interval_seconds = 30
| Feature | Debug | Release |
|---|---|---|
| Polling interval | 5s | 30s (from config) |
| Server deletion | Immediate | After min. 20min + billing-optimized |
Hetzner charges per started hour from server creation.
Example:
logs/orchestrator.log - Detailed logs (daily rotation)logs/runner_usage.csv - Server usage documentationtimestamp,event,server_id,project,pipeline_id,reason,duration_minutes
2026-01-14T10:30:00Z,START,12345678,mygroup/myproject,9876,pipeline_pending,
2026-01-14T11:15:00Z,STOP,12345678,,,all_pipelines_done,45