dnsfleet

module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 11, 2026 License: MIT

README

DNSFleet

Code Coverage Go Report Card Go Doc

Chinese version: README_zh.md

LensDNS

A self-hosted control plane for operating a fleet of AdGuard Home nodes from one place: register nodes, push desired configuration, run sync and drift checks, and watch Live Logs (WebSocket tail plus REST-backed history). The data plane stays on AdGuard Home at the edge; DNSFleet holds control-plane state in SQLite and talks to each node over HTTP.

Scope (v0.1.x): single shared Admin credential, no durable storage of query logs (real-time observation only), no multi-tenant RBAC. Intended for homelab and small edge fleets where one operator controls a bounded set of nodes.

The embedded web console supports English and Chinese UI copy; English is the default, and you can switch language from the dashboard header (persisted in the browser). REST/WebSocket API messages stay as returned by the server.

Demo

Fleet

Fleet

Desired State

Desired State

Live Logs

DNSFleet Live Logs

Who it is for

  • Operators who already run AdGuard Home on several hosts and want a single UI and API for inventory, sync, and live query visibility.
  • Teams comfortable with self-hosted services, Bearer-style admin auth, and TLS termination in front of the process (reverse proxy).

Not a fit (today): centralized long-term DNS analytics / SIEM, non–AdGuard Home resolvers as first-class data plane, or hosted multi-tenant SaaS.

Capabilities

  • Nodes: CRUD, credentials (basic / bearer), online/offline signal, sync to AdGuard Home.
  • Desired state: global upstream / rewrite expectations (see API and UI).
  • Sync & drift: pull and compare remote config on a schedule; bounded concurrency to each node.
  • Live Logs: control plane Hub polls GET /control/querylog per online node; browsers receive tail traffic on GET /api/v1/ws/logs and page older rows via GET /api/v1/nodes/:id/querylog (see api/DNSFLEET_HTTP_API.md).
  • Distribution: production build embeds the Next.js static export into the Go binary (go:embed); one listening port for UI + API. Docker image and Compose files under deploy/.

Released builds: see GitHub Releases for versioned static binaries (Linux, Windows, macOS; amd64/arm64 where applicable), checksums, and container images on GHCR (tag v* workflow).

Quick start

Requirements: Go 1.26+ (see go.mod), Node 22+ only if you rebuild the web UI from web/.

  1. Copy .env.example to .env (or export the same variables). The process reads os.Getenv only; it does not auto-load .env.
  2. Set DNSFLEET_ADMIN_TOKEN to a strong secret (unless you deliberately use the insecure dev switch documented below).
  3. Build the UI and embed it, then run:
cd web && npm ci && npm run build && cd ..
make ensure-webui-dist   # Unix / Git Bash; or: powershell -File scripts/ensure-webui-dist.ps1
go run ./cmd/dnsfleet

Docker (recommended for trials): from the repository root (build context is the repo root):

docker compose -f deploy/docker-compose.yml up --build

Details: deploy/README.md (volumes, non-root UID, image build args). Local Next dev with API rewrites: web/README.md.

Repository layout

Path Purpose
cmd/dnsfleet/ Process entrypoint
internal/ Application code (HTTP, DB, AdGuard Home client, querylog hub, embedded UI)
api/ Public HTTP contract notes (DNSFLEET_HTTP_API.md)
web/ Next.js UI (static export for embed)
deploy/ Dockerfile and Compose
scripts/ Helper scripts (e.g. sync web/out into internal/webui/dist)

Configuration

All variables are read at startup from the environment (see internal/config/config.go).

