On this page

Practical Home Network Architecture: Wired Mesh, Single-Arm Side Router, and Fail-Open

The goal of this network is not to pile up devices, but to solve three problems simultaneously: stable coverage in multiple rooms, device-based proxy path selection, and preventing the side router from dragging down the entire home network when it fails. The final structure is: Optical modem bridging → Main router PPPoE dial-up → 4 APs with wired backhaul; The N100 single-port device handles transparent proxy and DNS, while the core workstation bypasses the side router and manages its own proxy.

This article serves as both an architectural review and a design specification that you can use to check your own network. Hostnames, SSIDs, subscription addresses, and public nodes in this document have been generalized; .1, .7, .8, etc., are used only to illustrate role relationships within the same private network.

Design Conclusions First

  • Mesh nodes should use wired backhaul whenever possible; wireless roaming cannot compensate for congestion in the backhaul link itself.
  • Traffic for a single-arm side router enters and exits through the same LAN interface; return path symmetry and ICMP Redirects must be handled separately.
  • When DNS, transparent proxy, and DHCP gateway are coupled, a Fail-Open design should be implemented; if the proxy fails, it can degrade gracefully, but it must not cause a network outage for the entire house.
  • Key workstations can connect directly to the main router and run their own TUN, isolating the fault domain from the whole-house transparent proxy.
  • Configuration should be derived from a single source of truth; target endpoints only maintain their own DNS, TUN, and inbound differences.

1. Physical Topology

The optical modem performs only optical-electrical conversion (bridging, no dial-up, routing, or NAT); the public IP goes directly to the main router's PPPoE interface, avoiding double NAT. The whole house is approximately 120m² with four rooms. A single AP cannot cover all rooms (especially the master bedroom and secondary bedroom, which are separated by two load-bearing walls). Four APs with wired Mesh cover dead zones + unified SSID for seamless roaming. All APs use wired backhaul, not occupying wireless bandwidth.

Home Network Physical Topology (v2.1) · 120m² Four Rooms · 4 AP Wired Mesh Coverage Internet GPON · Telecom ONT Optical Modem · Bridging Main Router .1 (RP01) PPPoE Dial-up · NAT · DHCP · Mesh Root All Wired Backhaul Living Room .62 RC06 · Entrance Area Master Bedroom .67 RP03 · Two Walls Away Study .80 RP03 · N100 Hangs Here Secondary Bedroom .227 RP03 · Furthest End N100 .7 (Side Router) Single Port · Hangs on Study AP LAN Workstation .8 (WiFi)

2. Mesh Network

NodeIPHardwareLocationCoverage ChallengeBackhaul
root.1RP01EntranceLiving Room Center
leaf.62RC06Living RoomCovers Entrance AreaWired
leaf.67RP03Master BedroomSeparated by Two Load-Bearing WallsWired
leaf.80RP03StudyCore Equipment AreaWired
leaf.227RP03Secondary BedroomFurthest, No Signal from Single APWired

On the wireless side, one main SSID (5 GHz for daily devices) and one independent 2.4 GHz IoT SSID are used. Whether the IoT network is hidden does not constitute a security boundary; true isolation should rely on guest networks, VLANs, or firewall policies.

3. Key Hosts

DeviceIPRoleConnectionOS
ONT— (Bridged, No IP)Optical-Electrical ConversionFiber In, Ethernet OutTelecom GPON
Xiaomi Main Router.1PPPoE/NAT/DHCP/Mesh RootWAN connects to ModemMiWiFi (RP01)
N100 Side Router.7Transparent Proxy + DNS (AdGuard Home)Wired Single Port, Hangs on Study AP LANiStoreOS
Core Workstation.8Development & Self-Hosted Services, Static Gateway Points to .1Wi-Fi, Connects to Study APLinux
Old Node.9Retired Side Router, Maintenance Entry OnlyWi-FiWindows

Key Design: The static gateway of the core workstation (.8) points to the main router (.1), unaffected by the side router's transparent proxy. It runs its own TUN-mode mihomo and uses DNS that returns real addresses, thus forming two independent fault domains from ordinary home devices.

