惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

J
Java Code Geeks
GbyAI
GbyAI
Google DeepMind News
Google DeepMind News
Jina AI
Jina AI
B
Blog
aimingoo的专栏
aimingoo的专栏
酷 壳 – CoolShell
酷 壳 – CoolShell
T
The Blog of Author Tim Ferriss
Last Week in AI
Last Week in AI
月光博客
月光博客
H
Help Net Security
V
Visual Studio Blog
量子位
A
About on SuperTechFans
博客园 - Franky
人人都是产品经理
人人都是产品经理
N
Netflix TechBlog - Medium
云风的 BLOG
云风的 BLOG
雷峰网
雷峰网
Martin Fowler
Martin Fowler
Microsoft Security Blog
Microsoft Security Blog
博客园 - 叶小钗
P
Proofpoint News Feed
MongoDB | Blog
MongoDB | Blog

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
Zero-Config DNS and Monitoring for Your Traefik Homelab
Luc Allaire · 2026-05-09 · via DEV Community

Every Traefik service you expose already has a Host() rule that declares its public hostname. That information exists exactly once — in a Docker label — and propagates nowhere useful.

So you end up maintaining three or four systems by hand: Cloudflare for public DNS, NetBird for internal VPN-only hostnames, Uptime Kuma for monitoring — with groups, tags, and status pages configured per service. Add a container and you need to update everything manually. Remove it 4 months later and those records stay unless you remember to clean them up.

traefik-mesh-companion makes the container definition the single source of truth and syncs the rest automatically.

What It Does

A Go sidecar that watches the Docker socket and syncs your Traefik routing labels to:

  • NetBird — internal mesh VPN DNS records
  • Cloudflare — A records or CNAMEs to a CF Tunnel endpoint
  • Uptime Kuma — monitors, status page groups, tags, domain bindings
  • Gatus (via Gatus Bridge) — endpoints and groups

A single Docker Compose sidecar. No Kubernetes, no Helm, no operator.

How It Works

Split-Horizon DNS via Entrypoints

No new label namespace for DNS routing. Two env vars filter your existing entrypoint labels:

INTERNAL_FILTER=internal   # routers on this entrypoint → NetBird
EXTERNAL_FILTER=https      # routers on this entrypoint → Cloudflare

Enter fullscreen mode Exit fullscreen mode

Your existing Traefik labels stay exactly as-is:

# Matches INTERNAL_FILTER → NetBird only
traefik.http.routers.dashboard.rule: "Host(`dashboard.internal.example.com`)"
traefik.http.routers.dashboard.entrypoints: internal

# Matches EXTERNAL_FILTER → Cloudflare only
traefik.http.routers.api.rule: "Host(`api.example.com`)"
traefik.http.routers.api.entrypoints: https

Enter fullscreen mode Exit fullscreen mode

Force-override per container if needed:

mesh.dns.internal: "false"            # exclude from internal pipeline
mesh.routers.admin.managed: "false"   # exclude this router from everything

Enter fullscreen mode Exit fullscreen mode

The Rule Parser

Pure-Go regex AST. Handles compound rules:

(Host(`a.example.com`) || Host(`b.example.com`)) && PathPrefix(`/v2`)

Enter fullscreen mode Exit fullscreen mode

Both hostnames extracted for DNS. PathPrefix captured separately for monitor URL construction. HostRegexp intentionally skipped — you can't derive a static DNS record from a dynamic pattern.

Monitoring Label Hierarchy

The mesh.routers.* namespace sits outside Traefik's schema validator. Fallback hierarchy:

mesh.routers.<router_name>.kuma.<property>   ← highest priority
mesh.routers.<router_name>.<property>
mesh.kuma.<property>
mesh.<property>                              ← lowest priority

Enter fullscreen mode Exit fullscreen mode

Real example:

traefik.http.routers.api.rule: "Host(`api.example.com`)"
traefik.http.routers.api.entrypoints: https

mesh.routers.api.kuma.url: "/health"
mesh.routers.api.kuma.accepted_status_codes: "200, 204"
mesh.routers.api.kuma.interval: "30"
mesh.kuma.tags: "backend, prod:green"
mesh.kuma.pages: "public-status:APIs"

Enter fullscreen mode Exit fullscreen mode

Tags use djb2 deterministic hashing — same tag name always maps to the same color across nodes and restarts. Override with hex: prod:#22c55e.

Quick Start

services:
  mesh-companion:
    image: ghcr.io/wolf-infra/traefik-mesh-companion:stable
    container_name: traefik-mesh-companion
    restart: unless-stopped
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    environment:
      - SYNC_INTERVAL=1m
      - LOG_LEVEL=info
      # Internal (NetBird)
      - INTERNAL_PROVIDER=netbird
      - INTERNAL_FILTER=internal
      - INTERNAL_CLEANUP=true
      - NETBIRD_API_TOKEN=your_netbird_token
      - NETBIRD_TARGET_IP=100.64.0.5
      # External (Cloudflare)
      - EXTERNAL_PROVIDER=cloudflare
      - EXTERNAL_FILTER=https
      - EXTERNAL_CLEANUP=true
      - CLOUDFLARE_API_TOKEN=your_cf_token
      - CLOUDFLARE_TARGET_DOMAIN=your-tunnel-uuid.cfargotunnel.com
      # Monitoring (Uptime Kuma)
      - MONITOR_PROVIDER=kuma
      - KUMA_URL=http://kuma.example.com
      - KUMA_USERNAME=admin
      - KUMA_PASSWORD=${KUMA_PASS}
      - KUMA_AUTO_ENABLE=true
      - KUMA_GLOBAL_STATUS_PAGE=home-lab

Enter fullscreen mode Exit fullscreen mode

Use stable — it tracks the latest release. latest tracks main and is explicitly experimental.

Advanced: Distributed Coordinator

Running multiple edge nodes writing to one Uptime Kuma? They face race conditions on status page writes — both read current state, both modify it and last write ends up stomping the other's changes.

The companion ships a built-in Distributed Coordinator. One node is the server. Clients provision monitors locally and forward status page attachment operations to the server for sequential processing.

# Primary node
- KUMA_COORDINATOR_MODE=server
- KUMA_COORDINATOR_PORT=8081

# Other nodes
- KUMA_COORDINATOR_MODE=client
- KUMA_COORDINATOR_URL=http://primary:8081

Enter fullscreen mode Exit fullscreen mode

No external queue. Stateless — clients resend full state on reconnect.

Try It

GitHub: github.com/wolf-infra/traefik-mesh-companion

Full env var reference, label override docs, and Gatus Bridge config are in the README. The core.Processor interface makes adding new DNS or monitoring backends straightforward — PRs welcome.

Additional DNS backends are in development — the core.Processor interface is designed for exactly this. PRs welcome.