How ZeroTier Network Integration Works in CasaOS: Architecture and API Deep Dive

CasaOS integrates ZeroTier by wrapping the local daemon's HTTP API in Go helper functions (ZTGet, ZTPost), exposing network status through a structured v2 REST endpoint, and providing a legacy v1 proxy for raw daemon passthrough, all while auto-configuring the CasaOS virtual network on startup.

CasaOS embeds ZeroTier support to enable seamless virtual LAN creation without manual CLI configuration. The integration leverages the ZeroTier One daemon's local HTTP API, consuming token files for authentication and dynamic port discovery. By examining the source code in route/v2/zerotier.go and pkg/utils/httper, you can see exactly how the home-server platform bridges containers and hosts across NAT boundaries.

The ZeroTier HTTP Client Layer

The foundation of CasaOS's ZeroTier support lies in thin HTTP wrappers that handle authentication and request signing. These helpers isolate the rest of the codebase from the daemon's local API mechanics.

Authentication and Port Discovery

Before making any requests, CasaOS locates the running ZeroTier daemon by reading two files from /var/lib/zerotier-one/:

  • zerotier-one.port – contains the TCP port number the daemon is listening on (typically 9993).
  • authtoken.secret – contains the ephemeral authentication token required for the X-ZT1-AUTH header.

These values are loaded at runtime and injected into every request to ensure only the local CasaOS process can command the daemon.

Core Helper Functions

The utility functions live in pkg/utils/httper/zerotier.go and pkg/utils/httper/httper.go:

  • ZTGet(path string) ([]byte, error) constructs a GET request to http://127.0.0.1:<port><path>, adds the X-ZT1-AUTH header, and returns the raw response body.
  • ZTPost(path string, body string) ([]byte, error) performs the same setup but sends a POST request with the provided JSON payload.
  • ZeroTierGet(url string, head map[string]string) is a generic variant used for remote controller endpoints, returning both the response body and HTTP status code.

These functions abstract the low-level details of the ZeroTier API, allowing higher-level business logic to focus on network management rather than HTTP boilerplate.

Querying Network Status via the v2 API

The modern REST interface is implemented in route/v2/zerotier.go, specifically within the GetZerotierInfo handler. This endpoint drives the CasaOS dashboard's network status widget.

The GetZerotierInfo Handler

When the UI requests GET /api/v2/zerotier/info, the handler executes the following flow:

  1. Calls httper.ZTGet("/controller/network") to list all networks managed by the local daemon.
  2. Iterates through the network array using gjson for efficient JSON parsing.
  3. Identifies the CasaOS-specific network by matching common.RANW_NAME against the name field.
  4. Fetches detailed network configuration via ZTGet("/controller/network/" + networkID).
func (s *CasaOS) GetZerotierInfo(ctx echo.Context) error {
    info := codegen.GetZTInfoOK{}
    respBody, err := httper.ZTGet("/controller/network")
    // ... error handling ...
    
    networkNames := gjson.ParseBytes(respBody).Array()
    for _, v := range networkNames {
        res, err := httper.ZTGet("/controller/network/" + v.Str)
        name := gjson.GetBytes(res, "name").Str
        if name == common.RANW_NAME {
            via := gjson.GetBytes(res, "routes.0.via").Str
            info.Id = utils.Ptr(gjson.GetBytes(res, "id").Str)
            info.Name = &name
            if len(via) == 0 {
                info.Status = utils.Ptr("online")
            } else {
                info.Status = utils.Ptr("offline")
            }
            break
        }
    }
    return ctx.JSON(http.StatusOK, info)
}

Determining Online/Offline Status

CasaOS infers connectivity by inspecting the routes.0.via field in the network configuration. An empty via value indicates the network is operating in pure Layer-2 mode (or has no upstream gateway), which the codebase interprets as online. A populated via field triggers an offline status, signaling that traffic is being routed through a gateway that may be unreachable.

Legacy Proxy and Network Management

For backward compatibility and raw daemon access, route/v1/zerotier.go implements a transparent proxy and automated network provisioning.