4. DHCP and DNS

  • Gateway: DHCP defaults to issuing .7 (N100); ordinary devices are forwarded via the side router. The core workstation is an exception, with its static gateway pointing to .1.
  • DNS: DHCP only publishes .7 (AdGuard Home on N100). Do not issue public DNS as a "backup" simultaneously, because clients can bypass the primary DNS, making filtering and splitting results unpredictable. Fail-Open temporarily takes over :53 during component failures.
  • Lease Time: 1–2 hours. Shorter leases facilitate faster convergence after modifying gateway configurations but cannot replace gateway high availability.
  • Address Pool: 192.168.31.5–250.

Normal DNS Path

DNS Path: Client → AdGuard → mihomo fake-ip Split → Upstream Client AdGuard :53 Ad Filtering + Cache · Docker mihomo :1053 fake-ip Split Domestic: UDP 223.5.5.5 International: DoH 1.1.1.1 In fake-ip mode, AdGuard receives upstream responses all in the 198.18.x range; mihomo internally maps and restores the real IP. This solution does not verify DNSSEC at the AdGuard layer; fake-ip is a synthetic response, and the entire resolution chain must be verified separately before enabling. DHCP only publishes AdGuard; whether DoH/DoT bypass exists still needs to be confirmed via traffic observation.

5. Traffic Path

Normal Mode

Traffic Path: Side Router Proxy + Domestic Direct Connection Dual Path Client N100 (.7) · nftables prerouting Hairpin: MASQUERADE changes source → .7 ① Mainland IP Firewall return Does not enter mihomo, direct connection home ② Other Traffic mihomo Split Domestic Direct / International via Proxy Main Router .1 PPPoE → Public Network Workstation (.8) Gateway → .1, Direct to Main Router, Bypasses Side Router ① Mainland IPs are returned at the firewall prerouting stage (~3.7k chnroute), physically not entering mihomo, providing hard protection for domestic traffic.

① Mainland IPs are returned at the firewall layer, physically not entering mihomo — Hard protection for domestic traffic. The single-port hairpin (entering and exiting via the same br-lan) forwards back to .1, MASQUERADE must change the source to .7, otherwise asymmetric return paths will directly cause network outages.

② fake-ip misses CN domains in geosite (obtaining 198.18.0.0/15 addresses) will still enter mihomo, which can be caught by the GEOIP,CN,DIRECT rule at the end of the ruleset after resolving the real address. The core workstation uses its own TUN and real-address DNS, not relying on this path.

Fail-Open Mode (mihomo/AdGuard Down)

Fail-Open: Degrade to Direct Connection When Proxy Components Fail Client N100 (.7) · Still Gateway nft redirect removed · MASQ Injection Main Router .1 PPPoE · DNS Takeover Public Trigger Condition: mihomo or AdGuard process abnormal → nikki-failopen (procd) self-healing Behavior: nftables redirect entire table deleted → All traffic passes directly to main router → DNS :53 redirected to main router No Proxy · No Ad Filtering · All Direct —— Degraded Fallback, No Network Outage

This Fail-Open has clear boundaries: it relies on daemons still running on the N100, covering only software failures such as mihomo or AdGuard Home exiting or freezing. When the N100 loses power, the kernel hangs, or the LAN link is interrupted, .7 as the default gateway becomes completely unreachable, still causing ordinary clients to lose connectivity. To cover this layer of failure, VRRP/Double-Active Hot Standby is required, or the main router automatically changes the DHCP gateway after health checks; the current architecture does not implement this.

6. Splitting Strategy and Domestic Traffic Protection

A CN domain missed by geosite → MATCH,PROXY → US node reconnecting to a domestic server → GFW identified "domestic traffic" and blocked the VPS IP occurred previously. Now using Dual-Layer Protection:

Layer 1 (Hard, Firewall): bypass_china_mainland_ip=1 (v4) fills the nft china_ip set (~3.7k chnroute). Mainland IPs are returned at prerouting, physically unable to reach mihomo, regardless of whether the domain matches geosite.

  • Single-port hairpin requires table inet bypass_masq to MASQUERADE forwarded traffic source to .7.
  • v6 firewall bypass is temporarily disabled (to avoid v6 hairpin issues); v6 CN traffic falls back to mihomo GEOIP,CN.

Layer 2 (Fallback, mihomo Rules): End of ruleset GEOSITE,cn,DIRECTGEOIP,CN,DIRECTMATCH,PROXY. CN domains that missed fake-ip enter mihomo, where GEOIP,CN intercepts after resolving the real IP.

Key sysctl

