Skip to main content

Upgrading to IPv6 support

With newly added IPv6 support to nebula, there are a few steps that must be taken to enable it across your network.

The basic steps go:

Upgrade to nebula nightly

First, download the updated nebula version that has v2 certs and IPv6 support from nightly releases, and move all the hosts in your network to it.

Add a v2 Certificate Authority

Next, create a new CA for your network, and add it to the trust bundle of every host on the network. Creating a new CA with the nightly version of nebula will create a v2 CA by default, with support for creating and signing both v1 and v2 certificates.

❯ nebula-cert ca -name "Nebula IPv6 Tutorial CA" -encrypt
Enter passphrase:
# typed in my password and pressed enter.

Using nebula-cert print we can see that this is a v2 certificate authority, with support for IPv6 addresses.

❯ nebula-cert print -path ./ca.crt
{
"curve": "CURVE25519",
"details": {
"groups": null,
"isCa": true,
"issuer": "",
"name": "Nebula IPv6 Tutorial CA",
"networks": null,
"notAfter": "2026-03-11T12:26:19-05:00",
"notBefore": "2025-03-11T12:26:19-05:00",
"unsafeNetworks": null
},
"fingerprint": "a95ed86f7754fc5b0fcaf38473504403748d6dc422b16bc3e29fcae32af9a73c",
"publicKey": "4f1200baedc57f39adfc71e1b5409a3a7dc60fab4e1a2c4decaeb347a2ad4d75",
"signature": "e46d1f31e4b677fc4bbef9ebcf941261cd49e00fd4bf124e26b9fb7716d23e7588b0b6b87d276e625b30ef6fa32ced0aa46abee7b61d150907007586cd6e2203",
"version": 2
}

Copy the public key of the CA and add it to the pki.ca list in the config for every nebula host: https://nebula.defined.net/docs/config/pki/#pkica

Re-issue v1+v2 certificates for every host with the v2 CA

In order to move to a network where every host has ipv4 and ipv6, or every host has ipv6 only, it's recommended to start by re-issuing all hosts certificates with both v1 and v2 certificates for compatibility. Hosts will continue handshaking via the v1 cert while the network is being upgraded.

You can create a new v1+v2 cert like this:

❯ nebula-cert sign -name "nebula" -networks "192.168.1.1/24"
Enter passphrase:
# Entered my passphrase

By default, nebula-cert will create a v1 and v2 version of the certificate when creating and signing a certificate. This allows you to move from v1 to v2 seamlessly. v1 does not support IPv6 though, so we'll move to only v2 soon.

Using nebula-cert show we can see that the certificate has both cert format versions:

❯ nebula-cert print -path nebula.crt
{
"details": {
"curve": "CURVE25519",
"groups": [],
"isCa": false,
"issuer": "a95ed86f7754fc5b0fcaf38473504403748d6dc422b16bc3e29fcae32af9a73c",
"name": "nebula",
"networks": [
"192.168.1.1/24"
],
"notAfter": "2026-03-11T12:26:18-05:00",
"notBefore": "2025-03-17T14:27:25-05:00",
"publicKey": "ba79878d86c88b8d679e2db2382a31f32177d5a27727a167ee94f8ef1e12793b",
"unsafeNetworks": []
},
"fingerprint": "c2292774eaadf83a0a25a051cb0c66a22df56733b8683104b317978547e99cbc",
"signature": "064c25cd0d2fe4db2af84c2cd9396053f200e79736c13fcf8abfc2458cb9f40be0a9563c5d05b0192b891ab48aec3a9d82a09527fda8632e6286546170e2700b",
"version": 1
}
{
"curve": "CURVE25519",
"details": {
"groups": null,
"isCa": false,
"issuer": "a95ed86f7754fc5b0fcaf38473504403748d6dc422b16bc3e29fcae32af9a73c",
"name": "nebula",
"networks": [
"192.168.1.1/24"
],
"notAfter": "2026-03-11T12:26:18-05:00",
"notBefore": "2025-03-17T14:27:25-05:00",
"unsafeNetworks": null
},
"fingerprint": "beef1fd9ea8a78164c53a83f5b3fb362dc1afa4c90ffb5db78c794be64286eca",
"publicKey": "ba79878d86c88b8d679e2db2382a31f32177d5a27727a167ee94f8ef1e12793b",
"signature": "8ae8314e87a2a8c6c85eb567b1db74f706dca74b9d748ee32f1c7b2ca6ad84946242bcf38c02b2a83a5109f07f4874bf84a331278ad21400c781c874ef392304",
"version": 2
}

Move all hosts to only contain v2 certificates

Removing the v1 certificates allows non-backwards compatible features to be enabled in your nebula network, like IPv6 and multiple IPv4 and IPv6 network subnets contained within a network overlay.

The first step is to keep v1 certs on your hosts as backup, but to initiate tunnels with their v2 certs by default. Turning this setting on in steps allows you to detect issues with your config and reduce downtime in the case of a misconfig.

What follows is a suggested order of operations, but the general goal is to slowly roll out these changes, starting with the hosts that you don't expect to be initiating tunnels. We leave the lighthouses for last, since they're the coordinating nodes, and hosts still on v1 only will not be able to communicate with the network with their lighthouse is on v2 only. For a small network, it may be fine to simply change everything over in one go!

After each step, you may validate that your changes have taken effect by using the print-tunnel command within the debug ssh server.

For example, when debugging nebula(192.168.1.1)'s tunnel to lighthouse1(192.168.1.2) where both have both v1 and v2 certs and pki.default_version is set to 1 on both hosts, we can see that the certificate used in the tunnel is version 1.

steve@nebula > print-tunnel 192.168.1.2
{
"vpnAddrs": [
"192.168.1.2"
],
"localIndex": 2965094606,
"remoteIndex": 1285130098,
"remoteAddrs": [
"172.17.0.3:4242"
],
"cert": {
"details": {
"curve": "CURVE25519",
"groups": [],
"isCa": false,
"issuer": "a95ed86f7754fc5b0fcaf38473504403748d6dc422b16bc3e29fcae32af9a73c",
"name": "lighthouse1",
"networks": [
"192.168.1.2/24"
],
"notAfter": "2026-03-11T17:26:18Z",
"notBefore": "2025-03-18T17:14:43Z",
"publicKey": "c455bc023b1b3918538edf5f230169df12603703639db158c76da747e0eccc47",
"unsafeNetworks": []
},
"fingerprint": "84cf960de2e49f7560a5c7f876857528f02ab201c906f5a094d0d3294732b655",
"signature": "6b9e98e398fb4c6a89f8e71e6a1378cecb85c500966443673a3ebe8f9d46702d0213dbd4c5028644104eeae49c06a4906058b53cd809e07dec76fcec60a4370d",
"version": 1
},
"messageCounter": 3,
"currentRemote": "172.17.0.3:4242",
"currentRelaysToMe": [],
"currentRelaysThroughMe": []
}

You may also look in the host logs for the certVersion field in handshakes, ex:

time="2025-03-27T16:50:26-05:00" level=info msg="Handshake message received" certName=lighthouse1 certVersion=1 durationNs=63460958 fingerprint=84cf960de2e49f7560a5c7f876857528f02ab201c906f5a094d0d3294732b655 handshake="map[stage:2 style:ix_psk0]" initiatorIndex=530355834 issuer=a95ed86f7754fc5b0fcaf38473504403748d6dc422b16bc3e29fcae32af9a73c remoteIndex=530355834 responderIndex=3163624101 sentCachedPackets=1 udpAddr="172.17.0.3:4242" vpnAddrs="[192.168.1.2]"

Switch all non-lighthouse relays to use v2 certificates

Switch all am_relay: true && am_lighthouse: false hosts' pki.default_version to 2 or add it if it doesn't exist yet.

Now, if a relay initiates a handshake, it will attempt to use a v2 cert first, but this is an uncommon flow.

Try ssh debugging with print-tunnel now to validate these hosts initiate their tunnels with v2 certificates.

Switch all non-lighthouse hosts to use v2 certificates

Switch all am_lighthouse: false hosts' pki.default_version to 2 or add it if it doesn't exist yet. Lighthouses will reply to v2 hosts using v2 protocols.

Try ssh debugging with print-tunnel now to validate these hosts initiate their tunnels with v2 certificates.

Switch all lighthouses to use v2 certificates

Switch all am_lighthouse: true hosts' pki.default_version to 2 or add it if it doesn't exist yet. Now all of your hosts should be using their v2 certificate for initiating tunnels.

Try ssh debugging with print-tunnel now to validate these hosts initiate their tunnels with v2 certificates.

Re-issue v2 certificates for the hosts

Now that every host on the network is communicating via v2 certificates, you can remove the v1 certificates by reissuing the certificates. Pass -version 2 to only create certificates in the v2 certificate format. This will enable the non backwards compatible features of the v2 certificates.

❯ nebula-cert sign -name "nebula" -networks "192.168.1.1/24" -version 2
❯ nebula-cert print -path nebula.crt
{
"curve": "CURVE25519",
"details": {
"groups": null,
"isCa": false,
"issuer": "a95ed86f7754fc5b0fcaf38473504403748d6dc422b16bc3e29fcae32af9a73c",
"name": "nebula",
"networks": [
"192.168.1.1/24"
],
"notAfter": "2026-03-11T12:26:18-05:00",
"notBefore": "2025-03-17T16:06:48-05:00",
"unsafeNetworks": null
},
"fingerprint": "7260e59ca62a6a23ef8c6d5e912790fcb7073ffa1fe5da485d934a99d558c5ab",
"publicKey": "05baa0d1af10b89a8336c925a5c9b5fda5599943ee53a5bc742a573aa3e2753d",
"signature": "275229cd09228312171450fecc696776745dab88f6686e2a2577b764e4829a6566e3821e1101cdedb035e649fa70dc634300b3e628bf8ea839b6215ff68fdf02",
"version": 2
}

You can also add an IPv6 address to your hosts now.

❯ nebula-cert sign -name "nebula" -networks "192.168.1.1/24,fd0:0:0::1/64" -version 2
❯ nebula-cert print -path nebula.crt
{
"curve": "CURVE25519",
"details": {
"groups": null,
"isCa": false,
"issuer": "a95ed86f7754fc5b0fcaf38473504403748d6dc422b16bc3e29fcae32af9a73c",
"name": "nebula",
"networks": [
"192.168.1.1/24",
"fd0::1/64"
],
"notAfter": "2026-03-11T12:26:18-05:00",
"notBefore": "2025-03-17T16:11:30-05:00",
"unsafeNetworks": null
},
"fingerprint": "08e9d282adb0809457ad63982a9f1113a462763da58aa69b76d2b4cb1cd24724",
"publicKey": "ae950d4d0db966f93b5f463c9910d3fe9efd69347ddec4f3ed0f379c51712e0f",
"signature": "d156b2cd48916377426d8fab3286d176590ea48b83853f44f92089f1fb6d6bca9727b7169d3640e8a3418b3eac74159cb4368d847bd346663249d2dbbd81670e",
"version": 2
}

Once you switch services over to use the new IPv6 addresses, you can decide to deprecate the IPv4 addresses or continue to run your overlay network with both IPv4 and IPv6 subnets.