---
title: 家庭ネットワーク構築の実践：有線Mesh、単臂バイパスルーターとFail-Open
url: https://doc.liz6.com/ja/homelab/network-architecture
locale: ja
area: homelab
tags:
- 家庭ネットワーク
- Mesh
- バイパスルーター
- OpenWrt
- mihomo
- nftables
- homelab
date: 2026-08-11
modified: 2026-08-11
description: 家庭ネットワーク構築の実践：光モデムブリッジ、有線Mesh、N100単臂バイパスルーター、AdGuard Homeとmihomoによるトラフィック分割、およびプロキシコンポーネント障害時の自動ダイレクト接続（Fail-Open）設計。
---

# 家庭ネットワーク構築の実践：有線Mesh、単臂バイパスルーターとFail-Open

このネットワークの目的はデバイスを積み重ねることではなく、以下の3つの問題を同時に解決することにあります：複数部屋での安定したカバレッジ、デバイスごとのプロキシパスの選択、そしてバイパスルーター障害時に家庭全体のネットワークをダウンさせないこと。最終的な構造は以下の通りです：光モデムブリッジ → メインルーターPPPoE接続 → 4つのAP有線バックホール。N100単一ネットワークインターフェースデバイスが透過プロキシとDNSを担当し、コアワークステーションはバイパスルーターを迂回して自身でプロキシを管理します。

本記事はアーキテクチャの振り返りであり、ご自身のネットワークをチェックするための設計書としても機能します。文中のホスト名、SSID、サブスクリプションアドレス、およびパブリックノードはすべて一般化されています。`.1`、`.7`、`.8` などは、同一プライベートネットワーク内の役割関係を説明するためにのみ使用されています。

## 設計上の結論

- Meshノードは可能な限り有線バックホールを使用してください。無線ローミングでは、バックホールリンク自体の輻輳を補うことはできません。
- 単臂バイパスルーターのトラフィックは同じLANインターフェースを出入りするため、戻り経路の対称性とICMPリダイレクトは個別に処理する必要があります。
- DNS、透過プロキシ、DHCPゲートウェイを結合した場合、Fail-Openを設計する必要があります。プロキシが故障しても機能低下可能とし、家庭全体のネットワーク断線を防ぐ必要があります。
- 重要なワークステーションはメインルーターに直接接続し、独自のTUNを実行することで、家庭全体の透過プロキシから障害ドメインを分離できます。
- 設定は1つの真のソースから派生させるべきであり、ターゲット側は自前のDNS、TUN、およびインバウンド設定の違いのみを維持します。

## 1. 物理トポロジー

光モデムは光電変換のみを行い（ブリッジモード、PPPoE接続なし、ルーティングなし、NATなし）、パブリックIPはメインルーターのPPPoEインターフェースに直接接続され、二重NATは発生しません。家庭は約120m²の4部屋構成で、単一APではすべての部屋（特に主寝室と次寝室は2つの耐力壁で隔てられている）をカバーできません。4つのAPによる有線Meshで死角をカバーし、統一されたSSIDでシームレスなローミングを実現します。すべてのAPは有線バックホールを使用し、無線帯域幅を占有しません。

<svg viewBox="0 0 780 420" xmlns="http://www.w3.org/2000/svg" font-family="-apple-system,'Source Han Sans CN','Microsoft YaHei',sans-serif" role="img" aria-label="家庭ネットワーク物理トポロジー">
  <rect width="780" height="420" fill="#ffffff"/>
  <text x="390" y="28" text-anchor="middle" font-size="17" font-weight="700" fill="#1f2933">家庭ネットワーク物理トポロジー(v2.1) · 120m² 4部屋 · 4 AP有線Meshカバレッジ</text>
  <!-- Internet -->
  <rect x="354" y="46" width="72" height="24" rx="12" fill="#e2e8f0"/>
  <text x="390" y="62" text-anchor="middle" font-size="11" fill="#475569">Internet</text>
  <line x1="390" y1="70" x2="390" y2="86" stroke="#94a3b8" stroke-width="1.5"/>
  <!-- GPON -->
  <rect x="330" y="86" width="120" height="30" rx="6" fill="#f1f5f9" stroke="#cbd5e1"/>
  <text x="390" y="106" text-anchor="middle" font-size="11" fill="#475569">GPON · 電信</text>
  <line x1="390" y1="116" x2="390" y2="132" stroke="#94a3b8" stroke-width="1.5"/>
  <rect x="325" y="132" width="130" height="30" rx="6" fill="#e2e8f0" stroke="#94a3b8"/>
  <text x="390" y="151" text-anchor="middle" font-size="11" fill="#334155">ONT光モデム · ブリッジ</text>
  <line x1="390" y1="162" x2="390" y2="182" stroke="#475569" stroke-width="1.8"/>
  <!-- Main router -->
  <rect x="285" y="182" width="210" height="42" rx="8" fill="#dbeafe" stroke="#3b82f6"/>
  <text x="390" y="200" text-anchor="middle" font-size="13" font-weight="700" fill="#1e40af">メインルーター .1 (RP01)</text>
  <text x="390" y="216" text-anchor="middle" font-size="10" fill="#1d4ed8">PPPoE接続 · NAT · DHCP · Meshルート</text>
  <!-- trunk line -->
  <line x1="390" y1="224" x2="390" y2="248" stroke="#475569" stroke-width="1.5"/>
  <line x1="390" y1="248" x2="120" y2="270" stroke="#475569" stroke-width="1.5"/>
  <line x1="390" y1="248" x2="300" y2="270" stroke="#475569" stroke-width="1.5"/>
  <line x1="390" y1="248" x2="480" y2="270" stroke="#475569" stroke-width="1.5"/>
  <line x1="390" y1="248" x2="660" y2="270" stroke="#475569" stroke-width="1.5"/>
  <text x="390" y="264" text-anchor="middle" font-size="10" fill="#64748b">全有線バックホール</text>
  <!-- APs: wider spread each ~160px apart -->
  <rect x="36" y="274" width="164" height="44" rx="6" fill="#dcfce7" stroke="#86efac"/>
  <text x="118" y="294" text-anchor="middle" font-size="11" fill="#166534">リビング .62</text>
  <text x="118" y="309" text-anchor="middle" font-size="9" fill="#4ade80">RC06 · 玄関エリア</text>
  <rect x="210" y="274" width="164" height="44" rx="6" fill="#dcfce7" stroke="#86efac"/>
  <text x="292" y="294" text-anchor="middle" font-size="11" fill="#166534">主寝室 .67</text>
  <text x="292" y="309" text-anchor="middle" font-size="9" fill="#4ade80">RP03 · 2つの壁で隔てられる</text>
  <rect x="384" y="274" width="164" height="44" rx="6" fill="#dcfce7" stroke="#86efac"/>
  <text x="466" y="294" text-anchor="middle" font-size="11" fill="#166534">書斎 .80</text>
  <text x="466" y="309" text-anchor="middle" font-size="9" fill="#4ade80">RP03 · N100設置場所</text>
  <rect x="558" y="274" width="164" height="44" rx="6" fill="#dcfce7" stroke="#86efac"/>
  <text x="640" y="294" text-anchor="middle" font-size="11" fill="#166534">次寝室 .227</text>
  <text x="640" y="309" text-anchor="middle" font-size="9" fill="#4ade80">RP03 · 最遠端</text>
  <!-- N100 hangs off 書斎 -->
  <line x1="466" y1="318" x2="466" y2="344" stroke="#f59e0b" stroke-width="1.8"/>
  <rect x="370" y="344" width="192" height="34" rx="6" fill="#fef3c7" stroke="#f59e0b"/>
  <text x="466" y="360" text-anchor="middle" font-size="11" font-weight="700" fill="#b45309">N100 .7 (バイパスルーター)</text>
  <text x="466" y="373" text-anchor="middle" font-size="9" fill="#d97706">単一ネットワークインターフェース · 書斎AP LANに接続</text>
  <!-- workstation WiFi -->
  <line x1="466" y1="318" x2="380" y2="392" stroke="#94a3b8" stroke-width="1" stroke-dasharray="4 6"/>
  <rect x="310" y="390" width="100" height="18" rx="4" fill="#f8fafc"/>
  <text x="360" y="403" text-anchor="middle" font-size="10" fill="#94a3b8">ワークステーション .8 (WiFi)</text>
</svg>

## 2. Meshネットワーク

| ノード | IP | ハードウェア | 位置 | カバレッジの難所 | バックホール |
|------|-----|------|------|----------|------|
| ルート | .1 | RP01 | 玄関 | リビング中心 | — |
| リーフ | .62 | RC06 | リビング | 玄関エリアをカバー | 有線 |
| リーフ | .67 | RP03 | 主寝室 | 2つの耐力壁で隔てられる | 有線 |
| リーフ | .80 | RP03 | 書斎 | コアデバイスエリア | 有線 |
| リーフ | .227 | RP03 | 次寝室 | 最遠端、単一APでは信号なし | 有線 |

無線側では、メインのSSID（5 GHz、日常デバイス用）と独立した2.4 GHz IoT用SSIDの2つを使用します。IoTネットワークを非表示にするかどうかはセキュリティ境界を構成するものではありません。真の分離は、ゲストネットワーク、VLAN、またはファイアウォールポリシーによって行うべきです。

## 3. 主要ホスト

| デバイス | IP | 役割 | 接続 | システム |
|------|-----|------|------|------|
| ONT | — (ブリッジ、IPなし) | 光電変換 | 光ファイバー入力、イーサネット出力 | 電信GPON |
| 小米メインルーター | .1 | PPPoE/NAT/DHCP/Meshルート | WANは光モデムに接続 | MiWiFi(RP01) |
| N100バイパスルーター | .7 | 透過プロキシ + DNS（AdGuard Home） | 有線単一ネットワークインターフェース、書斎AP LANに接続 | iStoreOS |
| コアワークステーション | .8 | 開発およびセルフホスティングサービス、**静的ゲートウェイは .1 を指す** | Wi-Fi、書斎APに接続 | Linux |
| 旧ノード | .9 | 退役したバイパスルーター、保守用エントリのみ保持 | Wi-Fi | Windows |

> 重要な設計：コアワークステーション（.8）の静的ゲートウェイはメインルーター（.1）を指しており、バイパスルーターの透過プロキシの影響を受けません。独自にTUNモードのmihomoを実行し、実際のアドレスを返すDNSを使用するため、通常の家庭デバイスとは2つの独立した障害ドメインを形成します。

## 4. DHCPとDNS

- **ゲートウェイ**：DHCPはデフォルトで .7（N100）を配布し、通常デバイスはバイパスルーター経由で転送されます。コアワークステーションは例外で、静的ゲートウェイは .1 を指します。
- **DNS**：DHCPは .7（N100上のAdGuard Home）のみを公開します。パブリックDNSを「バックアップ」として同時に配布しないでください。クライアントはメインDNSを迂回できるため、フィルタリングとトラフィック分割の結果が予測不可能になります。コンポーネント障害時には、Fail-Openによって :53 が一時的に引き継がれます。
- **リース時間**：1〜2時間。ゲートウェイ設定変更後の収束を早めるために短いリース時間を使用しますが、ゲートウェイの冗長性を代替するものではありません。
- **アドレスプール**：192.168.31.5–250。

### 通常時のDNSリンク

<svg viewBox="0 0 720 210" xmlns="http://www.w3.org/2000/svg" font-family="-apple-system,'Source Han Sans CN','Microsoft YaHei',sans-serif" role="img" aria-label="DNSリンク">
  <defs><marker id="dnsah" markerWidth="10" markerHeight="8" refX="8" refY="3" orient="auto"><path d="M0,0 L8,3 L0,6 Z" fill="#475569"/></marker></defs>
  <rect width="720" height="210" fill="#ffffff"/>
  <text x="360" y="28" text-anchor="middle" font-size="17" font-weight="700" fill="#1f2933">DNSリンク:クライアント → AdGuard → mihomo fake-ip トラフィック分割 → アップストリーム</text>
  <!-- Client -->
  <rect x="30" y="56" width="80" height="30" rx="6" fill="#e2e8f0"/><text x="70" y="76" text-anchor="middle" font-size="12" fill="#334155">クライアント</text>
  <line x1="110" y1="71" x2="148" y2="71" stroke="#475569" stroke-width="1.5" marker-end="url(#dnsah)"/>
  <!-- AdGuard -->
  <rect x="152" y="48" width="140" height="46" rx="8" fill="#dbeafe" stroke="#3b82f6"/>
  <text x="222" y="67" text-anchor="middle" font-size="12" font-weight="700" fill="#1e40af">AdGuard :53</text>
  <text x="222" y="84" text-anchor="middle" font-size="9" fill="#3b82f6">広告フィルタリング + キャッシュ · Docker</text>
  <line x1="292" y1="71" x2="340" y2="71" stroke="#475569" stroke-width="1.5" marker-end="url(#dnsah)"/>
  <!-- mihomo -->
  <rect x="344" y="48" width="140" height="46" rx="8" fill="#fef3c7" stroke="#f59e0b"/>
  <text x="414" y="67" text-anchor="middle" font-size="12" font-weight="700" fill="#b45309">mihomo :1053</text>
  <text x="414" y="84" text-anchor="middle" font-size="9" fill="#d97706">fake-ip トラフィック分割</text>
  <!-- branch -->
  <line x1="484" y1="58" x2="530" y2="50" stroke="#475569" stroke-width="1.5" marker-end="url(#dnsah)"/>
  <line x1="484" y1="84" x2="530" y2="92" stroke="#475569" stroke-width="1.5" marker-end="url(#dnsah)"/>
  <!-- domestic -->
  <rect x="534" y="34" width="160" height="32" rx="6" fill="#dcfce7" stroke="#86efac"/>
  <text x="614" y="54" text-anchor="middle" font-size="11" fill="#166534">国内: UDP 223.5.5.5</text>
  <!-- international -->
  <rect x="534" y="78" width="160" height="32" rx="6" fill="#ffedd5" stroke="#fdba74"/>
  <text x="614" y="98" text-anchor="middle" font-size="11" fill="#9a3412">国外: DoH 1.1.1.1</text>
  <!-- bottom notes -->
  <rect x="60" y="130" width="600" height="66" rx="8" fill="#f8fafc" stroke="#e2e8f0"/>
  <text x="76" y="152" font-size="11" fill="#475569">fake-ip モードでは、AdGuard が受け取るアップストリーム応答はすべて 198.18.x 帯域であり、mihomo 内部でマッピングして実際の IP に復元します。</text>
  <text x="76" y="170" font-size="11" fill="#475569">本方案では AdGuard レベルで DNSSEC を検証しません。fake-ip は合成応答であるため、有効化する前に解析チェーン全体を個別に検証する必要があります。</text>
  <text x="76" y="188" font-size="11" fill="#475569">DHCP は AdGuard のみを公開します。DoH/DoT の迂回が存在するかどうかは、トラフィック観測を通じて確認する必要があります。</text>
</svg>

## 5. トラフィックパス

### 通常モード

<svg viewBox="0 0 720 320" xmlns="http://www.w3.org/2000/svg" font-family="-apple-system,'Source Han Sans CN','Microsoft YaHei',sans-serif" role="img" aria-label="通常トラフィックパス">
  <defs><marker id="fah" markerWidth="10" markerHeight="8" refX="8" refY="3" orient="auto"><path d="M0,0 L8,3 L0,6 Z" fill="#475569"/></marker></defs>
  <rect width="720" height="320" fill="#ffffff"/>
  <text x="360" y="28" text-anchor="middle" font-size="17" font-weight="700" fill="#1f2933">トラフィックパス: バイパスルータープロキシ + 中国本土直結の二重パス</text>
  <!-- Client -->
  <rect x="30" y="56" width="90" height="32" rx="6" fill="#e2e8f0"/>
  <text x="75" y="76" text-anchor="middle" font-size="12" fill="#334155">クライアント</text>
  <line x1="120" y1="72" x2="168" y2="72" stroke="#475569" stroke-width="1.5" marker-end="url(#fah)"/>
  <!-- N100 -->
  <rect x="172" y="46" width="210" height="52" rx="8" fill="#fef3c7" stroke="#f59e0b"/>
  <text x="277" y="66" text-anchor="middle" font-size="13" font-weight="700" fill="#b45309">N100 (.7) · nftables prerouting</text>
  <text x="277" y="83" text-anchor="middle" font-size="10" fill="#d97706">ヘアピン: MASQUERADE でソースを変更→.7</text>
  <!-- Branch top: CN -->
  <line x1="382" y1="56" x2="430" y2="56" stroke="#475569" stroke-width="1.5" marker-end="url(#fah)"/>
  <rect x="434" y="40" width="130" height="32" rx="6" fill="#dcfce7" stroke="#86efac"/>
  <text x="499" y="60" text-anchor="middle" font-size="11" fill="#166534">① 中国本土IP</text>
  <line x1="499" y1="72" x2="499" y2="96" stroke="#16a34a" stroke-width="1.2"/>
  <rect x="434" y="96" width="130" height="40" rx="6" fill="#f0fdf4"/>
  <text x="499" y="113" text-anchor="middle" font-size="10" fill="#166534">ファイアウォール return</text>
  <text x="499" y="128" text-anchor="middle" font-size="9" fill="#4ade80">mihomo を経由せず、中国本土へ直結</text>
  <!-- Branch bottom: 其余 -->
  <line x1="382" y1="88" x2="430" y2="120" stroke="#475569" stroke-width="1.5" marker-end="url(#fah)"/>
  <rect x="434" y="150" width="130" height="32" rx="6" fill="#dbeafe" stroke="#60a5fa"/>
  <text x="499" y="170" text-anchor="middle" font-size="11" fill="#1e40af">② その他のトラフィック</text>
  <line x1="499" y1="182" x2="499" y2="200" stroke="#3b82f6" stroke-width="1.2"/>
  <rect x="434" y="200" width="130" height="48" rx="6" fill="#eff6ff"/>
  <text x="499" y="218" text-anchor="middle" font-size="10" fill="#1e40af">mihomo トラフィック分割</text>
  <text x="499" y="233" text-anchor="middle" font-size="9" fill="#3b82f6">国内は直結 / 国外はプロキシ経由</text>
  <!-- converge -->
  <line x1="564" y1="116" x2="615" y2="116" stroke="#94a3b8" stroke-width="1.2"/>
  <line x1="564" y1="224" x2="615" y2="224" stroke="#94a3b8" stroke-width="1.2"/>
  <rect x="619" y="144" width="72" height="28" rx="6" fill="#dbeafe"/>
  <text x="655" y="162" text-anchor="middle" font-size="11" fill="#1e40af">メインルーター .1</text>
  <line x1="655" y1="172" x2="655" y2="194" stroke="#475569" stroke-width="1.5" marker-end="url(#fah)"/>
  <rect x="600" y="198" width="110" height="26" rx="6" fill="#e2e8f0"/>
  <text x="655" y="216" text-anchor="middle" font-size="10" fill="#475569">PPPoE → パブリック</text>
  <!-- workstation bypass -->
  <rect x="30" y="234" width="90" height="28" rx="6" fill="#f1f5f9" stroke-dasharray="3 5"/>
  <text x="75" y="252" text-anchor="middle" font-size="11" fill="#64748b">ワークステーション (.8)</text>
  <line x1="120" y1="248" x2="615" y2="248" stroke="#94a3b8" stroke-width="1.2" stroke-dasharray="4 5"/>
  <text x="370" y="264" text-anchor="middle" font-size="9" fill="#94a3b8">ゲートウェイ→.1、メインルーターに直結、バイパスルーターを通過しない</text>
  <!-- bottom notes -->
  <rect x="60" y="282" width="600" height="28" rx="6" fill="#f8fafc"/>
  <text x="360" y="301" text-anchor="middle" font-size="10" fill="#64748b">① 中国本土IPは、china_ip集合（約3.7k chnroute）により、ファイアウォールのprerouting段階でreturnされ、物理的にmihomoに入らず、中国本土へのトラフィックはハード保護されます。</text>
</svg>

> **① 中国本土IPはファイアウォール層でreturnされ、物理的にmihomoに入らない**——中国本土へのトラフィックのハード保護。単一ネットワークインターフェースのヘアピン（同じ br-lan を出入り）で .1 に転送する場合、**必ず MASQUERADE でソースを .7 に変更する必要があります**。そうしないと、戻り経路の非対称性によりネットワークが即座に切断されます。
>
> **② fake-ip で geosite の CN ドメインにマッチし漏れた場合**（198.18.0.0/15 アドレスを取得）は、mihomo に入ります。ルール末尾の `GEOIP,CN,DIRECT` により、実際のアドレスに解決された後にフォールバックできます。コアワークステーションは独自の TUN と実際のアドレス DNS を使用するため、このパスに依存しません。

### Fail-Open モード（mihomo/AdGuard 障害時）

<svg viewBox="0 0 720 210" xmlns="http://www.w3.org/2000/svg" font-family="-apple-system,'Source Han Sans CN','Microsoft YaHei',sans-serif" role="img" aria-label="Fail-Open モード">
  <defs><marker id="foah" markerWidth="10" markerHeight="8" refX="8" refY="3" orient="auto"><path d="M0,0 L8,3 L0,6 Z" fill="#ea580c"/></marker></defs>
  <rect width="720" height="210" fill="#ffffff"/>
  <text x="360" y="26" text-anchor="middle" font-size="17" font-weight="700" fill="#1f2933">Fail-Open: プロキシコンポーネント障害時に直結にフォールバック</text>
  <!-- Client -->
  <rect x="24" y="54" width="76" height="28" rx="6" fill="#e2e8f0"/><text x="62" y="73" text-anchor="middle" font-size="11" fill="#334155">クライアント</text>
  <line x1="100" y1="68" x2="152" y2="68" stroke="#ea580c" stroke-width="1.8" marker-end="url(#foah)"/>
  <!-- N100 failopen -->
  <rect x="156" y="44" width="210" height="48" rx="8" fill="#fef2f2" stroke="#f87171"/>
  <text x="261" y="63" text-anchor="middle" font-size="12" font-weight="700" fill="#b91c1c">N100 (.7) · ゲートウェイとして維持</text>
  <text x="261" y="80" text-anchor="middle" font-size="9" fill="#dc2626">nft redirect 削除済み · MASQ 注入</text>
  <line x1="366" y1="68" x2="428" y2="68" stroke="#ea580c" stroke-width="1.8" marker-end="url(#foah)"/>
  <!-- Main router -->
  <rect x="432" y="48" width="120" height="40" rx="8" fill="#dbeafe" stroke="#3b82f6"/>
  <text x="492" y="66" text-anchor="middle" font-size="12" font-weight="700" fill="#1e40af">メインルーター .1</text>
  <text x="492" y="80" text-anchor="middle" font-size="9" fill="#3b82f6">PPPoE · DNS 引き継ぎ</text>
  <line x1="552" y1="68" x2="614" y2="68" stroke="#475569" stroke-width="1.5" marker-end="url(#foah)"/>
  <rect x="618" y="54" width="72" height="28" rx="12" fill="#e2e8f0"/><text x="654" y="73" text-anchor="middle" font-size="11" fill="#475569">パブリック</text>
  <!-- bottom -->
  <rect x="80" y="106" width="560" height="56" rx="8" fill="#fff7ed" stroke="#fdba74"/>
  <text x="100" y="128" font-size="11" fill="#9a3412">トリガー条件: mihomo または AdGuard プロセスの異常 → nikki-failopen(procd) による自己修復</text>
  <text x="100" y="146" font-size="11" fill="#9a3412">動作: nftables redirect 全体の削除 → 全トラフィックのメインルーターへの直接転送 → DNS :53 をメインルーターにリダイレクト</text>
  <text x="360" y="176" text-anchor="middle" font-size="12" font-weight="600" fill="#c2410c">プロキシなし · 広告フィルタリングなし · 全直結 —— フォールバック保証、ネットワーク断線なし</text>
</svg>

ここでの Fail-Open には明確な境界があります。これは N100 上で実行可能なデーモンに依存しており、mihomo または AdGuard Home の終了、ハングアップなどのソフトウェア障害のみをカバーします。N100 の電源断、カーネルパニック、または LAN リンク断の場合は、`.7` がデフォルトゲートウェイとして全体として到達不能になり、通常クライアントのネットワーク断続を引き起こします。この層の障害をカバーするには、VRRP/デュアルホットスタンバイ、またはメインルーターのヘルスチェックによるDHCPゲートウェイの自動変更が必要です。現在のアーキテクチャでは実装されていません。

## 6. トラフィック分割戦略と中国本土トラフィック保護

以前、CN ドメインが geosite にマッチし漏れたことにより `MATCH,PROXY` → 米国ノード経由で中国本土サーバーに再接続 → GFW が「中国本土へのトラフィック」として認識し VPS IP をブロックするという事象が発生しました。現在は**二重保護**を採用しています：

**第一層（ハード、ファイアウォール）**: `bypass_china_mainland_ip=1`(v4) により nft `china_ip` 集合（約3.7k chnroute）を埋めます。中国本土IPはprerouting段階で `return` され、物理的にmihomoに到達できず、ドメインがgeositeにマッチするかどうかとは無関係です。
- 単一ネットワークインターフェースのヘアピンでは、`table inet bypass_masq` により転送トラフィックを MASQUERADE でソースを .7 に変更する必要があります。
- v6 は現時点でファイアウォールバイパスを無効にしています（v6 のヘアピン失敗を避けるため）。v6 の CN は mihomo の `GEOIP,CN` でフォールバックします。

**第二層（フォールバック、mihomo ルール）**: ルール末尾に `GEOSITE,cn,DIRECT` → `GEOIP,CN,DIRECT` → `MATCH,PROXY` を配置します。fake-ip で漏れた CN ドメインが mihomo に入ると、`GEOIP,CN` により実際の IP に解決されてブロックされます。

### 重要な sysctl 設定

| パラメータ | 値 | 理由 |
|------|----|------|
| `net.ipv4.conf.*.send_redirects` | **0** | そうしないと、.7 が ICMP リダイレクトを送信し、クライアントが .7 を迂回して .1 に直接接続する「二重パス」が形成されます：同じターゲットに対してクライアント直結 + mihomo 経由の代用接続が同時に存在し、メインルーターの同一パブリックIPによるNAT後、サーバーで **PAWS** によりタイムスタンプの小さい方のパケットが破棄されます → i/o タイムアウト嵐（闲魚などのアプリフリーズの真犯人）。これは**単臂/ヘアピンバイパスルーターのすべてのソリューションに適用されます**、本機だけでなく |
| `net.ipv4.conf.*.rp_filter` | 0 | 非対称通信を許可し、ヘアピンと併用 |

### 出国回線

3台のVPSが異なるネットワーク回線に分散配置されており、レイテンシと安定性の差は中国本土への回線のQoSレベルに起因します：

| 回線 | 正式名称 | 優先度 | 特徴 | 適した用途 |
|------|------|--------|------|------|
| **CN2 GIA** | China Telecom Next Gen Carrier | 最高 | 電信最高級回線、全程CN2バックボーンで163網を通過せず、QoSが最低、夕暮れ時でも速度低下ほぼなし | レイテンシ/安定性に要求のある主力ノード |
| **9929** | China Unicom Premium | 中高 | 联通プレミアム回線、CN2 GIA に類似するが联通バックボーン経由、北方联通ブロードバンドユーザーに最適 | 联通ユーザーの直結に最適 |
| **4837** | China Unicom Standard | 普通 | 联通標準国際回線、夕暮れ時の輻輳が顕著だが価格が安い | 予備線/コールドスタンバイ/予算重視 |

### ノードとプロトコルの選択方法

アーキテクチャドキュメントにベンダー、プラン価格、または特定のベンチマーク結果を固定しません。これらの情報は変化が速く、異なる地域、プロバイダ、夕暮れ時帯の体験を代表するものではありません。より確実な選択方法は、自前のアクセスネットワークで継続的に測定することです：

1. 平日の昼間と夕暮れ時帯のRTT、ジッター、パケット損失率、TCP/UDPスループットを個別に記録します。
2. 主力ノードと予備ノードは異なるアップストリームまたは異なるルーティングを選択し、一見すると複数のノードがあるように見えても、実際には同じ障害ドメインを共有しないようにします。
3. TCPとUDPプロトコルの両方をテストします。プロトコルのパフォーマンスはリンク品質に依存するため、1回のレイテンシテストから長期的な結論を導き出せないことに注意してください。
4. スイッチング戦略はビジネス体験を考慮に入れる必要があります。ノード品質が近い場合は自動切り替えが適しています。品質差が大きい場合は、手動切り替えの方がフォールダウンを発見しやすいです。
5. 生データをPrometheus Blackbox Exporterまたは同様のプローブに保存し、瞬間的な最小値ではなく1週間以上の分位数に基づいて決定します。

このネットワークでは手動Selectorを選択しています：主力ノードに異常が発生するとアラートが発信され、保守担当者が確認後に切り替えます。代償は復旧が完全には自動化されないことですが、利点は「接続可能だが体験が非常に悪い」ノードに静かにフォールダウンしないことです。

### 高速化項目

- `tcp-concurrent: true`: 並列接続で複数のIPを解決し、最速のものを選択します。
- QUIC拒否ルールを意図的に保持: `AND,(DST-PORT,443),(NETWORK,UDP),(NOT,GEOSITE,cn),REJECT` により、外部のHTTP/3をh2に強制し、「QUIC-over-Hy2 アイドル後のリソース共有フリーズ」を治療します。解放すると再発します。

> **IPv6 でハードバイパスを開けない理由**: v4 ハードバイパスの鍵はヘアピン MASQUERADE（ソースを .7 に変更して戻り経路の対称性を保証）ですが、この操作には N100 に固定された内網 v4 アドレスが必要です。しかし、v6 アドレスは SLAAC により動的に割り当てられるため、安定した内網アドレスによる SNAT アンカーがありません——v6 上ではヘアピンの戻り経路対称性を信頼できる形で実現できず、無理に開くとランダムな通信断を引き起こします。そのため、v6 の CN は現在 mihomo ルール層の `GEOIP,CN` によるフォールバックのみで、ファイアウォールの prerouting ハードバイパスは使用しません。
> **監視**：N100、コアワークステーション、メインルーターの主要コンポーネントは Prometheus + Grafana に接続されています。詳細は [monitoring.md](monitoring.md) を参照してください。ノードの可用性は Prometheus Blackbox Exporter によってプローブされます。ここでは、手動確認後の切り替え戦略を保持しています。

## 7. N100 主要コンポーネント

| コンポーネント | アドレス/パス | 説明 |
|------|-----------|------|
| mihomo カーネル | `/usr/bin/mihomo`, procd via `/etc/init.d/nikki` | 透過プロキシ+TUN |
| mihomo API | `127.0.0.1:9090` | ヘルスプローブ |
| mihomo mixed | `:7890`(SOCKS5+HTTP) | 明示的プロキシエントリ |
| mihomo redir | `:7891` | 透過プロキシ redirect 入力 |
| mihomo DNS | `:1053`(fake-ip) | AdGuard アップストリーム |
| Nikki ダッシュボード | `http://<side-router-ip>:9090/ui` | Web コンソール、内網アクセスのみ許可 |
| AdGuard Home | Docker ホストネットワーク、`http://<side-router-ip>:8083` | DNS 広告フィルタリング、アップストリームは :1053 を指す |
| failopen デーモン | `/usr/local/sbin/nikki-failopen.sh`, procd | ヘルスチェック + 自動 fail-open |
| CN バイパス SNAT | `/etc/nikki/scripts/bypass-masq.{nft,sh}` + firewall include | ヘアピン masquerade、永続化 |

> N100 移行の動機とハードウェア選定：以前はデスクトップ機の WiFi 上でバイパスルーターを実行していましたが、WiFi のジッターにより家庭全体のネットワークが断続していました。N100（低消費電力 x86、iStoreOS、単一ギガビットポート）に交換し、書斎 AP LAN ポートに有線バイパスルーターとして接続することで、WiFi から切り離されました。

## 8. nftables 構造

**処理順序**（prerouting → forward → postrouting）：

<svg viewBox="0 0 720 420" xmlns="http://www.w3.org/2000/svg" font-family="-apple-system,'Source Han Sans CN','Microsoft YaHei',sans-serif" role="img" aria-label="nftables 処理順序: prerouting から postrouting までのパケット処理パイプライン">
  <defs><marker id="nfah" markerWidth="10" markerHeight="8" refX="8" refY="3" orient="auto"><path d="M0,0 L8,3 L0,6 Z" fill="#475569"/></marker></defs>
  <rect width="720" height="420" fill="#ffffff"/>
  <text x="360" y="28" text-anchor="middle" font-size="17" font-weight="700" fill="#1f2933">nftables 処理順序: prerouting → forward → postrouting</text>
  <!-- 入站包 -->
  <rect x="150" y="44" width="140" height="26" rx="13" fill="#e2e8f0"/>
  <text x="220" y="61" text-anchor="middle" font-size="12" fill="#334155">着信パケット</text>
  <line x1="220" y1="70" x2="220" y2="88" stroke="#475569" stroke-width="1.6" marker-end="url(#nfah)"/>
  <!-- fw4 forward -->
  <rect x="40" y="90" width="360" height="32" rx="8" fill="#eef2ff" stroke="#c7d2fe"/>
  <text x="220" y="110" text-anchor="middle" font-size="12" font-weight="700" fill="#3730a3">fw4 forward(policy drop)</text>
  <line x1="220" y1="122" x2="220" y2="140" stroke="#475569" stroke-width="1.6" marker-end="url(#nfah)"/>
  <!-- nikki dstnat/mangle_prerouting -->
  <rect x="40" y="142" width="360" height="44" rx="8" fill="#eef2ff" stroke="#c7d2fe"/>
  <text x="220" y="160" text-anchor="middle" font-size="12" font-weight="700" fill="#3730a3">nikki dstnat / mangle_prerouting</text>
  <text x="220" y="176" text-anchor="middle" font-size="9" fill="#4f46e5">透過プロキシエントリ · 宛先に基づくトラフィック分割</text>
  <!-- branch lines -->
  <line x1="400" y1="164" x2="440" y2="154" stroke="#475569" stroke-width="1.4" marker-end="url(#nfah)"/>
  <line x1="400" y1="164" x2="440" y2="204" stroke="#475569" stroke-width="1.4" marker-end="url(#nfah)"/>
  <!-- branch: 大陆 IP/私网 -->
  <rect x="440" y="132" width="240" height="44" rx="6" fill="#dcfce7" stroke="#86efac"/>
  <text x="452" y="151" font-size="12" font-weight="700" fill="#166534">中国本土IP / プライベートネットワーク</text>
  <text x="452" y="168" font-size="10" fill="#15803d">→ return、プロキシを通過しない（直結）</text>
  <!-- branch: 其余 -->
  <rect x="440" y="182" width="240" height="44" rx="6" fill="#f0fdfa" stroke="#99f6e4"/>
  <text x="452" y="201" font-size="12" font-weight="700" fill="#115e59">その他のトラフィック</text>
  <text x="452" y="218" font-size="10" fill="#0f766e">→ DNAT :7891 または TUN マーク</text>
  <line x1="220" y1="186" x2="220" y2="206" stroke="#475569" stroke-width="1.6" marker-end="url(#nfah)"/>
  <!-- bypass_masq postrouting -->
  <rect x="40" y="208" width="360" height="40" rx="8" fill="#eef2ff" stroke="#c7d2fe"/>
  <text x="220" y="226" text-anchor="middle" font-size="12" font-weight="700" fill="#3730a3">bypass_masq postrouting</text>
  <text x="220" y="242" text-anchor="middle" font-size="9" fill="#4f46e5">ヘアピン SNAT アンカー</text>
  <line x1="400" y1="228" x2="440" y2="228" stroke="#475569" stroke-width="1.4" marker-end="url(#nfah)"/>
  <!-- branch: CN 直连流量 -->
  <rect x="440" y="206" width="240" height="44" rx="6" fill="#f0fdfa" stroke="#99f6e4"/>
  <text x="452" y="225" font-size="12" font-weight="700" fill="#115e59">CN 直結トラフィック</text>
  <text x="452" y="242" font-size="10" fill="#0f766e">→ MASQUERADE(src→.7、戻り経路対称)</text>
  <line x1="220" y1="248" x2="220" y2="266" stroke="#475569" stroke-width="1.6" marker-end="url(#nfah)"/>
  <!-- fw4 srcnat_lan -->
  <rect x="40" y="268" width="360" height="32" rx="8" fill="#eef2ff" stroke="#c7d2fe"/>
  <text x="220" y="288" text-anchor="middle" font-size="12" font-weight="700" fill="#3730a3">fw4 srcnat_lan(docker MASQUERADE)</text>
  <line x1="220" y1="300" x2="220" y2="318" stroke="#475569" stroke-width="1.6" marker-end="url(#nfah)"/>
  <!-- 出站 -->
  <rect x="150" y="320" width="140" height="26" rx="13" fill="#e2e8f0"/>
  <text x="220" y="337" text-anchor="middle" font-size="12" fill="#334155">発信</text>
  <!-- insight -->
  <rect x="40" y="366" width="640" height="42" rx="8" fill="#f8fafc" stroke="#e2e8f0"/>
  <text x="56" y="384" font-size="11" fill="#475569">中国本土IPはprerouting段階でreturnされ、物理的にmihomoに入らず、ドメインがgeositeにマッチするかどうかとは無関係です。</text>
  <text x="56" y="400" font-size="11" fill="#475569">bypass_masq は独立したテーブルとして構成されており、nikki の再起動/fail-open により戻り経路対称のSNATアンカーに影響されません。</text>
</svg>

### table inet fw4 (OpenWrt ファイアウォール)
- `forward`: policy drop; TUNトラフィック + LAN→WAN 転送を許可
- `srcnat_lan`: docker MASQUERADE

### table inet nikki (透過プロキシルール)
- `china_ip` 集合: 約3.7k chnroute CIDR（`bypass_china_mainland_ip=1` により埋められる）
- `dstnat` / `mangle_prerouting_lan`: 中国本土IP / プライベートネットワーク / 198.18 にマッチ → `return` によりバイパス; その他は DNAT TCP→:7891 または TUN マーク
- `mangle_output`: 本機発信 → TUN
- fail-open 時はテーブル全体を削除

### table inet bypass_masq (CN-IP バイパスのヘアピン SNAT)
- `postrouting`(nat hook、priority srcnat+5): `iifname br-lan oifname br-lan ip daddr != {プライベート+198.18+マルチキャスト} masquerade`
- `china_ip` によりバイパスされ、.1 に転送して戻す必要があるパブリック CN 直結トラフィックのみマッチし、ソースを .7 に変更して戻り経路の対称性を保証
- `table nikki` とは独立しており、**nikki の再起動に影響されません**。永続化は `firewall.bypass_masq` include により行われます。

### table inet failopen (障害注入、復旧時に削除)
- `srcnat`：MASQUERADE `<lan-cidr>` → 非ローカル
- `dns`: DNAT :53 → .1:53

## 9. セルフホスティングサービスと障害ドメイン

以下のサービスは現在、コアワークステーションの Wi-Fi に依存しています。`wifi-watchdog`（systemd timer）は、一時的なRFまたはドライバの異常を回復できますが、無線リンクを高可用性インフラストラクチャに変えることはできません。長期間稼働するエントリポイントと監視サービスは、有線ノードに移行する必要があります。

| サービス | 用途 | 可用性 |
|------|------|--------|
| DERP | Tailscale リレー | 高 |
| rathole | 内網トンネリング（[rathole-tunnel.md](rathole-tunnel.md) 参照） | 高 |
| paste/mdserve | ノート共有 | 中 |
| Prometheus | 監視収集 | 中 |
| sunshine | ゲームストリーミング | 低 |
| ローカルLLM | AI推論（[local-llm.md](local-llm.md) 参照） | 低 |

## 10. デーモン

| デーモン | 位置 | シナリオ |
|------|------|------|
| nikki-failopen | N100 (procd) | mihomo/AdGuard プロセス異常 |
| 通電時自動起動 | N100 (BIOS) | 停電復旧 |
| wifi-watchdog | コアワークステーション（systemd timer） | Wi-Fi ドライバ/RF異常 |
| sync-mihomo-to-router | コアワークステーション（systemd timer） | 真のソース → バイパスルーター設定のドリフト |
| sync-subscribe | コアワークステーション（systemd timer） | 真のソース → モバイル端末設定のドリフト |

### 設定派生パイプライン

家庭内には mihomo 設定が必要な場所が3箇所あります：コアワークステーション（TUN 自前プロキシ）、N100（家庭全体透過プロキシ）、およびモバイル端末用インポートファイル。これら3つの**ノードリスト、プロキシグループ、トラフィック分割ルールは一致している必要があります**が、DNS、TUN、入力方法はそれぞれ異なります。個別に維持すると必然的にドリフトが発生します。

**方案**：`<config-root>/config.yaml` のみを手動で編集し、`proxies`、`proxy-groups`、および `rules` を含めます。2つのtimer駆動スクリプトがこれらからターゲット設定を派生させます。

**#1 本機**: 真のソースを直接使用します。TUNデバイス `Meta` + ローカル AdGuard + fake-ip + controller。

**#2 N100 バイパスルーター** (`sync-mihomo-to-router.sh`, timer 03:45):
- 真のソースから `proxies`/`proxy-groups`/`rules` の3セクションのみを抽出 → `/etc/nikki/profiles/home.yaml`
- 本機で `mihomo -t` により真のソースを検証 → scp で N100 に転送 → `nikki -t` により検証 → 旧ファイルバックアップ（タイムスタンプ付き）→ 検証失敗時は自動ロールバック → Nikki をリロード
- DNS/TUN/sniffer は N100 側のローカル UCI mixin により注入され、プロファイルには含まれません——これらはターゲット側固有のものであり、真のソースから上書きされるべきではありません。

**#3 モバイル端末設定** (`sync-subscribe.sh`):
- `clash.yaml`(Clash インポート用) + `sub.txt`(v2rayN base64 共有リンク) を出力
- 本機依存の除去: `external-controller`+`secret`（漏洩すると制御される）、`tun` 全体（スマホは不要）、`nameserver:127.0.0.1`（ローミングデバイスでは到達不可）、`PROCESS-NAME` ルール（スマホでは絶対にマッチしない）を削除
- DNS を fake-ip + パブリック DoH に置き換え、国外ドメインは出口解析を使用して漏洩を防ぐ
- パブリック経由で配布する場合、エントリポイントには独立したドメインと予測不可能なパストークンを使用します。Webサーバーは派生ファイルのみを公開し、真のソース、コントローラーキー、またはディレクトリリストは公開しません。

2つのtimerは実行時間をずらして、ターゲット設定の同時読み書きを避けます。真のソースを変更した後、対応するスクリプトを手動で実行することもできます。スクリプトは冪等性を保ち、置換前に構文検証とバックアップを完了させる必要があります。

## 11. 運用後の検証チェックリスト

まず、バイパスルーターのアドレスを環境変数に設定し、サンプルコマンドに実際のアドレスが出現しないようにします：

```bash
SIDE_ROUTER_IP=192.168.31.7
```

通常モードでは、少なくとも以下の項目を検証します：

```bash
# クライアントのデフォルトルートがバイパスルーターを指しているか確認
ip route show default

# DNS が AdGuard のみを通過し、予期される fake-ip 応答を取得できるか確認
dig @"$SIDE_ROUTER_IP" example.com

# バイパスルーター上で転送、リダイレクト、SNAT ルールが存在することを確認
ssh "root@$SIDE_ROUTER_IP" 'nft list ruleset'

# 2つのプロセスとそのリスニングポートが生きているか確認
ssh "root@$SIDE_ROUTER_IP" 'pgrep -a mihomo; ss -lntup'
```

Fail-Open は、障害発生後に推測するのではなく、保守ウィンドウで演習する必要があります。mihomo と AdGuard Home を個別に停止し、デーモンが透過プロキシルールを取消し、DNS を引き継ぎ、クライアントが依然として直結できることを確認します。その後、サービスを復旧し、ルールが重複して注入されていないことを確認します。最後に、N100 の電源断を個別にシミュレートし、監視が実際にアラートを出し、現在のアーキテクチャ下では通常クライアントがネットワーク断続するという事実を受け入れることを確認します。

| シナリオ | 期待される結果 |
|------|----------|
| mihomo プロセス終了 | 自動的にリダイレクトを取消し、直結にフォールバック |
| AdGuard Home プロセス終了 | :53 が利用可能な DNS に引き継がれ、クライアントは引き続き解決可能 |
| N100 再起動後の復旧 | 設定は1回のみ注入され、ルートとDNSは通常モードに戻る |
| N100 電源断またはネットワークインターフェース断 | 現時点でゲートウェイのホットスタンバイなし、通常クライアントはネットワーク断続し、アラートが発生 |
| コアワークステーションオフライン | 通常の家庭デバイスには影響なし；セルフホスティングサービスがオフライン |

## 12. 既知のリスク

| リスク | 影響 | 緩和策 |
|------|------|------|
| **コアワークステーション Wi-Fi の単一障害点** | トンネルやリレーなどのセルフホスティングサービスが同時にオフライン | 長期的には有線ノードに移行；watchdog は短期的な止血策としてのみ |
| **N100 単一ネットワークインターフェースのヘアピン** | 単臂トポロジーでは戻り経路の非対称性により必然的に断線 | MASQUERADE + bypass_masq nft テーブルにより戻り経路の対称性を保証 |
| **mihomo/AdGuard プロセスフリーズ** | 家庭全体のネットワーク断続（DHCPゲートウェイは依然として .7 を指す） | nikki-failopen(procd) によるプロセスレベルの自己修復 |
| **N100 ハードウェア、電源、またはリンク障害** | デフォルトゲートウェイが到達不能になり、通常クライアントがネットワーク断続 | 現時点では監視アラートのみの対応；今後、デュアルゲートウェイまたはメインルーター側での自動切り替えを導入 |
| **メインルーター ハードウェア/ファームウェア障害** | 家庭全体のネットワーク断続（PPPoE+NAT+DHCP すべてダウン） | 現時点でホットスタンバイなし；元計画では N100 をメインルーターとする予定だったが未着工 |
| **光モデムブリッジ** | ONT は光電変換のみを行い、PPPoE接続なし、ルーティングなし、NATなし、パブリックIPはメインルーターに直接接続 | 基本的に障害源ではなく、二重NATは発生しない |

> 詳細な評価と復旧手順は [network-recovery.md](network-recovery.md) を参照してください。

## 変更履歴

| 日付 | 変更内容 |
|------|------|
| 2026-06-21 | N100 バイパスルーター運用開始、旧ワークステーションバイパスルーター退役；DHCP ゲートウェイ/DNS を .8 から .7 に切替；Fail-Open と Wi-Fi watchdog をデプロイ |
| 2026-06-24 | パブリックサブスクリプション修正: 本機 config をそのままコピーすると本機 DNS+管理口 secret+tun が漏洩したため、sync-subscribe.sh に本機依存除去の消毒処理を追加；バイパスルータープロファイルを再実行して更新；sync-mihomo-to-router.timer を追加 |
| 2026-06-27 | ICMP `send_redirects` を無効化: 闲魚などのアプリフリーズを治療（二重パス PAWS パケット損失嵐の根本原因）；CN-IP ファイアウォールバイパスを運用開始（`bypass_china_mainland_ip=1` + `table inet bypass_masq`）；`tcp-concurrent` + CN DNS を平文 UDP 223.5.5.5 に変更；ノード洞察 |
| 2026-08-11 | 公開版ドキュメントでホスト、SSID、サブスクリプションエントリ、ノード情報を一般化；設計原則と検証方法を補足 |

## 関連ドキュメント

- [rathole-tunnel.md](rathole-tunnel.md) — トンネルホーム方案
- [network-recovery.md](network-recovery.md) — 障害復旧マニュアル
- [monitoring.md](monitoring.md) — 監視アーキテクチャ