ParameterValueReason
net.ipv4.conf.*.send_redirects0Otherwise .7 sends ICMP Redirects, causing clients to bypass .7 and connect directly to .1, forming a "dual path": same target client direct connection + mihomo dial-up coexist, triggering server PAWS to discard the one with the smaller timestamp after NAT via the same public IP on the main router → i/o timeout storm (the real culprit for apps like Xianyu freezing). Applies to all single-arm/hairpin side router solutions, not just this one.
net.ipv4.conf.*.rp_filter0Allows asymmetry, cooperating with hairpin

Outbound Lines

Three VPSs are distributed across different network lines; differences in latency and stability come from the QoS levels of the return lines:

LineFull NamePriorityCharacteristicsSuitable For
CN2 GIAChina Telecom Next Gen CarrierHighestTelecom top-tier line, entire CN2 backbone without passing through 163 network, lowest QoS, basically no speed drop during evening peakMain nodes requiring low latency/stability
9929China Unicom PremiumMedium-HighUnicom premium line, similar to CN2 GIA but via Unicom backbone, optimal for Unicom broadband users in the NorthOptimal direct connection for Unicom users
4837China Unicom StandardNormalUnicom standard international line, obvious congestion during evening peak but cheapBackup/Cold Backup/Budget-sensitive

How to Select Nodes and Protocols

Do not hardcode vendors, package prices, or specific speed test results in the architecture document: this information changes quickly and cannot represent the experience of different regions, operators, and evening peak periods. A more robust selection method is to continuously measure using your own access network:

  1. Record RTT, jitter, packet loss rate, and TCP/UDP throughput separately during weekdays and evening peaks.
  2. Choose different upstreams or different routes for primary and backup nodes to avoid the scenario where multiple nodes appear to be independent but actually share the same fault domain.
  3. Test both TCP and UDP protocols; protocol performance depends on link quality, and long-term conclusions cannot be derived from a single latency test.
  4. Switching strategies should consider business experience. Automatic switching is suitable for scenarios where node quality is similar; when quality differences are large, manual switching makes it easier to detect degradation.
  5. Feed raw results to Prometheus Blackbox Exporter or similar probes for storage, and make decisions based on percentiles over a week or more rather than instantaneous minimum values.

This network chooses a manual Selector: alert when the primary node is abnormal, and switch after confirmation by the maintainer. The cost is that recovery is not fully automatic, but the benefit is that it won't silently drop to a node that "can connect but has a poor experience."

Speed-Up Items

  • tcp-concurrent: true: Concurrent dial-up resolves multiple IPs and picks the fastest.
  • QUIC reject rule intentionally retained: AND,(DST-PORT,443),(NETWORK,UDP),(NOT,GEOSITE,cn),REJECT forces external HTTP/3→h2, curing "QUIC-over-Hy2 idle reuse hang"; enabling it will cause recurrence.

Why not enable hard bypass for IPv6: The key to v4 hard bypass is hairpin MASQUERADE (changing source to .7 to ensure symmetric return), which relies on N100 having a fixed internal v4 address. However, v6 addresses are dynamically assigned via SLAAC, with no stable internal address to serve as an SNAT anchor — symmetric return for hairpin cannot be reliably achieved on v6; forcing it will only cause random disconnections. Therefore, v6 CN currently only relies on the mihomo ruleset layer GEOIP,CN for fallback, not bypassing via firewall prerouting. Monitoring: Key components of N100, core workstation, and main router are integrated into Prometheus + Grafana, see monitoring.md. Node availability is probed by Prometheus Blackbox Exporter; the manual confirmation switching strategy is retained here.

7. N100 Key Components

ComponentAddress/PathDescription
mihomo Kernel/usr/bin/mihomo, procd via /etc/init.d/nikkiTransparent Proxy + TUN
mihomo API127.0.0.1:9090Health Probe
mihomo Mixed:7890 (SOCKS5+HTTP)Explicit Proxy Entry
mihomo Redir:7891Transparent Proxy Redirect Inbound
mihomo DNS:1053 (fake-ip)AdGuard Upstream
Nikki Dashboardhttp://<side-router-ip>:9090/uiWeb Console, Intranet Access Only
AdGuard HomeDocker host network, http://<side-router-ip>:8083DNS Ad Filtering, Upstream points to :1053
failopen Daemon/usr/local/sbin/nikki-failopen.sh, procdHealth Check + Auto Fail-Open
CN Bypass SNAT/etc/nikki/scripts/bypass-masq.{nft,sh} + firewall includeHairpin masquerade, Persistent

N100 Migration Motivation and Hardware Selection: The original side router ran on a desktop PC via WiFi; WiFi jitter caused whole-house outages. Switched to N100 (low-power x86, iStoreOS, single Gigabit port) hanging on the Study AP LAN port as a wired side router, decoupling from WiFi henceforth.

8. nftables Structure

Processing Order (prerouting → forward → postrouting):

nftables Processing Order: prerouting → forward → postrouting Inbound Packet fw4 forward (policy drop) nikki dstnat / mangle_prerouting Transparent Proxy Entry · Split by Destination Mainland IP / Private → return, bypass proxy (direct connection) Other Traffic → DNAT :7891 or Mark TUN bypass_masq postrouting Hairpin SNAT Anchor CN Direct Traffic → MASQUERADE (src→.7, symmetric return) fw4 srcnat_lan (docker MASQUERADE) Outbound Mainland IPs are returned at prerouting, physically not entering mihomo, regardless of whether the domain matches geosite. bypass_masq is independent; nikki restart/fail-open does not affect the symmetric SNAT anchor for return paths.

table inet fw4 (OpenWrt Firewall)

  • forward: policy drop; allow TUN traffic + LAN→WAN forwarding
  • srcnat_lan: docker MASQUERADE

table inet nikki (Transparent Proxy Rules)

  • china_ip set: ~3.7k chnroute CIDRs (filled by bypass_china_mainland_ip=1)
  • dstnat / mangle_prerouting_lan: Mainland IP / Private / 198.18 match → return bypass; others DNAT TCP→:7891 or Mark TUN
  • mangle_output: Local outbound → TUN
  • Entire table deleted during fail-open

table inet bypass_masq (Hairpin SNAT for CN-IP Bypass)

  • postrouting (nat hook, priority srcnat+5): iifname br-lan oifname br-lan ip daddr != {private+198.18+multicast} masquerade
  • Only matches public CN direct traffic bypassed by china_ip that needs forwarding back to .1, changing source to .7 to ensure symmetric return
  • Independent of table nikki, nikki restart does not affect it; persistence relies on firewall.bypass_masq include

table inet failopen (Fault Injection, Deleted on Recovery)

  • srcnat: MASQUERADE <lan-cidr> → non-local
  • dns: DNAT :53 → .1:53

9. Self-Hosted Services and Fault Domains

The following services currently rely on the core workstation's Wi-Fi. wifi-watchdog (systemd timer) can recover brief RF or driver anomalies, but it cannot turn a wireless link into a high-availability infrastructure; long-running entry and monitoring services should be migrated to wired nodes.

ServicePurposeAvailability
DERPTailscale RelayHigh
ratholeIntranet Tunnel (see rathole-tunnel.md)High
paste/mdserveNote SharingMedium
PrometheusMonitoring CollectionMedium
sunshineGame StreamingLow
Local LLMAI Inference (see local-llm.md)Low

10. Daemons

DaemonLocationScenario
nikki-failopenN100 (procd)mihomo/AdGuard process abnormal
Power-On Self-StartN100 (BIOS)Power Recovery
wifi-watchdogCore Workstation (systemd timer)Wi-Fi Driver/RF Anomaly
sync-mihomo-to-routerCore Workstation (systemd timer)Source → Side Router Config Drift
sync-subscribeCore Workstation (systemd timer)Source → Mobile Config Drift

Configuration Derivation Pipeline

There are three places in the home that need mihomo configuration: Core Workstation (TUN self-proxy), N100 (Whole-house transparent proxy), and Mobile Import File. The node list, proxy groups, and splitting rules of the three must be consistent, but DNS, TUN, and inbound methods are all different. If maintained independently, drift is inevitable.

Solution: Manually edit <config-root>/config.yaml only, which contains proxies, proxy-groups, and rules; two timer-driven scripts derive target configurations from it.

#1 Local Machine: Use the source directly. TUN device Meta + Local AdGuard + fake-ip + controller.

#2 N100 Side Router (sync-mihomo-to-router.sh, timer 03:45):

  • Extract only proxies/proxy-groups/rules segments from the source → /etc/nikki/profiles/home.yaml
  • Validate source with mihomo -t locally → scp to N100 → nikki -t validate → Backup old file (with timestamp) → Auto rollback on validation failure → Reload Nikki
  • DNS/TUN/sniffer are injected by N100 local UCI mixin, not entering the profile — these are target-end specific and should not be overwritten from the source

#3 Mobile Configuration (sync-subscribe.sh):

  • Output clash.yaml (Clash Import) + sub.txt (v2rayN base64 share link)
  • De-localization sanitization: Remove external-controller + secret (leak means controlled), tun entire section (phones don't need it), nameserver:127.0.0.1 (roaming devices can't reach), PROCESS-NAME rules (phones never match)
  • DNS replaced with fake-ip + public DoH, international domains resolved via exit to prevent leakage
  • If distributed via public network, the entry uses an independent domain and unpredictable path token; the Web server only exposes derived files, not the source, controller secret, or directory listing

The two timers run staggered to avoid reading or writing target configurations simultaneously. After modifying the source, you can also manually execute the corresponding script; scripts must remain idempotent and complete syntax validation and backup before replacement.

11. Post-Launch Verification Checklist

Put the side router address into the environment variable first to avoid exposing real addresses in example commands:

SIDE_ROUTER_IP=192.168.31.7

At least verify the following items in normal mode:

# Whether the client's default route points to the side router
ip route show default

# Whether DNS only passes through AdGuard and gets the expected fake-ip response
dig @"$SIDE_ROUTER_IP" example.com

# Confirm forwarding, redirect, and SNAT rules exist on the side router
ssh "root@$SIDE_ROUTER_IP" 'nft list ruleset'

# Whether the two processes and their listening ports are alive
ssh "root@$SIDE_ROUTER_IP" 'pgrep -a mihomo; ss -lntup'

Fail-Open should be rehearsed during maintenance windows, not guessed after a failure occurs. Stop mihomo and AdGuard Home separately, confirm that the daemon revokes transparent proxy rules, takes over DNS, and clients can still connect directly; then restore services and confirm that rules are not injected repeatedly. Finally, simulate N100 power loss separately to verify that monitoring indeed alarms, while accepting the fact that ordinary clients will lose connectivity under the current architecture.

ScenarioExpected Result
mihomo process exitsAuto-revoke redirect, degrade to direct connection
AdGuard Home process exits:53 taken over by available DNS, clients continue resolving
N100 restarts and recoversConfiguration injected only once, routing and DNS return to normal mode
N100 power loss or port disconnectNo gateway hot standby currently, ordinary clients lose connectivity and trigger alarm
Core Workstation offlineOrdinary home devices unaffected; self-hosted services offline

12. Known Risks

RiskImpactMitigation
Core Workstation WiFi Single PointSelf-hosted services like tunnels and relays go offline simultaneouslyLong-term migration to wired nodes; watchdog is only a short-term band-aid
N100 Single Port HairpinAsymmetric return path in single-arm topology must breakMASQUERADE + bypass_masq nft table ensures symmetric return
mihomo/AdGuard Process HangWhole-house outage (DHCP gateway still points to .7)nikki-failopen (procd) process-level self-healing
N100 Hardware, Power, or Link FailureDefault gateway unreachable, ordinary clients lose connectivityCurrently only monitoring alarms; introduce double-active gateway or main router side auto-switching later
Main Router Hardware/Firmware FailureWhole-house outage (PPPoE+NAT+DHCP all down)No hot standby currently; original plan for N100 as main router not implemented
Optical Modem BridgingONT only does optical-electrical conversion, no dial-up/routing/NAT, public IP goes directly to main routerBasically not a failure source, no double NAT

Detailed evaluation and recovery procedures see network-recovery.md.

Change Log

DateChange
2026-06-21N100 side router online, old workstation side router retired; DHCP gateway/DNS switched from .8 to .7; Deployed Fail-Open and Wi-Fi watchdog
2026-06-24Public subscription fix: Original config copy caused leakage of local machine DNS + management port secret + tun, sync-subscribe.sh added de-localization sanitization; Side router profile rerun refreshed; Added sync-mihomo-to-router.timer
2026-06-27Disabled ICMP send_redirects: Cured Xianyu and other App freezes (root cause of dual-path PAWS packet loss storm); CN-IP firewall bypass online (bypass_china_mainland_ip=1 + table inet bypass_masq); tcp-concurrent + CN DNS changed to plaintext UDP 223.5.5.5; Node insights
2026-08-11Public version document generalized hosts, SSIDs, subscription entries, and node info; Added design principles and verification methods