Full Daemon Passthrough via ZerotierProxy

The ZerotierProxy function allows arbitrary ZeroTier API calls by forwarding any request matching /v1/zt/* directly to the local daemon:

func ZerotierProxy(ctx echo.Context) error {
    port, err := ioutil.ReadFile("/var/lib/zerotier-one/zerotier-one.port")
    path := strings.TrimPrefix(r.URL.Path, "/v1/zt")
    targetURL := fmt.Sprintf("http://localhost:%s%s", strings.TrimSpace(string(port)), path)

    req, err := http.NewRequest(r.Method, targetURL, r.Body)
    authToken, _ := ioutil.ReadFile("/var/lib/zerotier-one/authtoken.secret")
    req.Header.Set("X-ZT1-AUTH", strings.TrimSpace(string(authToken)))
    
    resp, err := client.Do(req)
    // ... copy headers and write response ...
    return nil
}

This enables debugging tools and advanced users to interact with the full ZeroTier controller API through CasaOS's authenticated session.

Automated Network Provisioning

During system initialization, CasaOS ensures the host is joined to the correct virtual network. Functions like CheckNetwork, CreateNet, and JoinAndUpdateNet (all in route/v1/zerotier.go) automate this process:

  1. CheckNetwork verifies if a network matching common.RANW_NAME exists by querying /controller/network.
  2. CreateNet generates a new network with a unique CIDR pool if none is found.
  3. JoinAndUpdateNet authorizes the local node's ZeroTier address and assigns a static IP address within the network segment.

All these operations rely on the ZTGet and ZTPost helpers, maintaining clean separation between the HTTP transport and business logic.

Architectural Flow Summary

Layer Responsibility Key Source File
HTTP Client Handles auth tokens, port discovery, and raw GET/POST to daemon pkg/utils/httper/zerotier.go
v2 API Structured JSON responses for UI consumption; network status detection route/v2/zerotier.go
v1 Proxy Raw passthrough for debugging; full daemon API exposure route/v1/zerotier.go
Auto-Setup Boot-time network creation and host authorization route/v1/zerotier.go (network management functions)

Summary

  • CasaOS communicates with the local ZeroTier daemon via authenticated HTTP requests to 127.0.0.1, using token files from /var/lib/zerotier-one/ for security.
  • The GetZerotierInfo handler in route/v2/zerotier.go provides a curated view of network health, determining online status by inspecting the routes.0.via field.
  • A legacy ZerotierProxy in route/v1/zerotier.go enables full API passthrough, while helper functions like ZTGet and ZTPost keep the codebase DRY.
  • Background tasks automatically provision the CasaOS-named network and authorize the host on first boot, ensuring zero-config networking out of the box.

Frequently Asked Questions

How does CasaOS authenticate with the ZeroTier daemon?

CasaOS reads the authtoken.secret file from /var/lib/zerotier-one/ and injects its contents into the X-ZT1-AUTH header for every request. It also reads zerotier-one.port to determine the correct TCP port, ensuring it can locate the daemon even if running on a non-standard port.

What is the difference between the v1 and v2 ZeroTier endpoints?

The v2 endpoint (/api/v2/zerotier/info) is a curated API that returns filtered, JSON-structured data about the CasaOS-specific network, including a simplified online/offline status. The v1 endpoint (/v1/zt/*) acts as a transparent proxy, forwarding raw requests directly to the local ZeroTier daemon for advanced administrative tasks.

How does CasaOS determine if the ZeroTier network is online?

The system queries the network configuration via /controller/network/{id} and inspects the routes.0.via field using gjson. If the via field is empty, the network is marked as online; if it contains a gateway address, the status is reported as offline.

Can I use the CasaOS API to manage arbitrary ZeroTier networks?

Yes. While the v2 API only exposes the CasaOS-specific network (identified by common.RANW_NAME), you can use the v1 proxy endpoint (/v1/zt/) to send arbitrary commands to the local daemon. This allows you to create, join, or modify any network ID permitted by your ZeroTier controller, provided the request includes valid CasaOS authentication cookies or tokens.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →