Server orchestration for bare metal and cloud. Define your server, packages, services, and deploy steps in a single harbor.yaml, then run harbor up — Harbor creates the server, provisions it over SSH, wires up DNS, and deploys your code. For multi-server setups, a 4-line fleet.yaml composes role directories into named fleets that spin up concurrently. Written in Rust, single static binary, no agents on the server.
- One-command lifecycle —
harbor upcreates, provisions, and deploys.harbor downdestroys the server and cleans DNS. No intermediate steps, no state to manage. - Declarative provisioning — packages, Docker, Go, Rust, Caddy, systemd services, firewall rules, SSH hardening, file deployment, container services — all from YAML. Harbor generates and executes the setup script over SSH, no agent required.
- Fleet orchestration —
harbor fleet up productioncreates an entire fleet from role directories, each with its ownharbor.yaml. Concurrent by default, idempotent, deterministic server naming.
harbor up # create server, provision, deploy
harbor deploy # git pull, rebuild, restart
harbor fleet up staging # spin up a named fleet
harbor down # tear it all downcargo install --path crates/harbor-rs1. Set up credentials
harbor init # scaffolds ~/.harbor/config.yaml
nano ~/.harbor/config.yaml # add your Hetzner token2. Add a harbor.yaml to your project
name: myapp
server:
name: myapp-prod
type: cax11
location: nbg1
ssh_key: my-key
hostname: myapp # optional: creates myapp.i.example.com
setup:
packages: [ca-certificates, curl, git]
components:
docker:
enabled: true
services:
- name: myapp
enabled: true
exec_start: /usr/local/bin/myapp
restart: always
deploy:
repo: github.com/you/myapp
steps:
- make build
- sudo systemctl restart myapp3. Ship it
harbor up # server created, provisioned, deployed
harbor deploy # subsequent deploys — pull, build, restart
harbor down # done — server and DNS removedFor multi-server setups, organize each service as a directory with its own harbor.yaml and dist/ config files:
cloud/
├── fleet.yaml
├── clickhouse/
│ ├── harbor.yaml
│ └── dist/
├── collectors/
│ ├── harbor.yaml
│ └── dist/
└── platform/
├── harbor.yaml
└── dist/
The fleet.yaml composes roles and counts:
roles:
clickhouse: 1
collectors: 3
platform: 2The fleet name is mandatory — it generates deterministic server names and identifies the fleet instance:
harbor fleet up staging # creates clickhouse-staging-1, collectors-staging-{1,2,3}, platform-staging-{1,2}
harbor fleet status staging # table: name, role, status, IP, type, location
harbor fleet down staging # destroys all staging servers, cleans DNSSame config, different fleets. harbor fleet up production creates a separate set of servers from the same role directories. Each role's harbor.yaml defines its server type, location, packages, services, and deploy steps — fleet just orchestrates.
Harbor uses two config files: user config for credentials (once per machine) and project config for what to build and deploy (per repo).
Created by harbor init. Stores API tokens — never committed to a repo.
hetzner:
token: "..."
cloudflare: # optional — only needed for DNS
api_token: "..."
zone_id: "..."
dns:
base_domain: ".i.example.com"
github:
token: "..." # optional — only needed for private reposThe Hetzner token resolves through a fallback chain: user config, then HCLOUD_TOKEN env var.
Lives in your repo root. Discovered automatically by harbor up/down/deploy/status/ssh/logs by walking up from the current directory. See the quick start example for the structure.
| Command | What it does |
|---|---|
harbor up |
Create server, provision, deploy |
harbor down |
Destroy server, clean DNS |
harbor deploy |
Pull, rebuild, restart services |
harbor rollback [sha] |
Roll back to previous deploy or specific SHA |
harbor status |
Server state, last deploy, service health, disk |
harbor ssh |
Shell into the server |
harbor exec -- <cmd> |
Run a one-off command on the server |
harbor logs [service] |
Stream journald logs |
harbor fleet up <name> |
Create and provision a named fleet |
harbor fleet down <name> |
Destroy a named fleet |
harbor fleet status <name> |
Show fleet server status |
MIT