AI 资讯
How a Simple Ping Took 4 Hours: WireGuard, Docker Desktop, and the Silent Linux Kernel Drops
I have been working on building a private, secure network accessible from anywhere. The goal was to connect my mobile phone and my local development laptop using a WireGuard VPN , hosting the central gateway on a free-tier Google Cloud Platform (GCP) e2-micro instance. I wanted to access my self-hosted services, specifically my Docker-hosted Open WebUI , running on my local home Wi-Fi connected laptop, directly from my phone using mobile data. It sounded straightforward. But if you read my other from scratch journeys, you might have already guessed, it was not. The Setup My architectural plan was a simple hub-and-spoke topology: The Hub: GCP VM ( 10.66.66.1 ) with IPv4 forwarding enabled. Spoke 1 (My Phone): 10.66.66.2 Spoke 2 (My Laptop): 10.66.66.3 I wrote my server configurations, enabled IP forwarding ( net.ipv4.ip_forward=1 ), wrote the iptables rules to allow forwarding between peers, and started the interfaces. Then came the moment of truth. I tried to bring up the tunnel. Absolute silence. No packet moving from anywhere. Hurdle 1: The Classic Cloud NAT Trap (Internal vs. Public IP) Before I could even worry about routing packets between my phone and laptop, I couldn't even get them to handshake with the GCP server. Like many of us do when working inside a VM, I had run ip addr on the GCP instance to grab its IP address for my client configurations. I set up the WireGuard peers to point to this IP. Nothing connected. The Culprit: GCP (and AWS) operates on a 1:1 NAT mapping. The virtual network interface inside your VM only sees and binds to a private, internal cloud IP (e.g., 10.128.0.x ). The public IP assigned to your instance lives outside the VM at the VPC gateway level. By putting the internal IP into my client configs, my phone and laptop were trying to connect to a private address that didn't exist on their local networks. The Fix: I had to swap the internal IP in the client configurations with the GCP Ephemeral/Static External IP . Once the handshake
AI 资讯
Did You Know TLDs Can Be Websites?
You've probably registered a domain with Route53 or another popular registrar. You pick something...
AI 资讯
How to Build an AI Agent with n8n
Building an AI agent with n8n is the fastest, cheapest way to turn a large language model into a useful worker — if you stay within its sweet spot. The honest truth, informed by the custom agents we ship, is that n8n carries a well-scoped agent further than most people expect. An LLM node, a few tool/webhook nodes and a trigger are all you need. This guide walks you through that exact workflow and, just as importantly, names the precise moment n8n stops cutting it and a custom build must take over. What You Need Before You Start You'll need a running n8n instance (self-hosted or cloud) and API keys for the services you want to integrate. Grab a Gemini or OpenAI key from their respective developer consoles — n8n's official AI agent builder documentation lists the full compatibility. The quick-start template also gives you a one-click import to see an agent's skeleton immediately. How to Build an AI Agent with n8n: The Core Workflow The core is a chain of nodes: a trigger wakes the agent, an LLM node reasons, and tool/webhook nodes take action. That's the entire pattern. Here's how to assemble it. Set the trigger Drag a Webhook node onto the canvas if you want the agent called via HTTP, or a Schedule node to run it periodically. For our example, we'll use a webhook that receives a customer question. Add the LLM node Attach an OpenAI Chat Model (or Gemini) node. In the node's parameters, craft a system prompt that scopes the agent. For a support bot, something like: You are a helpful support agent for our SaaS product. Use the tools provided to answer questions. If you don't know, say you need human help. This prompt is the boundary of the agent's autonomy. Keep it specific — vagueness leads to hallucinations. Attach tool and webhook nodes Here's where n8n shines. Drag a Function node to run custom JavaScript (e.g., querying a database) or a HTTP Request node to call an external API. Wire them as "tools" by connecting them to the LLM node's tool output. In the LLM node
AI 资讯
What Is My IP Address? IPv4 vs IPv6 Explained for DevelopersPublished
What Is My IP Address? IPv4 vs IPv6 Explained for Developers If you've ever debugged a CORS error, set up an IP allowlist, or wondered why req.ip returned something weird in your Express logs, you've run into the same question from a different angle: what actually is an IP address, and which one is "mine"? fastestchecker.com This post breaks down IPv4 vs IPv6, public vs private IPs, and how to reliably detect a user's IP address in your own code — plus a fast way to check yours right now. fastestchecker.com TL;DR IPv4 addresses look like 192.168.1.1 — four numbers, 0-255, separated by dots. There are about 4.3 billion of them, and we've run out. IPv6 addresses look like 2001:0db8:85a3::8a2e:0370:7334 — a much larger address space designed to replace IPv4. Your device usually has a private IP (local network) and shares a public IP (internet-facing) with everyone else on your router. You can check your current public IP instantly with a tool like FastestChecker's IP Checker — useful for confirming what your server or API actually sees. > IPv4 vs IPv6 : What's the Actual Difference IPv4 IPv4 has been the backbone of the internet since the 1980s. It's a 32-bit address, which caps the total number of unique addresses at roughly 4.3 billion. Given how many devices are online today, that pool has been effectively exhausted for years — which is why NAT (Network Address Translation) exists: it lets an entire household or office share one public IPv4 address. Example IPv4: 203.0.113.42 IPv6 IPv6 uses 128-bit addresses, which gives it an address space so large it's effectively unlimited for practical purposes (2^128 addresses). It was designed specifically to solve IPv4 exhaustion, and adoption has been climbing steadily — most major cloud providers and mobile carriers support it by default now. ** Example IPv6:** 2001:0db8:85a3:0000:0000:8a2e:0370:7334 Quick Comparison IPv4IPv6Address length32-bit128-bitFormatDotted decimal (192.168.1.1)Hexadecimal, colon-separatedTotal addre
AI 资讯
The Biggest Misconception About React Reconciliation (Render vs. Paint)
Hey everyone, I recently had an "aha!" moment regarding how React handles updates under the hood, and I wanted to share it because I realize a ton of developers (including myself, until recently) trip over this exact concept. The common mental model is that React Reconciliation compares the Virtual DOM directly to the Real Browser DOM and surgically updates only what changed. But that’s fundamentally incorrect. React never reads or directly compares the real DOM during the diffing process. It actually splits the process into two entirely separate phases —The Render Phase and The Commit Phase —which creates a massive distinction between Re-rendering and Re-painting. Here is the exact breakdown of what happens when a single state change affects just 1 out of 100 divs in a component: The Render Phase (Pure JavaScript) When state changes, React calls your component function. It doesn't know which of your 100 divs changed yet, so it has to evaluate the entire JSX block. The Scope: React re-renders all 100 virtual divs in memory. The Process: It builds a brand-new Virtual DOM tree and compares it to the previous Virtual DOM tree (JavaScript object vs. JavaScript object). The Outcome: It spots that 99divs are identical, but 1 div has an update. It flags that single virtual node with an "Update" tag. Because this happens purely in-memory as JavaScript, it is incredibly fast and cheap. The Commit Phase (The Real DOM Update) This is where Reconciliation does its primary job. It acts as a shield to protect the browser from doing unnecessary work. The Scope: React completely ignores the 99 unchanged elements. The Process: It surgically targets the single real browser div associated with the flagged Virtual DOM element and updates only its modified property (e.g., element.textContent = "New Value"). The Outcome: The browser repaints only 1 single div on the screen. The Conclusion: Reconciliation isn't about stopping React from re-rendering (re-running JS to calculate the UI). It
AI 资讯
Designing a Three Reviewer Consensus Platform for Digital Harm Reporting
The Problem Real411 is a South African platform where citizens report digital harms: misinformation, incitement, hate speech, and harassment. When someone submits a complaint, it needs to be reviewed by multiple people, assessed against legal criteria, and resolved with a public verdict. The process must be transparent, auditable, and fair. I joined this project early and worked on it extensively over a long period. A senior solutions architect consulted on the database schema design. There was a cloud person who helped with parts of the infrastructure. Other coworkers contributed at different stages. I spent most of my time on the API layer and the frontend components. This article covers the architecture decisions I worked with, what I learned from the senior architect's design choices, and how the system evolved. The Status Machine Most applications model status as a column on a table. You update the value and the old state is gone. That works for simple workflows but fails when you need to know not just where a complaint is now, but how it got there and who made each decision. The senior architect who consulted on the database design suggested an append only status log. Instead of a single status column, the complaint_status table records every transition as a separate row. Each row has the status code, the user who made the change, a timestamp, and optional notes. The current status is derived by querying the most recent row. I implemented this pattern across the API layer. Every status transition became an insert operation rather than an update. It took some adjustment to shift from mutable state to event sourced state, but the benefits were immediate. Auditing became straightforward. The state machine also became easier to implement because each transition is a simple insert with a business logic check, not a conditional update. The schema has seventeen status codes covering the full lifecycle: received, claimed, under assessment, pending secretariat review,
开发者
Iran abused mobile networks’ vulnerabilities to locate US military in the Middle East, report says
The Iranian government exploited well-known flaws in cellphone networks to locate and then strike U.S. military personnel in the build-up and beginning of the war.
AI 资讯
Meta's Noninvasive Brain–Computer Interface Brain2Qwerty Achieves 61% Accuracy
Meta recently open-sourced Brain2Qwerty v2, a noninvasive Brain–Computer Interface (BCI) that can decode sentences from thoughts using electroencephalography (EEG) or magnetoencephalography (MEG) signals from the brain. In evaluations, the system achieved a word accuracy rate 61% on average, compared to 8% for other non-invasive methods. By Anthony Alford
AI 资讯
A Differential Test Harness for Native vs. Generic XDP: Methodology and Baseline
Native XDP and generic SKB-mode XDP are not the same thing in practice. The same BPF program can pass the verifier and still behave differently depending on which mode the kernel uses, this could be a different verdict, different frame bytes, or different metadata. This post ships three things: an open differential test harness, a fixed eleven-packet corpus, and a simple way to classify the differences it finds. A tagged release lets anyone reproduce the virtio/veth baseline on Linux 6.8. The operational risk is straightforward. A firewall or rate-limiter validated only under native XDP can fall back to generic mode on an unsupported driver, a veth port, or after a reload. You keep the same bytecode, but behaviour can change, often without a clear error line. What this release includes: A harness loop: corpus → inject on the RX path → native vs generic sweep → xdpdump capture → compare.py manifest, comparing both the captured frame bytes and the XDP verdict ( PASS / DROP / TX / REDIRECT ). A deterministic corpus with eleven embedded test IDs ( 0xA001 – 0xA005 , 0xA007 – 0xA00C ; 0xA006 is intentionally omitted as a reserved gap in the generator). An operational divergence taxonomy (Class A / B / C). A virtio/veth smoke gate on Linux 6.8; now gating on frame bytes and verdict agreement that shows the full path is reproducible end to end. Scope for this post: native vs generic XDP on the virtio_vm profile only (five BPF programs, pinned manifests). This is part 1 of 2; it establishes the harness and an instrument-validity baseline; a follow-up post covers bare-metal divergence results. Physical NIC results are not part of this baseline. Ordinary conformance checks stop at “did the program load?” Differential testing asks a sharper question: given identical input packets, do the backends produce the same observable outcome at the hook? Background: native vs generic XDP Both modes load the same BPF object. They diverge at the hook point and in how the packet is represen
开发者
The US government warns that Russia state hackers are coming after your router
With residential proxies all the rage, CISA urges router users to be vigilant.
AI 资讯
They Asked for My AI Rules. But I Could Not Just Hand Them Over.
A team lead announces that the team will start using AI-assisted development. Everyone nods. Nobody asks what that actually means on Monday morning. Some times ago I was in that position. A project I was working on needed to start using AI-assisted development, and the team was new to it. Nobody had rules written down for an agent to follow. Nobody had skills defined for it to load. There was no shared idea of how this should work inside our specific repo. Someone had to go first. That someone was me. The rules worked because I built them for one repo I spent time curating a set of rules and skills for that project. Not generic ones. I shaped them tightly around how that repo was actually structured, its conventions, its layout, the things a new engineer usually has to learn by asking around. I wanted an agent working inside that codebase to already know what a human teammate would have picked up in the first two weeks. I gave a demo. It landed well. Well enough that it got shared further across team, as something other teams could learn from. I gave the demo again. Same reaction. Then a few developers reached out for the actual rules and skills files. I said sure, and then I actually looked at what I would be handing them. The problem showed up the moment other people wanted in It was not copy-paste-able. The rules referenced folder names, module boundaries, and patterns specific to one repo. Handing them over as-is would have meant handing over advice that was wrong for their project, dressed up as a shortcut. So I told them to use it as a reference. Look at the structure, understand the reasoning, adapt it to your own repo. That is correct advice. I watched people nod at it and then quietly missing it. I was solving the wrong problem the whole time I had been thinking about this as a documentation problem. Write good rules, explain them well, let people copy the idea. What I actually had was a generation problem. The rules that worked were the ones rendered speci
AI 资讯
PHP Speaks QUIC Now, and OpenSSL Did the Hard Part
I released php-quic 1.0.0, a PHP extension that gives you raw QUIC transport with first-class access to streams. It links against the same OpenSSL that PHP already links against, and that is the whole trick. Why This Was Awkward Before QUIC is not a protocol you bolt on in userland. It is TLS 1.3, congestion control, loss recovery, and stream multiplexing, all riding on UDP, and all of it has to be right before you can send a single useful byte. You could get there from PHP if you were willing to bind to a foreign QUIC library like ngtcp2 or quiche through FFI. That works, but now your PHP app carries a second TLS stack, a second set of CVEs to track, a build story that involves Rust, and a version matrix that has nothing to do with the one your distro maintains. For a language whose entire deployment story is "the package manager handles it," that is a lot of rope. What Changed OpenSSL 3.5 shipped a native QUIC stack. Client and server, in the library PHP is already built against. That reframes the problem. The extension is no longer "embed a QUIC implementation into PHP." It is "expose the QUIC that is already sitting there." No new TLS stack, no FFI layer, no Rust toolchain in your build. If your OpenSSL is patched, your QUIC is patched. The requirements fall out of that directly: PHP 8.4 or newer (8.5 on Windows), NTS or ZTS OpenSSL 3.5.0 or newer, built with QUIC support Transport, Not HTTP/3 The thing I most wanted to avoid was shipping an HTTP/3 client and calling it a QUIC library. QUIC is a transport. HTTP/3 is one protocol that runs on it, and it is not the interesting one for everybody. DNS-over-QUIC runs on it. So does anything you want to invent that needs multiplexed, ordered, loss-recovered streams without head-of-line blocking across them. So php-quic hands you connections and streams, and stays out of the framing business. If you want HTTP/3, you build HEADERS frames and QPACK on top of it, and the README has a worked example. If you want something
AI 资讯
Wi-Fi 8 Explained: Features, Release Date, and More
Chipset makers and router manufacturers are talking about Wi-Fi 8, but what is the new standard, and when will it arrive?
产品设计
As TV-tracking app TV Time shuts down, its founder builds Bingers, a new home for fans
The creator of TV Time is building a successor app that will let users import their watch histories and preserve the community that formed around discussing their favorite shows.
AI 资讯
Demystifying LDAP: The Digital Phonebook of Your Network
If you have ever logged into a corporate computer, searched for a colleague in your company’s email directory, or used a single set of credentials to access dozens of different internal applications, you have likely interacted with LDAP . Standing for Lightweight Directory Access Protocol , LDAP is an open, vendor-neutral, industry-standard application protocol for accessing and maintaining distributed directory information services over an IP network. In simpler terms, it is the underlying language that allows different systems and applications to communicate with a central directory to find information about users, devices, and permissions. Think of LDAP as a highly organized, digital phonebook. When an application needs to know if "John Doe" is a valid user and what his password is, it uses LDAP to ask the phonebook. How LDAP Organizes Data Unlike traditional relational databases (like SQL) that store data in tables, LDAP stores data in a hierarchical, tree-like structure known as the Directory Information Tree (DIT) . This makes it incredibly fast at reading and searching for information, which is exactly what an authentication system needs to do millions of times a day. Here are the core components of this structure: Root: The top level of the directory tree, usually representing the organization (e.g., dc=example, dc=com ). Branches (Organizational Units - OU): Categories or departments within the organization (e.g., ou=Marketing , ou=Servers ). Leaves (Entries): The actual objects being stored, such as a specific user, printer, or computer. Attributes: The specific pieces of data tied to an entry. For a user entry, attributes might include givenName (first name), mail (email address), and userPassword . Every entry in an LDAP directory has a unique identifier called a Distinguished Name (DN) . It acts like an absolute file path. For example, John Doe’s DN might look like this: cn=John Doe, ou=Marketing, dc=example, dc=com How Applications Talk to LDAP When an
AI 资讯
EEM 101: On-Box Automation That Runs Even When Your NMS Doesn't
This is Part 1 of a 5-part series on Cisco EEM. We start here with the fundamentals and a few working applets, then build toward self-healing networks, automated diagnostics, compliance guardrails, and a complete real-world deployment. Ask ten network engineers what they use EEM for, and nine will say the same thing: "Oh, I have an applet that auto-recovers err-disabled ports." Then they never touch it again. That's a shame, because Embedded Event Manager is one of the most capable tools already sitting inside every Cisco IOS device you own — and almost nobody uses more than 1% of it. It's a full automation engine that lives on the box . No external server. No API gateway. No orchestration platform. Just the router or switch, watching itself, ready to react the instant something happens — even if the WAN is cut, the NMS is down, and it's three in the morning. This series is about using that other 99%. By the end you'll have a toolkit of applets you can deploy and, more importantly, a way of thinking about on-box automation. But we start at the foundation: what EEM actually is, how it's put together, and why "on the box" is a bigger deal than it sounds. What EEM actually is Embedded Event Manager is an event-driven automation framework built into Cisco IOS, IOS-XE, and NX-OS. Strip away the jargon and it's a very simple idea: When something happens, do something about it — automatically, on the device itself. That "something happens" is an event . That "do something" is one or more actions . Bundle an event with its actions and you have an applet — the basic unit of EEM. That's the whole model. The power comes from how many different things can be an event , and how much an action can do. Events EEM can watch for include: A syslog message matching a pattern (an interface flapping, an HSRP state change, a config being saved). An SNMP OID crossing a threshold (CPU over 85%, a power supply going absent, temperature rising). A CLI command being entered (someone typing wr
AI 资讯
What Happened When I Let Several AI Agents Loose in One Repo
Originally published at blog.whynext.app . Work with AI agents for a while and the ambition comes naturally. While one session fixes a bug, another can refactor, and a third can investigate an issue, right? You can spin up as many models as you like, so productivity should scale to match. That's how I started too. And within a week I learned that the real enemy of parallel agents isn't the models' skill. It's the working directory they share. HEAD is a global variable The cause fits in one sentence. When multiple sessions share a single git checkout, the current branch becomes everyone's global variable. Picture two people working on one computer at the same time and the absurdity is obvious, but that thought never occurred to me while spinning up agents. With one session per terminal tab, they look isolated from each other. But there is one filesystem, and one HEAD. The moment one session runs git checkout , the ground shifts under every other session. The incidents from that week fell into clear types. Branch hijacking. While session A was working on a topic branch, session B switched branches to do its own work. A committed without knowing, and the commit landed on top of B's branch. It happened in the other direction too: right as A was about to commit, the branch had been switched to develop, and only the hook that blocks direct commits to protected branches saved it. Without the hook, it would have gone straight in. Orphaned commits. Session B deleted session A's topic branch during a cleanup pass. A's commits became orphans belonging to no branch, and I dug through the reflog, found the commit hashes, and recovered them with cherry-pick. Lucky that it worked; if the reflog had expired or I hadn't found them, the work would have simply evaporated. Staging contamination. At the moment session A was creating a commit, a file deletion that session B had staged was sitting in the staging area alongside it. Committed as-is, B's deletion would have been folded into
AI 资讯
Pipeline, Flow, or Chain? Picking the Right Tool to Wire LLM Calls Together
In the previous post I argued that agents are great planners and DAGs are great executors . This one is the practical follow-up: when you actually sit down to wire several LLM calls together, what tool do you reach for? Because the moment one prompt's output feeds the next, you've built a workflow — whether you call it that or not. download transcript → summarize → translate (tool) (LLM) (LLM) That tiny pipeline is already the whole problem in miniature: a non-LLM step (fetch a YouTube transcript), then a model call, then another model call that depends on the first. Run it as one giant prompt and you lose visibility; split it into steps and you gain debuggability — at the cost of more calls and more state to manage. The naming trap Half the confusion is vocabulary. The same idea ships under a dozen labels: Name What it whispers Chain sequential, output → input Pipeline stages, data flowing through Flow branches and conditions Workflow general orchestration Agent workflow the model also decides The word sets expectations. "Chain" promises a straight line; "agent workflow" promises the thing might re-plan on you mid-run. Pick the label that matches how much autonomy you're actually handing over — calling a deterministic two-step pipeline an "agent" only invites disappointment. The real choice: library or orchestrator? There are two families of tools, and they solve different problems. LLM-native chaining libraries — LangChain , LlamaIndex Workflows , Azure Prompt Flow , or visual layers like Flowise . These understand LLM-specific concerns out of the box: prompt templating, passing context between steps, token budgets, streaming, retries on a flaky model. General orchestrators — Airflow , Prefect , AWS Step Functions , Azure Logic Apps . These treat each LLM call as just another task in a DAG, and give you the heavyweight reliability machinery: durable state, scheduling, checkpointing, audit trails, human approval. The rule of thumb that falls out of the last post: F
产品设计
Are you filthy enough for a $700 portable shower?
Hot showers, like electricity, are a luxury that's easy to take for granted. That all changes after a few nights camping at a music festival, a week toiling at a backcountry job site, or overlanding all summer in the great unknown. An itchy scalp and the vague smell of warm clams suddenly make the idea […]
AI 资讯
My First Experience with SigNoz
Modern applications, especially AI agents and distributed systems, need more than logs to understand what is happening. That's why I explored SigNoz, an open-source observability platform built on OpenTelemetry. Setting up SigNoz with Docker was simple. After connecting a sample application, I could view logs, metrics, and traces from a single dashboard within minutes. My favorite feature is distributed tracing. Instead of guessing where requests slow down or fail, SigNoz clearly shows the complete request journey across services, making debugging much easier. The built-in dashboards provide valuable insights into CPU usage, memory, request latency, throughput, and error rates. Having centralized logs alongside metrics and traces saves time by eliminating the need to switch between multiple tools. I also liked the alerting feature, which helps detect issues before they affect users. For AI applications, observability is essential. AI agents make multiple API calls, use tools, and perform complex workflows. SigNoz makes it easier to understand each step, identify failures, measure latency, and optimize performance. Overall, my experience with SigNoz was excellent. It combines logs, metrics, traces, dashboards, and alerts into one intuitive platform. Among all its features, distributed tracing impressed me the most because it provides deep visibility into application behavior and simplifies troubleshooting. I'm excited to use SigNoz in future AI and cloud-native projects.