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

> Discover how ZeroTier network integration works in CasaOS. Learn about its architecture, API, and seamless startup auto-configuration for your virtual network.

- Repository: [IceWhale/CasaOS](https://github.com/IceWhaleTech/CasaOS)
- Tags: architecture
- Published: 2026-06-27

---

**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`](https://github.com/IceWhaleTech/CasaOS/blob/main/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`](https://github.com/IceWhaleTech/CasaOS/blob/main/pkg/utils/httper/zerotier.go)** and **[`pkg/utils/httper/httper.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/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`](https://github.com/IceWhaleTech/CasaOS/blob/main/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)`.

```go
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`](https://github.com/IceWhaleTech/CasaOS/blob/main/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:

```go
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`](https://github.com/IceWhaleTech/CasaOS/blob/main/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`](https://github.com/IceWhaleTech/CasaOS/blob/main/pkg/utils/httper/zerotier.go) |
| **v2 API** | Structured JSON responses for UI consumption; network status detection | [`route/v2/zerotier.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/route/v2/zerotier.go) |
| **v1 Proxy** | Raw passthrough for debugging; full daemon API exposure | [`route/v1/zerotier.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/route/v1/zerotier.go) |
| **Auto-Setup** | Boot-time network creation and host authorization | [`route/v1/zerotier.go`](https://github.com/IceWhaleTech/CasaOS/blob/main/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`](https://github.com/IceWhaleTech/CasaOS/blob/main/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`](https://github.com/IceWhaleTech/CasaOS/blob/main/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.