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

推荐订阅源

美团技术团队
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
博客园 - Franky
有赞技术团队
有赞技术团队
博客园 - 司徒正美
量子位
N
News and Events Feed by Topic
T
Threatpost
Last Week in AI
Last Week in AI
D
Darknet – Hacking Tools, Hacker News & Cyber Security
酷 壳 – CoolShell
酷 壳 – CoolShell
C
CERT Recently Published Vulnerability Notes
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
I
Intezer
人人都是产品经理
人人都是产品经理
T
Tenable Blog
IT之家
IT之家
雷峰网
雷峰网
腾讯CDC
博客园 - 聂微东
V
Visual Studio Blog
S
SegmentFault 最新的问题
Scott Helme
Scott Helme
Spread Privacy
Spread Privacy
月光博客
月光博客
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
V
V2EX
大猫的无限游戏
大猫的无限游戏
Apple Machine Learning Research
Apple Machine Learning Research
爱范儿
爱范儿
T
Tailwind CSS Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
罗磊的独立博客
N
Netflix TechBlog - Medium
J
Java Code Geeks
宝玉的分享
宝玉的分享
F
Full Disclosure
WordPress大学
WordPress大学
A
Arctic Wolf
小众软件
小众软件
AWS News Blog
AWS News Blog
Attack and Defense Labs
Attack and Defense Labs
NISL@THU
NISL@THU
AI
AI
Hugging Face - Blog
Hugging Face - Blog
F
Fortinet All Blogs
云风的 BLOG
云风的 BLOG
N
News | PayPal Newsroom
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org

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 Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
Local AI Needs Data-Plane Health Checks
Rob · 2026-06-15 · via DEV Community

The worst network bugs are the ones where every dashboard says green and the packet still dies.

That was my Sunday.

I have a Mac that I use as my daily machine and a Linux box called newtorob with a 2080 Ti in it. Potluck runs a local AI sidecar on each machine. The Mac can use its own model locally, or route a request to another machine in my household over a WireGuard mesh.

The product shape is simple:

Mac app -> local sidecar -> WireGuard mesh -> Linux sidecar -> model runtime -> streamed tokens back to the Mac.

This is the "my machines" path. No model API. No cloud inference. The coordinator handles roster and signaling metadata, but the prompt itself should go directly over the private mesh to my own hardware.

Everything looked connected. The Linux peer was enrolled. The coordinator knew about it. The mesh sidecar was running. The UI showed a peer. The machine had a model loaded.

Then I sent a prompt and got: no reachable peer.

The control plane was green. The data plane was dead.

The lie in "online"

Most peer health checks answer the wrong question.

A coordinator heartbeat proves the peer can talk to the coordinator.

A WebSocket connection proves the peer can keep one control connection open.

A WireGuard handshake proves two tunnel endpoints exchanged packets recently.

A capabilities response proves a process can report what it thinks it can serve.

None of those prove that an inference request can cross the exact path the product needs right now.

For a local AI mesh, the real question is not "is this peer online?"

The real question is:

Can this prompt reach that model and stream a token back right now?

That distinction matters because the failure modes sit between the layers. A peer can be present in the roster while the tunnel is broken. A tunnel can have a fresh handshake while HTTP over the tunnel fails. A model can be loaded while the process is unreachable from the other machine. A privacy VPN can silently drop traffic on an interface it does not recognize while every higher-level control check looks fine.

That last one was my bug.

The first wrong theory

My first theory was MTU.

That was not random. WireGuard-over-WireGuard paths are good at producing partial success. A small handshake packet can pass while larger data packets disappear. If path MTU discovery is broken, the tunnel looks alive and the application path dies. This is exactly the kind of problem where "connected" and "usable" diverge.

Tailscale and NetBird both default to conservative MTUs around 1280 for a reason. WireGuard adds overhead. Relays add overhead. Residential networks add weirdness. If you run a local mesh on top of another VPN, a 1420-byte default can turn into a packet shredder.

So I checked the mesh MTU.

It was already 1280.

That was a useful dead end. It ruled out the cleanest explanation and left the uglier one: the packet was not too large. It was not allowed.

The real cause

The Linux box runs Mullvad. The Mac also has Tailscale. Potluck uses a potluck0 WireGuard interface and mesh IPs in the 100.64.0.0/10 range.

That combination has two separate traps.

Tailscale treats 100.64.0.0/10 as its space. Its nftables rules can drop packets from that range when they arrive on a non-tailscale0 interface.

Mullvad's killswitch is stricter. It installs nftables chains with default-drop policy and allows traffic only through interfaces it trusts. potluck0 is not one of them.

From Mullvad's perspective, this is correct behavior. A privacy VPN killswitch should not let random interfaces become escape hatches.

From Potluck's perspective, this means my own mesh interface is blocked unless I add a narrow exception.

The fix was three scoped accept rules:

nft insert rule ip filter ts-input iifname potluck0 accept
nft insert rule inet mullvad input iifname potluck0 accept
nft insert rule inet mullvad output oifname potluck0 accept

Not a flush. Not a policy change. Not disabling the VPN firewall. Just a hole for the Potluck mesh interface.

After that, the Mac could hit:

curl http://100.64.0.7:8321/health
curl http://100.64.0.7:8321/peer/capabilities

Both returned 200. The prompt routed to the Linux box. The footer showed it ran on newtorob-a16.

That fixed the immediate problem.

Then it broke again.

Reconnects erase one-shot fixes

VPN clients rebuild firewall rules.

That sentence is obvious after you have been bitten by it once. It is not obvious when you are staring at a mesh that worked five minutes ago.

