Skip to content

Provision Hetzner VyOS Edge (HyOps Blueprint)

Purpose: Build or discover the canonical VyOS image record, seed the Hetzner image, and provision the default routed edge pair.
Owner: Network/platform engineering
Trigger: New Hetzner edge bring-up, image refresh, or routed edge rebuild
Impact: Creates or refreshes the public VyOS edge pair that fronts Site-A and feeds the WAN control plane
Severity: P2
Pre-reqs: Hetzner init is ready for the target env, the canonical image record path is reachable, and the operator provides a valid SSH public key.
Rollback strategy: Destroy the edge foundation state and reseed/reapply with corrected image or key inputs.

Use the shipped blueprint ref networking/hetzner-vyos-edge@v1 to build/publish (or reuse) a canonical VyOS record, seed or discover the Hetzner image, and provision the default routed Hetzner edge pair.

This is the target-state replacement for the Linux strongSwan/FRR edge path. The shared Hetzner control host remains a separate Linux service host.

Current recommended image path:

  1. publish a versioned public qcow2 for Proxmox consumption
  2. publish a versioned public raw.xz for Hetzner consumption
  3. seed the Hetzner image from that direct raw.xz
  4. let org/hetzner/vyos-edge-foundation consume image_state_ref

Important first-boot behavior:

  • Hetzner VyOS custom images now perform one intentional first-boot reboot after cloud-init writes the final config.boot.
  • Treat the first boot as image customization and the second boot as the point where routed public/private networking becomes active.
  • Do not treat a short initial SSH gap as image failure unless the node is still unreachable after that reboot window.
  • Hetzner Cloud Networks are routed. The edge private NIC is therefore configured as private_ip/32, with an explicit route to private_network_cidr via the standard network gateway (cidrhost(private_network_cidr, 1)), not as an on-link /24.

Inputs

The blueprint is state-first where possible:

  • core/shared/vyos-image-build publishes the canonical VyOS record URL contract
  • core/hetzner/vyos-image-seed publishes the custom Hetzner image reference
  • org/hetzner/vyos-edge-foundation consumes it by image_state_ref

Operator-supplied values still required:

  • object repo state or explicit record URL for the build step
  • SSH public key

Initialize an env-scoped overlay

hyops blueprint init --env dev \
  --ref networking/hetzner-vyos-edge@v1 \
  --dest-name hetzner-vyos-edge.yml

Edit:

  • ~/.hybridops/envs/dev/config/blueprints/hetzner-vyos-edge.yml
  • If you already have a seeded Hetzner custom image, set image_ref.
  • The blueprint now defaults to core/shared/vyos-image-build#vyos_default_build.
  • If vyos_record_build.inputs.record_url is set, HyOps uses it directly.
  • If vyos_record_build.inputs.record_url is empty, HyOps runs build/publish and uses repo_state_ref to discover bucket backend.
  • vyos_image consumes the resulting shared record state by default.
  • For the clean Hetzner path, prefer setting image_source_url to a direct public raw.xz record.
  • The qcow2 auto-wrap path remains supported only when the execution host has qemu-img and can expose the wrapped record through a public base URL.
  • If your only upstream source is an installer ISO, leave image_source_url empty and provide a custom seed_command that performs the ISO-to-image workflow before snapshot creation.
  • Leave seed_tool: hcloud-upload-image unless you provide a custom seed_command.
  • HyOps fails fast when image_source_url is invalid/unreachable, with guidance to run core/shared/vyos-image-build.
  • A single operator-managed qcow2 URL can still serve both Proxmox and Hetzner, but only when the wrapper preconditions are satisfied. Treat direct raw.xz import as the primary Hetzner path.

If hyops blueprint init --ref networking/hetzner-vyos-edge@v1 says the blueprint is not found under ~/.hybridops/core/app/blueprints/..., your installed HyOps payload is older than the current source tree. Refresh the install, or use the repo-local CLI until the installed payload is updated.

Validate

hyops blueprint preflight --env dev \
  --file "$HOME/.hybridops/envs/dev/config/blueprints/hetzner-vyos-edge.yml"

Deploy

hyops blueprint deploy --env dev \
  --file "$HOME/.hybridops/envs/dev/config/blueprints/hetzner-vyos-edge.yml" \
  --execute

Verify

jq '.status,.outputs.image_ref,.outputs.image_description' \
  "$HOME/.hybridops/envs/dev/state/modules/core__hetzner__vyos-image-seed/latest.json"

jq '.status,.outputs.edge01_public_ip,.outputs.edge02_public_ip' \
  "$HOME/.hybridops/envs/dev/state/modules/org__hetzner__vyos-edge-foundation/latest.json"

EDGE_A_IP="$(jq -r '.outputs.edge01_public_ip' "$HOME/.hybridops/envs/dev/state/modules/org__hetzner__vyos-edge-foundation/latest.json")"
EDGE_B_IP="$(jq -r '.outputs.edge02_public_ip' "$HOME/.hybridops/envs/dev/state/modules/org__hetzner__vyos-edge-foundation/latest.json")"
ssh -o StrictHostKeyChecking=no "vyos@${EDGE_A_IP}" 'echo HYOPS_HETZNER_EDGE_A_OK'
ssh -o StrictHostKeyChecking=no "vyos@${EDGE_B_IP}" 'echo HYOPS_HETZNER_EDGE_B_OK'

If the edge foundation is reapplied and Hetzner assigns new public IPs, refresh org/gcp/wan-vpn-to-edge before rerunning WAN day-2. The cloud VPN peer IPs must track the current org/hetzner/vyos-edge-foundation state.