تخطَّ إلى المحتوى

Nebula Cheat Sheet

Overview

Nebula is an open-source, scalable overlay networking tool originally developed at Slack to connect tens of thousands of hosts across multiple cloud providers, data centers, and employee devices into a single flat network. It uses a certificate-based identity system where each node receives a signed certificate containing its Nebula IP, groups, and metadata. All traffic between nodes is encrypted end-to-end using Noise protocol (similar to WireGuard), and nodes discover each other through designated lighthouse nodes that facilitate NAT traversal.

Unlike traditional VPN solutions, Nebula creates a true mesh network where traffic flows directly between peers rather than through a central gateway, minimizing latency and eliminating bottlenecks. Each node runs its own firewall with rules based on certificates, groups, and network properties, enabling fine-grained microsegmentation. Nebula supports Linux, macOS, Windows, iOS, and Android, runs entirely in user space without kernel modules, and can scale to networks with thousands of nodes with minimal overhead.

Installation

Linux

# Download latest release
NEBULA_VERSION=$(curl -s https://api.github.com/repos/slackhq/nebula/releases/latest | grep tag_name | cut -d'"' -f4)
wget https://github.com/slackhq/nebula/releases/download/${NEBULA_VERSION}/nebula-linux-amd64.tar.gz
tar xzf nebula-linux-amd64.tar.gz
sudo mv nebula nebula-cert /usr/local/bin/

# Verify
nebula --version
nebula-cert --version

macOS

brew install nebula

Windows

# Download from GitHub releases
# Extract nebula.exe and nebula-cert.exe to PATH
# Or use Scoop
scoop install nebula

Docker

docker run --rm -v $(pwd):/nebula \
  --cap-add NET_ADMIN \
  --device /dev/net/tun \
  nebulaoss/nebula:latest \
  -config /nebula/config.yml

Certificate Authority Setup

Create CA

# Create CA certificate (valid for 2 years)
nebula-cert ca -name "MyOrg CA" -duration 17520h

# This creates:
# ca.crt - CA certificate (distribute to all nodes)
# ca.key - CA private key (keep secure, offline)

# Create CA with specific groups
nebula-cert ca -name "MyOrg CA" -groups "servers,laptops,phones"

# View CA certificate
nebula-cert print -path ca.crt

Sign Node Certificates

# Sign certificate for a lighthouse
nebula-cert sign \
  -name "lighthouse1" \
  -ip "10.100.0.1/24" \
  -groups "lighthouse,infrastructure"

# Sign certificate for a server
nebula-cert sign \
  -name "webserver1" \
  -ip "10.100.0.10/24" \
  -groups "servers,web"

# Sign certificate for a laptop
nebula-cert sign \
  -name "alice-laptop" \
  -ip "10.100.0.100/24" \
  -groups "laptops,engineering"

# Sign with custom duration
nebula-cert sign \
  -name "temp-device" \
  -ip "10.100.0.200/24" \
  -groups "contractors" \
  -duration 720h

# Sign with subnet routing
nebula-cert sign \
  -name "site-router" \
  -ip "10.100.0.5/24" \
  -groups "routers" \
  -subnets "192.168.1.0/24"

# Verify certificate
nebula-cert print -path webserver1.crt

# Each sign command creates:
# <name>.crt - Node certificate
# <name>.key - Node private key

Configuration

Lighthouse Configuration

# /etc/nebula/config.yml (lighthouse node)
pki:
  ca: /etc/nebula/ca.crt
  cert: /etc/nebula/lighthouse1.crt
  key: /etc/nebula/lighthouse1.key

static_host_map:
  # Empty on lighthouse itself

lighthouse:
  am_lighthouse: true
  # Listen interval
  interval: 60

listen:
  host: 0.0.0.0
  port: 4242

punchy:
  punch: true
  respond: true

tun:
  disabled: false
  dev: nebula1
  drop_local_broadcast: false
  drop_multicast: false
  tx_queue: 500
  mtu: 1300

logging:
  level: info
  format: text

firewall:
  conntrack:
    tcp_timeout: 12m
    udp_timeout: 3m
    default_timeout: 10m

  outbound:
    - port: any
      proto: any
      host: any

  inbound:
    - port: any
      proto: icmp
      host: any
    - port: 22
      proto: tcp
      groups:
        - infrastructure
    - port: 443
      proto: tcp
      host: any

Node Configuration

# /etc/nebula/config.yml (regular node)
pki:
  ca: /etc/nebula/ca.crt
  cert: /etc/nebula/webserver1.crt
  key: /etc/nebula/webserver1.key

static_host_map:
  "10.100.0.1": ["203.0.113.10:4242"]

lighthouse:
  am_lighthouse: false
  interval: 60
  hosts:
    - "10.100.0.1"

listen:
  host: 0.0.0.0
  port: 0

punchy:
  punch: true
  respond: true

tun:
  disabled: false
  dev: nebula1
  drop_local_broadcast: false
  drop_multicast: false
  tx_queue: 500
  mtu: 1300

logging:
  level: info
  format: text

firewall:
  outbound:
    - port: any
      proto: any
      host: any

  inbound:
    - port: any
      proto: icmp
      host: any
    - port: 22
      proto: tcp
      groups:
        - engineering
        - infrastructure
    - port: 80
      proto: tcp
      host: any
    - port: 443
      proto: tcp
      host: any

Running Nebula

Direct Execution

# Run in foreground
sudo nebula -config /etc/nebula/config.yml

# Test configuration
nebula -config /etc/nebula/config.yml -test

Systemd Service

# /etc/systemd/system/nebula.service
cat << 'EOF' | sudo tee /etc/systemd/system/nebula.service
[Unit]
Description=Nebula Overlay Network
Wants=basic.target network-online.target nss-lookup.target
After=basic.target network.target network-online.target
Before=sshd.service

[Service]
SyslogIdentifier=nebula
ExecReload=/bin/kill -HUP $MAINPID
ExecStart=/usr/local/bin/nebula -config /etc/nebula/config.yml
Restart=always

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable nebula
sudo systemctl start nebula
sudo systemctl status nebula

Firewall Rules

Group-Based Access Control

firewall:
  inbound:
    # Allow ICMP from everyone
    - port: any
      proto: icmp
      host: any

    # SSH only from engineering and ops
    - port: 22
      proto: tcp
      groups:
        - engineering
        - ops

    # Web traffic from any Nebula host
    - port: 80
      proto: tcp
      host: any
    - port: 443
      proto: tcp
      host: any

    # Database only from web servers
    - port: 5432
      proto: tcp
      groups:
        - web

    # Monitoring from infrastructure group
    - port: 9090
      proto: tcp
      groups:
        - infrastructure

    # Allow specific host by name
    - port: any
      proto: any
      host: "admin-workstation"

    # CIDR-based rules
    - port: any
      proto: any
      cidr: 10.100.0.0/24

  outbound:
    - port: any
      proto: any
      host: any

Advanced Usage

Multiple Lighthouses

static_host_map:
  "10.100.0.1": ["203.0.113.10:4242"]
  "10.100.0.2": ["198.51.100.20:4242"]

lighthouse:
  am_lighthouse: false
  hosts:
    - "10.100.0.1"
    - "10.100.0.2"

Unsafe Routes (Route to Non-Nebula Subnets)

tun:
  unsafe_routes:
    - route: 192.168.1.0/24
      via: 10.100.0.5      # Nebula IP of the gateway node
      mtu: 1300
    - route: 172.16.0.0/16
      via: 10.100.0.6

Relay Nodes (for Difficult NAT)

# On relay node config
relay:
  am_relay: true
  use_relays: false

# On nodes that need relay
relay:
  am_relay: false
  use_relays: true
  relays:
    - 10.100.0.1

Certificate Rotation

# Check certificate expiration
nebula-cert print -path node.crt | grep "Not After"

# Issue new certificate with same IP
nebula-cert sign -name "webserver1" -ip "10.100.0.10/24" -groups "servers,web"

# Replace cert and key on node, then reload
sudo cp webserver1.crt /etc/nebula/
sudo cp webserver1.key /etc/nebula/
sudo systemctl reload nebula

DNS Integration

# Nebula doesn't include DNS, but you can use:
# 1. Add entries to /etc/hosts on each node
# 2. Run a DNS server (CoreDNS/dnsmasq) on a Nebula node
# 3. Use mDNS/Avahi for .local names

Troubleshooting

IssueSolution
Nodes can’t find each otherVerify lighthouse public IP in static_host_map
Handshake timeoutCheck UDP port 4242 is open on lighthouse
Certificate errorVerify ca.crt matches, check cert expiration
Relay-only connectionsNAT issue; enable punchy, check STUN/UPnP
High latencyCheck if traffic is relayed vs direct peer
tun device not createdNeed root/NET_ADMIN capability
Config test failsRun nebula -config config.yml -test
Firewall blocking trafficCheck inbound rules match source groups

Diagnostic Commands

# Check Nebula interface
ip addr show nebula1

# Test connectivity
ping 10.100.0.1

# View Nebula logs
journalctl -u nebula -f

# Send SIGHUP to reload config (without cert changes)
sudo kill -HUP $(pgrep nebula)

# Check listening port
sudo ss -ulnp | grep nebula

# Debug logging
# Set level: debug in config.yml, restart

Common Log Messages

# Successful handshake
Handshake message sent to 10.100.0.10

# NAT traversal working
punchy: sending punch to 10.100.0.10

# Certificate issue
Certificate is expired or not yet valid

# Firewall blocking
dropping inbound packet from 10.100.0.100: no matching firewall rule