Upgrading a Nebula network to IPv6 overlay addresses
Nebula v1.10 adds support for IPv6-addressed Nebula hosts. To support the feature, Nebula has upgraded to a v2 certificate format. While v1 certificates support only a single IPv4 address for a given host, the v2 format allows multiple IPv4 and/or IPv6 addresses. In this guide we will describe how to upgrade a network to the v2 certificate format with IPv6 support using a dual-CA migration strategy.
The dual-CA approach allows for a smooth transition by running both v1 and v2 certificates simultaneously during the migration, signed by separate certificate authorities. This provides a clear upgrade path with easy rollback capability.
The basic steps are:
Upgrade all hosts to Nebula v1.10+
First, update every host in your network to Nebula v1.10 or later with support for v2 certificates. This ensures all hosts can handle v2 certificates when they encounter them.
- https://github.com/slackhq/nebula/releases
- https://hub.docker.com/r/nebulaoss/nebula
- https://github.com/NebulaOSS/nebula-nightly/releases
- https://hub.docker.com/r/nebulaoss/nebula-nightly
All hosts must be upgraded to v1.10+ before proceeding. Older versions cannot validate v2 certificates.
Create a v2 Certificate Authority
Create a new v2 Certificate Authority that will coexist with your existing v1 CA during the migration. Creating a new CA with Nebula v1.10 will create a v2 CA by default.
❯ nebula-cert ca -name "My Nebula CA v2" -encrypt -version 2
Enter passphrase:
Using nebula-cert print we can verify this is a v2 certificate authority:
❯ nebula-cert print -path ./ca.crt
{
"curve": "CURVE25519",
"details": {
"groups": null,
"isCa": true,
"issuer": "",
"name": "My Nebula CA v2",
"networks": null,
"notAfter": "2026-12-09T12:34:35-06:00",
"notBefore": "2025-12-09T12:34:35-06:00",
"unsafeNetworks": null
},
"fingerprint": "74303f85545a26409fc73a3da0969858fc6262111b1476705083f519779e4a0c",
"publicKey": "e5d51f98a4056fd615ea145e3fdc79068cabb5553cac75673dd19afc83fc69b1",
"signature": "05fb865cee10cec3ff0e832a7e289e3aac9f22b14e640b9bdc1ecb3e85aa591ee3447fae556b7a090618f092f17af91feb666d802cbe0abbdb12f65c518ba106",
"version": 2
}
Add the v2 CA to all hosts
Append the new v2 CA certificate to the pki.ca trust bundle in
the config of every Nebula host. This allows hosts to trust certificates signed by both the old v1 CA and the new v2 CA.
pki:
ca: |
-----BEGIN NEBULA CERTIFICATE-----
[your existing v1 CA certificate content]
-----END NEBULA CERTIFICATE-----
-----BEGIN NEBULA CERTIFICATE-----
[your new v2 CA certificate content]
-----END NEBULA CERTIFICATE-----
After updating the trust bundle, reload Nebula on all hosts. At this point, hosts can validate certificates from either CA, but are still using their v1 certificates.
Gradually migrate hosts to v2 certificates
Now you can begin migrating hosts to v2 certificates one by one or in small groups. This gradual approach minimizes risk and allows for easy rollback if issues arise.
Create v2 certificates with IPv6 addresses
For each host you want to migrate, create a v2 certificate using the new CA. A v2 CA creates v2 certificates by default. This is the perfect time to add IPv6 addresses to your certificates.
Option 1: Add IPv6 while keeping IPv4 (dual-stack):
❯ nebula-cert sign -ca-crt ca.crt -ca-key ca.key -name "host-1" -networks "192.168.1.1/24,fdc8:d0db:a315:cb00::1/64"
Enter passphrase:
Option 2: Keep IPv4 only for now:
❯ nebula-cert sign -ca-crt ca.crt -ca-key ca.key -name "host-1" -networks "192.168.1.1/24"
Enter passphrase:
Verify the certificate is v2:
❯ nebula-cert print -path host-1.crt
{
"curve": "CURVE25519",
"details": {
"groups": null,
"isCa": false,
"issuer": "74303f85545a26409fc73a3da0969858fc6262111b1476705083f519779e4a0c",
"name": "host-1",
"networks": [
"192.168.1.1/24",
"fdc8:d0db:a315:cb00::1/64"
],
"notAfter": "2026-12-09T12:34:34-06:00",
"notBefore": "2025-12-09T12:35:42-06:00",
"unsafeNetworks": null
},
"fingerprint": "1376f30ea6ec555bde413be57eb3a3fad58ff7f6e31a87890e24a4a65b22c688",
"publicKey": "7212bb5a0fe8d4e353a74110d0460c8b67fde63b1ad511b33abf6e3d78117c2b",
"signature": "e7776ca62cced9bf0a9ee78e1df9ef92c60bdc1fad7cceaba946c468e6dde53265693a23d531cfff06fb41e8ebab4cdd39089c3d4a0d7aa2ba5d3f6289f2c202",
"version": 2
}
Deploy v2 certificates to hosts
Update each host with its new v2 certificate. Update the
pki.cert and
pki.key fields with the new v2 certificate and key.
pki:
ca: |
# Both CAs remain in the trust bundle
-----BEGIN NEBULA CERTIFICATE-----
[v1 CA certificate]
-----END NEBULA CERTIFICATE-----
-----BEGIN NEBULA CERTIFICATE-----
[v2 CA certificate]
-----END NEBULA CERTIFICATE-----
cert: |
-----BEGIN NEBULA CERTIFICATE-----
[new v2 certificate content]
-----END NEBULA CERTIFICATE-----
key: |
-----BEGIN NEBULA ED25519 PRIVATE KEY-----
[new v2 private key content]
-----END NEBULA ED25519 PRIVATE KEY-----
initiating_version: 2
After updating, restart Nebula. The host will now use its v2 certificate for all connections.
Update configuration for IPv6 addresses
If you added IPv6 addresses to your certificates, you'll need to update any configuration that references Nebula overlay IP addresses.
Static host map for lighthouses:
# Dual-stack configuration (both IPv4 and IPv6 overlay addresses)
static_host_map:
'192.168.1.2': ['lighthouse.example.com:4242']
'fdc8:d0db:a315:cb00::2': ['lighthouse.example.com:4242']
Unsafe routes that point to Nebula IPs:
tun:
unsafe_routes:
# Update to include IPv6 addresses for route destinations
- route: '10.0.0.0/24'
via: '192.168.1.5' # IPv4 via address
- route: '10.0.0.0/24'
via: 'fdc8:d0db:a315:cb00::5' # IPv6 via address (if dual-stack)
Relay configurations if using relays:
relay:
relays:
- '192.168.1.3' # IPv4 relay
- 'fdc8:d0db:a315:cb00::3' # IPv6 relay
Firewall rules using CIDR blocks:
firewall:
inbound:
# Allow SSH from specific IPv4 subnet
- port: 22
proto: tcp
cidr: '192.168.1.0/24'
# Allow SSH from specific IPv6 subnet
- port: 22
proto: tcp
cidr: 'fdc8:d0db:a315:cb00::/64'
lighthouse:
hosts:
- '192.168.1.2' # IPv4 lighthouse
- 'fdc8:d0db:a315:cb00::2' # IPv6 lighthouse
Anywhere your configuration references a Nebula overlay IP address should be updated to include the new IPv6 addresses when using dual-stack, or replaced entirely when moving to IPv6-only.
Roll this change out gradually:
- Start with non-critical hosts to verify the process
- Migrate your lighthouses next
- Then migrate the rest of your hosts in batches
- Verify connectivity between upgraded and non-upgraded hosts at each step
Since all hosts trust both CAs, v1 and v2 hosts can communicate during the migration period.
Verify v2 certificates are in use
After updating a host, you can verify it's using v2 certificates via the print-tunnel command from the
debug SSH server:
alex@nebula > print-tunnel 192.168.1.2
{
"vpnAddrs": ["192.168.1.2", "fdc8:d0db:a315:cb00::2"],
"localIndex": 2138029252,
"remoteIndex": 2098516474,
"remoteAddrs": ["100.0.0.151:4242"],
"cert": {
"curve": "CURVE25519",
"details": {
"groups": null,
"isCa": false,
"issuer": "74303f85545a26409fc73a3da0969858fc6262111b1476705083f519779e4a0c",
"name": "lighthouse",
"networks": ["192.168.1.2/24", "fdc8:d0db:a315:cb00::2/64"],
"notAfter": "2026-12-09T12:34:34-06:00",
"notBefore": "2025-12-09T12:39:44-06:00",
"unsafeNetworks": null
},
"fingerprint": "2fbf4b456d6759b42a3479676149ee438e6888e3a405aa48ea14b45d04222972",
"publicKey": "63a0ec7427540c0b3996254f2b7d0f90afbc6a1a94befb3d36c0b66db1847811",
"signature": "e0be1d62ac8652f4682e371e51723d71b97128e4f687f7e2c2366c37a0df7471f2aaef21644dc8a6cc524c2a857cf6e288d156ecb34a109d660adb8c5bdca008",
"version": 2
},
"messageCounter": 4,
"currentRemote": "100.0.0.151:4242",
"currentRelaysToMe": [],
"currentRelaysThroughMe": []
}
You can also check the logs for the certVersion field in handshakes:
time="2025-12-09T22:23:33Z" level=info msg="Handshake message received" certName=host-1 certVersion=2 fingerprint=1376f30ea6ec555bde413be57eb3a3fad58ff7f6e31a87890e24a4a65b22c688 from="192.168.65.1:16583" handshake="map[stage:1 style:ix_psk0]" initiatorIndex=2138029252 issuer=74303f85545a26409fc73a3da0969858fc6262111b1476705083f519779e4a0c remoteIndex=0 responderIndex=0 vpnAddrs="[192.168.1.1 fdc8:d0db:a315:cb00::1]"
Optional: Transition to IPv6-only
Once all hosts are on v2 certificates and have IPv6 addresses, you can optionally transition to an IPv6-only network.
Remove IPv4 dependencies from configuration
First, update all configuration to rely only on IPv6 addresses while hosts still have both IPv4 and IPv6 addresses. This ensures connectivity won't break when IPv4 is removed.
Update static_host_map to use only IPv6:
static_host_map:
'fdc8:d0db:a315:cb00::2': ['lighthouse.example.com:4242']
Remove IPv4 entries from lighthouse.hosts, tun.unsafe_routes, relay.relays, firewall.inbound,
firewall.outbound and any other configuration that references Nebula overlay IPs. Verify the network is stable with
these configuration changes before proceeding.
Remove IPv4 addresses from certificates
Once all configuration has been updated to use IPv6 addresses exclusively, reissue certificates with only IPv6 addresses:
❯ nebula-cert sign -ca-crt ca.crt -ca-key ca.key -name "host-1" -networks "fdc8:d0db:a315:cb00::1/64"
Enter passphrase:
Deploy these certificate changes gradually and verify connectivity at each step, just as with the v2 migration.
Clean up
Once all hosts have been migrated to v2 certificates and the network is stable:
- Remove the v1 CA certificate from the
pki.catrust bundle on all hosts - Reload Nebula on all hosts
- Remove any backup files containing v1 certificates and keys
Your network is now fully migrated to v2 certificates with IPv6 support!
Rollback procedure
If issues arise during migration, you can rollback by:
- If only some hosts are upgraded: Simply restart the affected hosts with their original v1 certificates
- If all hosts are upgraded but experiencing issues:
- Keep both CAs in the trust bundle
- Revert the
pki.certandpki.keyfields to the v1 certificates - Remove or set
pki.initiating_versionto 1 - Restart Nebula