Mullvad, Proton, Nord, and similar clients do not treat nftables as a stable place where your hand-inserted rule gets to live forever. Reconnect the VPN, switch servers, wake from sleep, change networks, and the client may recreate its ruleset. Your narrow exception disappears. The killswitch keeps doing its job. Your mesh goes dark again.

My first fix was a boot-time one-shot. It installed the three accept rules when the machine started. That survives reboots. It does not survive VPN reconnects.

The better fix was a watcher.

Every few seconds it checks whether the accept rules that should exist still exist. If Tailscale or Mullvad is not present, it owes nothing. If they are present and any of the three potluck0 rules are missing, it reruns the same idempotent insert path.

The loop is boring by design:

while true; do
    sleep "${POTLUCK_FW_WATCH_INTERVAL:-5}"
    if ! rules_intact; then
        log "accept rule(s) missing; reapplying"
        do_install || log "reapply hit an error; will retry on next tick"
    fi
done

The systemd unit is also boring:

Type=exec
ExecStart=/usr/local/lib/potluck/install-firewall-rules.sh --watch
ExecStop=/usr/local/lib/potluck/install-firewall-rules.sh --uninstall
Restart=always

I tested it the blunt way. Run --uninstall, confirm all three rules are missing, wait seven seconds, confirm they are back. The journal logged the reapply event. The mesh stayed usable after that.

That is not the whole product fix. It is only the repair for this Linux VPN coexistence case.

The product fix is diagnostics.

A health check needs to follow the work

The lesson is not "add firewall rules."

The lesson is that local AI needs data-plane health checks.

If a system routes inference across machines, it should have a check that uses the same route as inference. Not just the same peer. Not just the same coordinator. The same path.

For my setup, a real health check should answer separate questions:

  1. Is the local sidecar running?
  2. Is the coordinator reachable?
  3. Is the peer present in the roster?
  4. Is there a recent WireGuard handshake?
  5. Can this machine make an HTTP request to the peer sidecar over the mesh IP?
  6. Can the peer stream a small response from the model path?

Those are different failures with different owners and different fixes.

If the coordinator is down, restarting Mullvad will not help.

If the peer is powered off, reapplying nftables rules will not help.

If the WireGuard key in the coordinator is stale, reloading the model will not help.

If the model runtime is missing CUDA libraries, the tunnel can be perfect and inference will still fail.

If Mullvad dropped potluck0, the peer can look enrolled and still be unusable.

The UI should not compress all of that into "offline."

It should say "coordinator unreachable," "peer not present," "no tunnel," "relayed," "firewall likely blocking mesh traffic," or "model runtime not ready." The exact labels matter less than the principle: name the layer that failed.

Why this matters more for local AI than normal SaaS

In a normal SaaS product, most of the network path is owned by the operator. The user opens a browser. Your load balancer works or it does not. Your app servers work or they do not. There are still ugly edge cases, but the core path is under one operational umbrella.

Local AI is different.

The path crosses the user's laptop, their OS firewall, their VPN, their home router, a mesh tunnel, another machine's firewall, a model sidecar, a Python runtime, a GPU driver, and a model file on disk.

The product does not get to pretend that is one boolean.

This is especially true for "my machines" routing. The whole point is to make a user's idle hardware useful: Mac for the app, Linux box for GPU inference, Windows desktop for another model, maybe a mini PC in a closet. That is a better architecture for ownership and cost. It is also a worse architecture for lazy health checks.

The user should not need to know nftables to understand why their peer is unavailable.

The software should know enough to say: "Your peer is visible, but data-plane traffic over potluck0 is blocked. Reapply the scoped firewall rules or disable the VPN killswitch exception."

Even better, with consent, it should offer the fix.

What I changed

The immediate change was operational:

  1. Add a narrow, reversible firewall helper for Linux systems using Tailscale and Mullvad.
  2. Run it as a long-lived systemd watcher, not a boot-only one-shot.
  3. Keep the scope to potluck0 accepts. Do not flush rulesets. Do not weaken the broader VPN policy.
  4. Verify the real path with curl to /health and /peer/capabilities, then a prompt that actually runs on the remote machine.

The next change is product:

Replace the single peer-status badge with a small diagnostics model. Local host, coordinator, relay, tunnel, peer data plane, model runtime. Each layer gets a named failure and a concrete fix.

That is less elegant than a green dot.

It is also more honest.

The check I want

The check I want is not expensive.

Send a tiny HTTP probe to the peer over the mesh. Sometimes send a larger one to catch MTU and fragmentation problems. If the app is about to route inference, ask the peer for capabilities over the same path. If that passes, optionally send a tiny model-path probe before marking the peer usable for a real prompt.

Cache the answer briefly. Debounce flaps. Suppress downstream errors when an upstream layer is already broken.

But do not call the peer reachable just because a control-plane heartbeat exists.

That is how I lost an afternoon.

What I would tell anyone building this

If you are building local-first AI across machines, do not start with "peer online."

Start with the path:

Can the request leave this process?

Can it cross the mesh?

Can it reach the peer process?

Can the peer reach the model runtime?

Can one token come back?

Everything else is metadata.

The metadata is still useful. Heartbeats, handshakes, rosters, relay status, and capabilities all help narrow the search. But they are not proof that the system can do the work.

A local AI mesh should not ask "is the peer online?"

It should ask "can this prompt reach that model and stream a token back right now?"

That is the health check that matters.


Rob writes the Local AI Engineering Notes series on strake.dev. He's building Potluck AI, a local-first AI system that routes inference across your own machines and trusted peers, and Strake, a GitHub Action deploy gate.