Skip to content
Nebula logoNebula logoNebula Docs

Controlling Nebula locally with nebula ctl

Nebula serves two local APIs, configured in the local_api section:

  • The control socket, used by nebula ctl, runs the same commands as the SSH debug console without having to set up sshd. It is on by default.
  • The info API answers "who is this?" for overlay addresses over HTTP, for other programs on the host. It is off by default.

nebula ctl connects to a Nebula already running on the same machine. Run it as root, as the user Nebula runs as, or as a member of local_api.control.group. On Windows, run it from an elevated prompt.

Terminal window
$ sudo nebula ctl list-hostmap
$ sudo nebula ctl identity 10.128.1.2
name: web01
vpn addrs: 10.128.1.2
networks: 10.128.1.2/16
unsafe networks:
groups: servers, web
fingerprint: 6d1f...
issuer: 4f0b...
not before: 2026-01-05T17:00:00Z
not after: 2027-01-05T16:59:59Z
cert version: 2

nebula ctl with no command, or nebula ctl help, lists the available commands. They are the same commands as the SSH debug console, except logout. nebula ctl help <command> or nebula ctl <command> -h shows a command's flags.

nebula ctl needs to know where the control socket is. It looks, in order:

  1. At the path given with -socket.
  2. At local_api.control.socket in the config given with -config, or else in a config.yml or config.yaml next to the nebula binary.
  3. At the default path, /var/run/nebula/ctl.sock, or \\.\pipe\ProtectedPrefix\Administrators\nebula-ctl on Windows.

If Nebula uses a non-default socket, point nebula ctl at the same config Nebula runs with:

Terminal window
$ sudo nebula ctl -config /etc/nebula/config.yml print-tunnel -pretty 10.128.1.2

-config and -socket may come before or after the command. nebula -config /etc/nebula/config.yml ctl <command> works too.

Commands print human readable text by default. Add -json for compact JSON, or -pretty for indented JSON. print-tunnel, print-relays, and query-lighthouse only have JSON output, and require -json or -pretty.

In JSON, commands that act rather than report, such as close-tunnel or reload, print {"ok":true,"reason":"..."}, or "ok":false with the reason when they refuse.

nebula ctl exits 0 on success and 1 on any failure. nebula ctl reload prints the outcome of the reload, and exits 1 when the new config did not load or part of it failed to apply, but not when it only needs a restart.

The control socket serves up to 8 connections at once.

The info API lets programs on the host ask Nebula which certificate is behind an overlay address, for example to authorize a connection by the peer's Nebula groups. Enable it with a socket path:

local_api:
info:
enabled: true
socket: /var/run/nebula/info.sock
group: nebula-info

It serves these requests:

Request Answers
GET /v1/identity This node's identity
GET /v1/identity/<vpn addr>[:port] The identity of the host with an established tunnel that owns the address
GET /v1/identity/pem This node's certificate, as {"pem": "-----BEGIN NEBULA CERTIFICATE-----..."}
GET /v1/identity/<vpn addr>[:port]/pem That host's certificate, the same way

A port on the address is accepted and ignored, so a program can pass the remote address of a connection as it is. Write an IPv6 address with a port as [addr]:port. Add ?pretty to any request to indent the JSON.

Terminal window
$ curl --unix-socket /var/run/nebula/info.sock 'http://localhost/v1/identity/10.128.1.2:443?pretty'
{
"name": "web01",
"vpnAddrs": [
"10.128.1.2"
],
"networks": [
"10.128.1.2/16"
],
"unsafeNetworks": [],
"groups": [
"servers",
"web"
],
"fingerprint": "6d1f...",
"issuer": "4f0b...",
"notBefore": "2026-01-05T17:00:00Z",
"notAfter": "2027-01-05T16:59:59Z",
"certVersion": 2
}

Lists are empty rather than null. Errors are JSON as well, {"error": "..."}, with these statuses:

  • 400: the address could not be parsed, the query was not pretty, or the request had a body.
  • 404: there is no established tunnel for the address, the address is outside this node's networks, or the path is unknown.
  • 405: the method was not GET.

The info API is read-only and only serves certificate identity, so it is fine to open it to a group, or to every user on the host with socket_mode: "0666". Never open the control socket that way.

On Windows the info API is a named pipe. Name it under \\.\pipe\ProtectedPrefix\Administrators\, so that only an administrator can create it and another program cannot take the name first. A program connecting as a member of local_api.info.group must open the pipe asking for exactly FILE_READ_DATA | FILE_WRITE_DATA | FILE_READ_ATTRIBUTES | READ_CONTROL | SYNCHRONIZE. Asking for GENERIC_READ or GENERIC_WRITE is refused.