Static Go binary for renewing Nebula VPN certificates via the nebula-platform API. Replaces the shell-based renewal script with a single binary — zero runtime dependencies, atomic file writes, optional X25519 key rotation with DH proof-of-possession.
Download from Releases:
curl -sL https://github.com/Project-Highway/nebula-renew-binary/releases/latest/download/nebula-renew-linux-amd64 \
-o /usr/local/bin/nebula-renew
chmod +x /usr/local/bin/nebula-renewOr build from source:
make buildnebula-renew --platform-url https://platform.example.comAll flags can also be set via environment variables.
| Flag | Env | Default | Description |
|---|---|---|---|
--platform-url |
PLATFORM_URL |
(required) | Platform API base URL |
--cert-path |
CERT_PATH |
/etc/nebula/host.crt |
Host certificate path |
--key-path |
KEY_PATH |
/etc/nebula/host.key |
Host private key path |
--ca-path |
CA_PATH |
/etc/nebula/ca.crt |
CA certificate path |
--fingerprint-path |
FINGERPRINT_PATH |
/etc/nebula/fingerprint |
Fingerprint file (regenerated after renewal so nebula-guard stays authenticated) |
--nebula-cert-bin |
NEBULA_CERT_BIN |
/usr/local/bin/nebula-cert |
nebula-cert binary (used to extract fingerprint from renewed cert) |
--service-name |
SERVICE_NAME |
nebula |
Systemd service name |
--post-swap-action |
POST_SWAP_ACTION |
restart |
Service action after cert swap: restart or reload (reload falls back to restart on failure) |
--no-restart |
— | false |
Skip service restart after renewal |
--rotate-key |
— | false |
Generate new X25519 keypair |
--renewal-pub |
RENEWAL_PUBLIC_KEY |
— | Platform renewal public key (base64) |
--timeout |
— | 30s |
HTTP request timeout |
--log-format |
LOG_FORMAT |
json |
Log output format (json or text) |
--version |
— | — | Print version and exit |
nebula-renew \
--platform-url https://platform.example.com \
--cert-path /etc/nebula/host.crt \
--ca-path /etc/nebula/ca.crtRotate the device's X25519 keypair with DH proof-of-possession:
nebula-renew \
--platform-url https://platform.example.com \
--rotate-key \
--renewal-pub "base64-encoded-platform-public-key"On hosts running nebula >= 1.7 (rehandshakes existing tunnels on cert reload), use reload to activate the new cert without dropping tunnels:
nebula-renew \
--platform-url https://platform.example.com \
--post-swap-action reloadreload delivers a raw SIGHUP to the nebula process — systemctl kill -s HUP <service> on systemd hosts, pkill -HUP -x <name> otherwise. It does not run systemctl reload/restart. This is required on lighthouses whose nebula-renew unit is ordered Before=nebula.service: a systemctl reload/restart call enqueues a systemd job for nebula.service, but that job cannot run until the Before= oneshot exits, while the oneshot blocks inside the synchronous systemctl call waiting for the job — the job queue deadlocks (reload times out, restart fallback gets SIGKILLed, ~90s nebula blip, unit ends failed). A signal creates no job, so there is no deadlock, no ExecReload= requirement, and nebula hot-reloads its cert with zero tunnel blip.
If the signal cannot be delivered (systemctl errors), nebula-renew logs a warning and falls back to a hard restart so the new cert is never left inactive.
# /etc/systemd/system/nebula-renew.timer
[Unit]
Description=Nebula certificate renewal
[Timer]
OnCalendar=daily
RandomizedDelaySec=3600
Persistent=true
[Install]
WantedBy=timers.target# /etc/systemd/system/nebula-renew.service
[Unit]
Description=Renew Nebula certificate
[Service]
Type=oneshot
ExecStart=/usr/local/bin/nebula-renew --platform-url https://platform.example.com
Environment=LOG_FORMAT=jsonmake test # run tests with race detector
make lint # golangci-lint
make build # build binary
make clean # remove artifactscmd/nebula-renew/ CLI entry point
internal/
config/ Flag parsing + env vars
client/ HTTP client for POST /api/renew
crypto/ X25519 DH proof, Nebula PEM helpers
renew/ Orchestrator: read → renew → atomic write → restart