Skip to content
Nebula logoNebula logoNebula Docs

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:

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.

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.

Terminal window
❯ 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:

Terminal window
❯ 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
}

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

Section titled “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

Section titled “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.

v2 certificate names must be between 1 and 253 bytes long.

Option 1: Add IPv6 while keeping IPv4 (dual-stack):

Terminal window
❯ 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:

Terminal window
❯ 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:

Terminal window
❯ 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
}

Update each host with its new v2 certificate. Update the pki.cert and pki.key fields with the new v2 certificate and key. With a network of all v1.10 Nebula hosts, you can run with a mix of v1 and v2 certificates, allowing for a smooth transition as you update the cert version on each host in the network gradually.

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.

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 configurations:

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.

After updating a host, you can verify the certificate version a peer is using with nebula ctl identity, which reports it as cert version:

Terminal window
❯ sudo nebula ctl identity 192.168.1.2
name: lighthouse
vpn addrs: 192.168.1.2, fdc8:d0db:a315:cb00::2
...
cert version: 2

The print-tunnel command, from nebula ctl or the debug SSH server, shows the whole certificate:

Terminal window
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:

Terminal window
time=2025-12-09T22:23:33.402Z level=INFO msg="Handshake message received" vpnAddrs="[192.168.1.1 fdc8:d0db:a315:cb00::1]" from=192.168.65.1:16583 certName=host-1 certVersion=2 fingerprint=1376f30ea6ec555bde413be57eb3a3fad58ff7f6e31a87890e24a4a65b22c688 issuer=74303f85545a26409fc73a3da0969858fc6262111b1476705083f519779e4a0c initiatorIndex=2138029252 responderIndex=0 handshake="map[stage:1 style:ix_psk0]"

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

Section titled “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.

Once all configuration has been updated to use IPv6 addresses exclusively, reissue certificates with only IPv6 addresses:

Terminal window
❯ 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.

Once all hosts have been migrated to v2 certificates and the network is stable:

  1. Remove the v1 CA certificate from the pki.ca trust bundle on all hosts
  2. Reload Nebula on all hosts
  3. Remove any backup files containing v1 certificates and keys

Your network is now fully migrated to v2 certificates with IPv6 support!

If issues arise during migration, you can rollback by:

  1. If only some hosts are upgraded: Simply restart the affected hosts with their original v1 certificates
  2. If all hosts are upgraded but experiencing issues:
    • Keep both CAs in the trust bundle
    • Revert the pki.cert and pki.key fields to the v1 certificates
    • Remove or set pki.initiating_version to 1
    • Restart Nebula