Variable Default Description
DNSFLEET_DB_PATH ./data/dnsfleet.db SQLite file path (resolved to an absolute path on load). Not :memory:. Parent directory is created if missing.
DNSFLEET_HTTP_ADDR :8080 Listen address (Echo).
DNSFLEET_ADMIN_TOKEN (required) Shared secret for /api/v1 (Authorization: Bearer or X-Admin-Token). Empty token fails startup unless insecure mode is enabled.
DNSFLEET_ADMIN_INSECURE_DISABLE unset If exactly 1, skips Admin checks and allows an empty token. Do not use in production or on an exposed network.
DNSFLEET_SYNC_MAX_CONCURRENT 8 Cap concurrent AdGuard Home HTTP calls for drift, POST /api/v1/sync, GET /api/v1/nodes/:id/querylog, and POST /api/v1/nodes/:id/probe(创建/编辑节点时的探测 不经此槽,见 api/DNSFLEET_HTTP_API.md)。
DNSFLEET_SYNC_TOTAL_TIMEOUT 5m Total timeout for POST /api/v1/sync (time.ParseDuration).
DNSFLEET_DRIFT_INTERVAL 5m Drift ticker interval; one drift run happens immediately on startup.
DNSFLEET_QUERYLOG_MAX_CONCURRENT 8 Cap concurrent GET /control/querylog calls from the querylog Hub (independent of sync cap).
DNSFLEET_QUERYLOG_POLL_INTERVAL 2s Hub polling interval per online node.
DNSFLEET_QUERYLOG_PAGE_LIMIT 100 Hub single-page limit for GET /control/querylog. REST history uses its own default (20, max 100); the two need not match.
DNSFLEET_WS_MAX_FRAME_BYTES 65536 Max outbound WebSocket text frame size toward browsers.

HTTP: GET /healthz (no Admin). /api/v1 REST and /api/v1/ws/logs WebSocket require Admin (see api/DNSFLEET_HTTP_API.md).

Security and limits

  • Single operator model: one Admin secret for the control plane API and WebSocket upgrade path used by the UI.
  • Query logs are not a database product: tail and REST pages are ephemeral from the operator’s perspective; do not rely on DNSFleet as long-term audit storage.
  • Reverse proxies: terminate TLS and forward WebSocket headers (Upgrade, Connection) or Live Logs will fail through the proxy.
  • Client bundle: any NEXT_PUBLIC_* value is fixed at web build time; do not bake insecure skips into production images (see deploy/docker-compose.yml comments).

Development and CI

From the repository root:

go fmt ./...
go vet ./cmd/... ./internal/...
go test ./cmd/... ./internal/...

go test requires a non-empty internal/webui/dist (run make ensure-webui-dist after web production build, or make test which prepares it). Avoid go test ./... from the repo root if web/node_modules exists, to prevent the Go tool from picking up unrelated packages.

Web checks (web/README.md):

cd web && npm ci && npm run lint && npm run test && npm run build

GitHub Actions: .github/workflows/ci.yml runs the Go + web matrix on Ubuntu, Windows, and macOS, uploads Go coverage from the Ubuntu job to Codecov (optional repo secret CODECOV_TOKEN, or enable Codecov’s GitHub app / OIDC on your account), then builds the same Docker image as release with no registry push. Pushing a tag matching v* runs .github/workflows/release.yml: same tests, multi-platform static binaries and SHA256SUMS attached to the GitHub Release, and the image pushed to GHCR.

Design documents and maintainer-only notes are not shipped with this repository; behavior is defined by code and the public files linked above.

License

MIT

Directories

Path Synopsis
cmd
dnsfleet command
internal
adguard
Package adguard provides a minimal HTTP client for AdGuard Home control API (/control/*).
Package adguard provides a minimal HTTP client for AdGuard Home control API (/control/*).
config
Package config loads process configuration from environment variables with DNSFleet defaults.
Package config loads process configuration from environment variables with DNSFleet defaults.
db
Package db 提供 DNSFleet 控制面 SQLite 连接与 GORM AutoMigrate(Step 1.4)。
Package db 提供 DNSFleet 控制面 SQLite 连接与 GORM AutoMigrate(Step 1.4)。
models
Package models 存放 DNSFleet 的 GORM 领域模型(Step 1.3:Node、GlobalConfig)。
Package models 存放 DNSFleet 的 GORM 领域模型(Step 1.3:Node、GlobalConfig)。
querylog
Package querylog holds the process-wide query log Hub (Step 4 §4.2) and field-mapping docs (README.md).
Package querylog holds the process-wide query log Hub (Step 4 §4.2) and field-mapping docs (README.md).
webui
Package webui embeds the Next.js static export (output: 'export') for same-origin delivery by the control plane.
Package webui embeds the Next.js static export (output: 'export') for same-origin delivery by the control plane.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL