nebula puts group membership in the certificate, and the CA expires in a year
A scalable overlay networking tool with a focus on performance, simplicity and security
At a glance
- What is it?
- Nebula is an overlay network in Go that authenticates peers with certificates and filters traffic with user-defined groups, and the two decisions that shape how you operate it are that a node's groups are fixed when its certificate is signed and that a certificate authority has a one-year lifetime by default. The repository details are worth reading too, since the code lives under a corporate organisation while the docs, the commercial offering, the mobile clients and the container image all live under other names.
- Who is it for?
- Nebula fits a team that wants a private network across cloud providers and datacenters with cloud-style security groups, that is willing to run at least one lighthouse, and that can manage a certificate authority. A team that wants a control plane someone else runs is pointed by the quick start at Managed Nebula from Defined Networking.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly Go, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.
Star history
- slackhq/nebula18,529 ★ · +159
| Repository | 2026-09-21 | 2026-11-14 |
|---|---|---|
| slackhq/nebula | 18.4k | 18.5k |
159 Stars in the last 54 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
The code is under slackhq and every substantive link points elsewhere
The repository is `slackhq/nebula`, and the README does not describe a Slack product. Every link that carries substance points somewhere else.
The documentation is at `nebula.defined.net/docs`. The commercial offering is Managed Nebula from Defined Networking, and the getting started section opens by offering it to anyone who does not want to manage their own PKI and lighthouses. The mobile clients' source code is at `DefinedNet/mobile_nebula`, so the iOS and Android apps are not in this repository. The container image is `nebulaoss/nebula` on Docker Hub, and the chat is the NebulaOSS Slack group.
So there are three names in play. A corporate GitHub organisation holds the code, a company holds the documentation site and the managed service, and an independent-looking OSS identity holds the image and the chat. The dependency list confirms the company is involved in the code itself, since one of the direct requirements is a fork of a netlink library released with a suffix marking it as the company's own build.
None of this is a problem, and the arrangement is common for infrastructure that outgrew a single organisation. It is a problem to evaluate, because a reader arriving from the repository name has three places to check before they know which documentation is current.
ca.key is called the most sensitive file you will create, and PKCS#11 is a direct dependency
The certificate authority step is three lines of the quick start:
./nebula-cert ca -name "Myorganization, Inc"That creates `ca.key` and `ca.cert` in the current directory, and the README then says the `ca.key` file is the most sensitive file you will create, because it is the key used to sign the certificates for individual nodes, and to store it somewhere safe, preferably with strong encryption. Later the same step says, in capitals, do not copy `ca.key` to individual nodes.
The manifest shows what a serious answer to that warning looks like. Two PKCS#11 modules are direct dependencies, one the implementation and one a URI parser for referring to keys. PKCS#11 is the interface hardware security modules and software key stores expose, which suggests keys can be held in one, though source does not document how Nebula uses it.
The quick start does not mention PKCS#11, so the capability is visible in the dependency list rather than in the getting started steps.
A node's groups are set when it is signed, not in the config file
The signing step is where policy is attached, and the example makes it clear:
./nebula-cert sign -name "lighthouse1" -ip "192.168.100.1/24"
./nebula-cert sign -name "laptop" -ip "192.168.100.2/24" -groups "laptop,home,ssh"
./nebula-cert sign -name "server1" -ip "192.168.100.9/24" -groups "servers"
./nebula-cert sign -name "host3" -ip "192.168.100.10/24"Two of the four nodes carry `-groups` and two do not. The certificate is what asserts a node's IP address, name and membership within user-defined groups, and the groups are what allow provider-agnostic traffic filtering between nodes.
So group membership lives in the certificate, not in `config.yml`. The consequence is an operational loop rather than a technical one: changing which groups a node belongs to means reissuing its certificate and distributing the new one. The README's own framing is that Nebula was created to enable expressive firewall definitions similar in style to cloud security groups, and cloud security groups are attached to interfaces, not reissued with a new key.
That is the trade for having one identity object that carries address, name and policy together.
The CA has a one-year lifetime and host certificates expire one second before it
Two sentences in adjacent steps, and both are about expiry rather than about encryption.
The first is a warning in capitals: be aware, by default certificate authorities have a one-year lifetime before expiration, with a link to a guide on rotating a certificate authority. So a year is the default cadence for reissuing the root of trust for an entire network, and every node certificate depends on it.
The second is in the signing step: by default, host certificates will expire 1 second before the CA expires, and you can use the `-duration` flag to specify a shorter lifetime.
The one-second offset is a detail worth appreciating. It makes it structurally impossible for a node certificate to outlive the authority that signed it, which is the failure that turns a rotation into an outage. The cost is that you cannot extend a node's life without touching the authority, so the only direction available to an operator is shortening.
For a team planning this, the practical reading is that the annual rotation is not optional housekeeping, it is the expiry of your entire network, and the linked guide is the document to read before the first anniversary rather than on the day.
One UDP port, one cheap VM, and a lighthouse whose IP must not change
The infrastructure requirement is described in one step, and it is smaller than most overlay networks imply.
A lighthouse is a discovery node with a routable IP address, and the README is specific about its properties. It is the only node in a Nebula network whose IP should not change. Running one requires very few compute resources, and you can use the least expensive option from a cloud hosting provider. The maintainers then give their own figure: a number of them have used $6/mo DigitalOcean droplets as lighthouses.
The network requirement is one line. Once you have launched an instance, ensure that Nebula UDP traffic, default port udp/4242, can reach it over the internet.
So the whole discovery tier is one inbound UDP rule on one inexpensive virtual machine, and that is the number to hold on to. A lighthouse lets peers find each other anywhere in the world and can optionally use UDP hole punching to establish connections from behind most firewalls or NATs, so the remaining nodes do not need public addresses or forwarded ports.
The README is also honest that the lighthouse is optional but strongly recommended, marking it optional, but you really should, which is a fair way to describe a component that is technically avoidable and practically required.
CGO is off, gVisor is pinned to a 2024 commit, and the transport is WireGuard
Three manifest and build facts that together describe the data plane.
The Makefile sets `CGO_ENABLED = 0` and exports it. That is the opposite of most Go projects, and it is the right choice for a node binary you copy to a heterogeneous fleet: the result is static and has no libc requirement, which matters when the targets include five MIPS variants including a soft-float build.
The dependency list includes `golang.zx2c4.com/wireguard`, `golang.zx2c4.com/wireguard/windows` and `golang.zx2c4.com/wintun`, alongside `github.com/flynn/noise` for the Noise Protocol Framework the README names.
And `gvisor.dev/gvisor` is required at `v0.0.0-20261014193016-04d31b385980`, a pseudo-version dated October 2026; several other direct dependencies, such as `DefinedNet/dnsconfig` and `anmitsu/go-shlex`, are also pseudo-versions or v0 tags.
Fourteen Linux architectures in the build against four platforms in the prose
The README's supported platforms section names four systems for desktop and server: Linux in 64 and 32 bit, arm and others, plus Windows, MacOS and Freebsd. The build matrix is much larger.
The Makefile's `ALL_LINUX` is fourteen targets: amd64, 386, ppc64le, four arm variants covering versions 5, 6 and 7 plus arm64, five mips variants including soft-float, and then riscv64 and loong64. There are FreeBSD, OpenBSD and NetBSD pairs for amd64 and arm64, and darwin, windows pairs for amd64 and arm64.
The release cost of that is described in a comment rather than in prose. Cross-build shards are used by the test workflow, matching the full list but with the architecture that has a native runner removed, so the cross-build job is not duplicating what the native jobs already cover. That filtered list is then split into three family sub-shards, and the comment states the constraint plainly: the union of the three must equal the filtered list, and a new Linux architecture goes into the matching family.
So adding a Linux architecture means placing it in the matching family sub-shard to keep a stated arithmetic identity true. That is a maintenance cost a reader will not see from the four-bullet platform list.
The core sits at the repository root, and two subsystems have their own harnesses
The top level is a wall of Go files rather than a package directory, and nearly every one has a sibling test file beside it: `allow_list.go`, `bits.go`, `calculated_remote.go`, `connection_manager.go`, `connection_state.go`, `control.go`, `dns_server.go`, `firewall.go`, `hostmap.go`, `identity.go` and more, each with its `_test.go` in the same place.
Two of them carry a second file, and those are the interesting ones. `control_tester.go` and `hostmap_tester.go` sit alongside `control.go` and `hostmap.go`, so the control channel and the host map each have a purpose-built harness rather than only table-driven tests. In a daemon whose hardest part is a state machine negotiating with peers, that is the right allocation of test effort, and it is visible in the filenames.
One other detail. The Windows branch of the Makefile suppresses a vet check, because RIO on Windows does pointer work that makes go vet complain, which is the kind of thing a project either does quietly or writes down, and this one writes it down.
Editorial conclusion
Nebula fits a team that wants a private network across cloud providers and datacenters with cloud-style security groups, that is willing to run at least one lighthouse, and that can manage a certificate authority. A team that wants a control plane someone else runs is pointed by the quick start at Managed Nebula from Defined Networking. It does not fit a team that cannot accept a yearly CA rotation, because the default authority lifetime is one year and every node certificate expires with it. Before adopting, check three things: which port you have to open, since Nebula UDP traffic defaults to udp/4242 and must reach a lighthouse, whether the CA key can live in an HSM, which the two PKCS#11 dependencies in the manifest suggest is possible, and the release matrix, because the build produces fourteen Linux architectures including five MIPS variants while the prose names four platforms.
Frequently asked questions
What is Nebula?
Nebula is a scalable overlay networking tool that connects computers anywhere in the world, running on Linux, macOS, Windows, iOS and Android. It is a mutually authenticated peer-to-peer software-defined network based on the Noise Protocol Framework, using Elliptic-curve Diffie-Hellman key exchange and AES-256-GCM in its default configuration, with certificates asserting a node's IP address, name and group membership.
How do I set up a Nebula network?
The README walks seven steps: install `nebula-cert` and the nebula binary, run at least one lighthouse with a routable IP, create a certificate authority with `./nebula-cert ca`, sign a certificate per host with `./nebula-cert sign` including any `-groups`, copy the config plus `ca.crt` and each host's own certificate and key to it without ever copying `ca.key`, and run `./nebula -config` on each host. Nebula UDP traffic on the default port udp/4242 has to reach the lighthouse.
Does Nebula require a managed service?
No. The getting started section opens by saying that if you do not want to manage your own PKI and lighthouses, Managed Nebula from Defined Networking handles that, and then gives the self-hosted steps. The README also records that a number of the maintainers have used $6/mo DigitalOcean droplets as lighthouses, noting that a lighthouse needs very few compute resources.
How do Nebula security groups and certificate expiry work?
User-defined groups are attached to a node when its certificate is signed, through the `-groups` flag on `nebula-cert sign`, and they allow provider-agnostic traffic filtering between nodes. A certificate authority created with `nebula-cert ca` has a one-year lifetime by default, and host certificates expire one second before the authority does unless you pass `-duration` to make them shorter.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/slackhq-nebula)Star history chart for your README
[](https://hysenlabs.com/projects/slackhq-nebula)Was this useful?