Debianで作った10GルータをNixOSで作り直した話

前回 Debian 13 で組んだ自宅 10G ルータの構成 (BCM57810 / VLAN / nftables / MAP-E / tinc) はそのまま、OS だけを NixOS 25.11 (unstable) に丸ごと書き直した 話です。作業日は 2026-03-19

前回と同じく、複数のレイヤで書きます。

  • 比喩で全体像 (一般向け)
  • Web 系のエンジニアっぽい言い回し (Terraform / blue-green / immutable / atomic)
  • 実コマンド・version 番号・Nix モジュール片 (ネットワーク・OS 系)
  • NixOS の 基礎機能 (services.*, systemd.services.*, environment.etc."x".source, nixos-rebuild switch) を実例で押さえる

ソフトウェアエンジニア視点で言うと、これは 「本番 EC2 を手で運用していたのを Terraform + Ansible 相当に書き直した」 くらいのインパクトのある作業です。


なぜ動いてるものを作り直すのか

ルータ自体はちゃんと動いていました。インターネットは普通に出ていたし、宅内も 10Gbps 出ていた。それなのに作り直したのは、毎日使う分には問題ないけど、いじろうとした瞬間に大変だったから です。

辛みポイント 例えるなら アプリ開発で例えると
設定ファイルが 10 か所以上に散らばっている レシピが冷蔵庫・食器棚・引き出し・机の上に分散 リポジトリ無しで本番 EC2 に直接 vim
一部のソフトは自前ビルドで /opt/usr/local に置いてある 自分で改造した家電を使ってる グローバルインストールされた CLI に依存、ロックファイル無し
半年前に何を変えたか忘れる カレンダーは残ってるけど「なぜそうしたか」が思い出せない 設定変更の PR が無い、commit message も歯抜け
別のパソコンで同じものを作れない 引っ越し先で同じ家を建てたくても、設計図が頭の中 デプロイ手順が口伝、新環境の bootstrap がブログ記事

特に最後がしんどい。ルータは絶対に止めたくない装置なのに、壊れたときの復旧プランが「がんばって思い出す」ではマズい

Web アプリならカナリアデプロイで段階的に切り戻せます。ルータは設定ミスで自分の SSH 経路を切るので段階デプロイが効かない。だから 単一の宣言ファイル + アトミックな切り替え + ロールバック が効く NixOS、という選択は割と理に適っています。

NixOS って何 (3 行で)

  • OS 全体を Nix 言語で宣言的に書く ディストリ。/etc/nixos/configuration.nix がほぼ単一のソース
  • パッケージ管理が immutable + atomic (/nix/store/<hash>-<name>/... に世代ごとにインストール、切り替えは symlink 1 本の貼り替え)
  • 何かやらかしても起動メニューから前世代を選んで戻れる (= 物理マシン版の git revert)

nixos-rebuild switch というのが要するに terraform applynixos-rebuild switch --rollbackterraform apply で前の state に戻す感じ。直感的に近いです。

重要概念 (5 分で)

用語 ざっくり説明
module Nix 式で書かれた設定のかたまり。options (型付き設定項目) と config (実体) を定義する
evaluation Nix 式を評価して具体的なファイル群 (/nix/store/<hash>-<name>/) を生成すること
store path /nix/store/<hash>-<name> 形式の不変パス。同じ内容なら同じハッシュ
generation rebuild するたびに作られる「システム全体のスナップショット」。世代番号で管理
atomic switch 新世代への切替は symlink 1 本を貼り替える だけ。中途半端な状態にならない

/etc/nftables.conf のような「人間が直接書き換える設定ファイル」は NixOS には存在しない。代わりに /etc/nftables.conf/nix/store/<hash>-nftables.conf への symlink として置かれていて、rebuild ごとに symlink 先が変わる、というイメージ:

$ ls -l /etc/nftables.conf
lrwxrwxrwx 1 root root 51 /etc/nftables.conf -> /nix/store/zk2p...n9-nftables.conf

Debian vs NixOS 高レベル比較

項目 Debian 13 NixOS 25.11
設定の中央集権 /etc/ 各地に散在 /etc/nixos/ 配下に集約
パッケージ管理 dpkg + apt (mutable) nix-store (immutable, per-generation)
サービス定義 systemctl edit + override.conf services.<name> または systemd.services.<name> を Nix で記述
ロールバック バックアップ復元 (祈り) nixos-rebuild switch --rollback (確実)
再現性 手順書 configuration.nix を別ハードに持っていけばほぼ同じ
ファイアウォール記述 /etc/nftables.conf を手書き networking.nftables.ruleset = ''...'' で文字列リテラル埋め込み
DNS AdGuard Home (deb 外) nixpkgs に AdGuard Home モジュール有り
DHCP /etc/kea/kea-dhcp4.conf を手書き services.kea.dhcp4.settings = { ... };
DHCPv6-PD クライアント wide-dhcpv6 odhcp6c に変更 (nixpkgs に wide-dhcpv6 無し)
tinc 自前ビルド (/usr/local/sbin/tincd) nixpkgs の pkgs.tinc_pre (1.1pre18)

ハードウェア・設計はそのまま

ルータ用のハード (BCM57810 10GbE × 2 + RTL8111 1GbE) は流用。 VLAN 設計 (移行時点で 6 本: 1001/1010/1083/1100/1110/1120)、nftables のルールセット、サブネット割り当て、tinc のノード名・鍵もそのまま。変えるのは OS と「どう書くか」だけ。(なおゲスト VLAN 1020 と別拠点 L2 用の 1130 は移行後に追加した。詳しくは末尾の後日談で。)

移行戦略 — ブルー/グリーンの物理版

  1. 別 SSD に NixOS を新規インストール (Debian 側のディスクは抜いて温存)
  2. /etc/nixos/configuration.nix + /etc/nixos/modules/*.nix で構成を書き上げる
  3. nixos-rebuild testswitch で完成形を作ってから、ONU と CRS305 のケーブルを Debian → NixOS 機に物理で差し替え
  4. 切り戻し = ケーブルを Debian 側に戻すだけ

要するに ブルー/グリーンデプロイの物理版。アプリだと ALB の重み変えるところを、ルータでは SFP+ ケーブルを引き抜いて差し替える。

家のたとえで言うと「作業中も既存のルータは生かしておく。最悪 ケーブルを挿し替える 30 秒 だけネットが止まる、という戦略」です。

ディスク・ブート構成

パーティション サイズ 用途
EFI (FAT32) 512MB systemd-boot
btrfs 残り全部 サブボリューム @, @nix, @var (compress=zstd)

NixOS の /nix/store は世代を持つので 同じバイナリの重複が大量に出る。btrfs の透過圧縮 + reflink 効果で実効容量がだいぶ稼げます。

モジュール分割 — 9 個のかたまり

NixOS では設定を 1 ファイルに書くこともできますが、長くなりすぎるので 9 個のかたまり に分けました (/etc/nixos/modules/*.nix)。

モジュール 内容 方式
network.nix VLAN 6 本 + sysctl NixOS native (networking.vlans)
nftables.nix 6 テーブルのファイアウォール NixOS native (networking.nftables.ruleset)
dns.nix AdGuard Home + Unbound NixOS native (services.adguardhome, services.unbound)
dhcp.nix Kea DHCP4 (5 サブネット, PXE) NixOS native (services.kea)
mape.nix MAP-E + Fixed IP トンネル + tc pedit カスタム (environment.etc + systemd.services)
ipv6.nix odhcp6c + radvd + assign-prefix カスタム systemd unit
routing.nix ポリシールーティング (ip rule) カスタム systemd unit
tinc.nix tinc VPN gsnet (pkgs.tinc_pre) NixOS native (services.tinc.networks)
monitoring.nix Netdata + iperf3 NixOS native + カスタム

configuration.nix から取り込むだけ:

{ config, pkgs, ... }: {
  imports = [
    ./hardware-configuration.nix
    ./modules/network.nix
    ./modules/nftables.nix
    ./modules/dns.nix
    ./modules/dhcp.nix
    ./modules/mape.nix
    ./modules/ipv6.nix
    ./modules/routing.nix
    ./modules/tinc.nix
    ./modules/monitoring.nix
  ];

  system.stateVersion = "25.11";
}

設計方針は 「NixOS が用意するサービスモジュールはなるべくそれを使う。合わなければ無理せず systemd.services.<name> でフラットに書く」 こと。Nix らしく抽象化しようとすると 1 行のシェルが 40 行の Nix 式になることがあって、Web 開発で言う 過剰な DRY と同じで保守性が逆に下がります。

「ここを直したいときはこのファイル」と決まっているので、半年後の自分でも迷わない。これだけで前回の 「設定がバラバラ問題」 が一気に解決しました。

設定パスの対応表 (Debian → NixOS)

NixOS 入門者にとって、これが頭に入ると Debian 時代の /etc/ 知識を NixOS 設定に投影できる

Debian の設定パス NixOS 上での書き方 実体パス (rebuild 後)
/etc/network/interfaces networking.vlans, networking.interfaces systemd-networkd 設定 (Nix が生成)
/etc/nftables.conf networking.nftables.ruleset = '' ... ''; /etc/nftables.conf → store path
/etc/kea/kea-dhcp4.conf services.kea.dhcp4.settings = { ... }; /nix/store/<hash>-kea-dhcp4.conf
/opt/AdGuardHome/AdGuardHome.yaml services.adguardhome.settings = { ... }; /var/lib/AdGuardHome/AdGuardHome.yaml
/etc/unbound/unbound.conf.d/*.conf services.unbound.settings = { ... }; /nix/store/<hash>-unbound.conf
/etc/wide-dhcpv6/* (廃止: odhcp6c に移行) -
/etc/router-scripts/map-e-setup.sh environment.etc."router-scripts/map-e-setup.sh".source = ./scripts/map-e-setup.sh; /etc/router-scripts/map-e-setup.sh → store path
/etc/tinc/gsnet/ services.tinc.networks.gsnet = { ... }; /etc/tinc/gsnet/ (鍵は /var/lib/tinc/)
/etc/systemd/system/iperf3-gsnet.service systemd.services.iperf3-gsnet = { ... }; /etc/systemd/system/iperf3-gsnet.service → store path

「すべて configuration.nix から派生する」 のがポイント。

Debian → NixOS で実際に書き換えた点

NixOS のエコシステムと衝突する箇所を、移行のついでに書き換えました。casual な言い方をすると 「同じ機能を、別の流儀で書き直すだけ」 の作業です。

1. wide-dhcpv6 → odhcp6c

nixpkgs に wide-dhcpv6 パッケージが存在しない。OpenWrt 由来の odhcp6c に乗り換え/56 を取得したら hook を叩くだけのシンプルな実装で、assign-ipv6-prefix.sh 側の I/F は同じにしたためロジック無修正。

# modules/ipv6.nix
systemd.services.odhcp6c = {
  description = "DHCPv6 PD client";
  wantedBy = [ "multi-user.target" ];
  serviceConfig.ExecStart = "${pkgs.odhcp6c}/bin/odhcp6c -P 56 -s /etc/router-scripts/odhcp6c-hook.sh enp1s0f0";
  serviceConfig.Restart = "always";
};

2. /etc/wide-dhcpv6//etc/router-scripts/

スクリプト置き場改名。NixOS 上は environment.etc で配置:

environment.etc."router-scripts/assign-ipv6-prefix.sh" = {
  source = ./scripts/assign-ipv6-prefix.sh;
  mode = "0755";
};

これで /etc/router-scripts/assign-ipv6-prefix.sh がシンボリックリンクとして配置される。「設定ファイルは store の中で immutable、/etc には link を貼るだけ」というのが Nix の流儀。

3. nftables の ipencap → プロトコル番号 4

これが地味に痛かった。WAN (enp1s0f0) で 4in6 (MAP-E と ipip-fixed underlay の両方) を受ける行を Debian では ip6 nexthdr ipencap と書いていた。NixOS で nixos-rebuild を回すと:

error: ... nftables-check-...
/nix/store/.../ruleset.nft:NN:M-M: Error: Could not resolve protocol name
    ip6 nexthdr ipencap accept
                ^^^^^^^

で落ちる。services.nftables.checkRuleset = true (デフォルト) がサンドボックス derivation 内で nft --check を回しており、そこで symbolic name 解決に失敗する。

最初は「サンドボックスで /etc/protocols が読めない」のかと疑ったが、調べると runtime の /etc/protocols 自体は見えていて、中身が違う のが本当の原因だった:

ディストロ /etc/protocols 提供元 proto 4 のエントリ
Debian netbase パッケージ ipv4 + ipencap (別名)
NixOS iana-etc (IANA 正式名のみ) ipv4 のみ (ipencap は無い)

nftablesnft は symbolic name を getprotobyname(3) 経由で解決するので、NixOS では ipencap を引けない。

- ip6 nexthdr ipencap iifname "enp1s0f0" accept
+ ip6 nexthdr 4       iifname "enp1s0f0" accept

「プロトコル番号 4 (IP-in-IP / RFC 2003 で命名、ここでは IPv4-in-IPv6 = RFC 2473 の inner)」をベタ書きすることで解決。ip6 nexthdr ipv4 と書いても通る (こちらは IANA 名で NixOS にも存在) が、「symbolic 名は環境差で詰む」と一度刺されたので、以後は GRE (47) / ESP (50) / IPv4 (4) / IPv6 (41) はすべて番号で書く のを鉄則にした。

これは 依存解決の世界では「環境に置いてある名前 (= グローバル変数) を参照する習慣」が NixOS の iana-etc で剥がれる、という典型例。Docker でベースイメージを debian から alpine に変えたら iproute2 の細部が違って死ぬのに近い。

services.nftables.checkRuleset: NixOS は nftables.ruleset を渡すと、activation の前に サンドボックス derivation で nft --check を走らせて構文・symbolic 名解決を検証する。ここで落ちると nixos-rebuild switch 自体が失敗するので、壊れた ruleset が /etc/nftables.conf に降りて WAN を切る ような事故が原理的に起きない。Debian で nft -f /etc/nftables.conf の reload に失敗してネットが死ぬパターンが、構造的に消える。

4. enp2s0 管理用ルール

NixOS 機の初期構築は管理 NIC 経由 SSH 想定なので、enp2s0 用の SSH 許可ルールを input chain に追加。Debian 時代は雑に enp2s0accept していたが、宣言的に書くなら明示せざるを得ない。

5. Kea の Dhcp4 ネスト除去

services.kea.dhcp4.settings は内部で Dhcp4 キーを自動付与する。Debian の kea-dhcp4.conf をそのまま貼ると {"Dhcp4":{"Dhcp4":{"subnet4":...}}} の二重ネストで起動しない:

services.kea.dhcp4 = {
  enable = true;
  settings = {
    interfaces-config = { interfaces = [ "enp1s0f1.1010" "enp1s0f1.1100" ... ]; };
    subnet4 = [ ... ];
    hooks-libraries = [ { library = "${pkgs.kea}/lib/kea/hooks/libdhcp_lease_cmds.so"; } ];
  };
};

Dhcp4 階層を 1 段剥がして書く。OpenAPI generator が prefix を勝手に付けるのと同じ罠で、生成系のフレームワークが二重に suffix/prefix を付けて死ぬ、というよくある奴。

ちなみに pkgs.kea から自動で hook ライブラリの store path を引ける のが便利。Debian だと /usr/lib/x86_64-linux-gnu/kea/hooks/... を手で書いていたが、NixOS では store path が hash 込みで決まるので、pkgs.kea の式から動的に組み立てる。

6. tinc は nixpkgs の tinc_pre

pkgs.tinc_pre (1.1pre18) が nixpkgs に居るので自前ビルドを廃止。Debian 時代の最大の負債だった「tinc 1.1pre の自前ビルド + systemd override」がここで消える:

services.tinc.networks.gsnet = {
  package = pkgs.tinc_pre;        # ★ 1.1pre18
  name = "aibauiha";
  interfaceType = "tap";          # Mode = switch
  listenAddress = "0.0.0.0";

  extraConfig = ''
    Mode = switch
    ConnectTo = gsngw01
    ConnectTo = suzukautako
    ConnectTo = linuweb
    ConnectTo = kimon
    ConnectTo = rabbit_house
  '';
};

鍵 (rsa_key.priv, ed25519_key.priv, hosts/*) は Debian ルータから scp で /var/lib/tinc/gsnet/ にコピーtinc 1.0.36 (Debian 公式) では SPTPS / ChaCha-Poly1305 が使えない。1.1pre 同士なら UDP 経路の暗号が軽くなる期待があり、10G メッシュなら効くだろう、というのが 1.1pre を入れた動機。全ピアが 1.1pre になっていないと新プロトコルに乗らない (= レガシー側に落ちる経路はメリット無し) ので、効果は経路次第。

「自前ビルド + systemd override + service ファイル」という 3 ファイルの密結合が パッケージ名 1 個に圧縮された のは、移行効果の中でも一番気持ち良かった部分。

NixOS 入門者向け: 実モジュールの中身

何箇所か、入門者が 「あぁ Nix ってこう書くんだ」 と分かる例として中身を出しておきます。

network.nix — VLAN を NixOS で書く

{ ... }:
let
  vlanIds = [ 1001 1010 1083 1100 1110 1120 ];
in {
  networking.useDHCP = false;
  networking.interfaces.enp1s0f0.useDHCP = false;

  # VLAN サブインタフェースを 6 本まとめて生成
  networking.vlans = builtins.listToAttrs (map (vid: {
    name = "enp1s0f1.${toString vid}";
    value = { id = vid; interface = "enp1s0f1"; };
  }) vlanIds);

  # 各 VLAN GW IP (.1) を割り当て
  networking.interfaces = builtins.listToAttrs (map (vid: {
    name = "enp1s0f1.${toString vid}";
    value = {
      ipv4.addresses = [{
        address = "192.168.${toString (vid - 1000)}.1";
        prefixLength = 24;
      }];
    };
  }) [ 1001 1010 1100 1110 1120 ]);

  boot.kernel.sysctl = {
    "net.ipv4.ip_forward" = 1;
    "net.ipv6.conf.all.forwarding" = 1;
  };
}

Debian の /etc/network/interfaces を 6 ブロック手書きしていた分が、リストの上を map するだけ で済みます。

nftables.nix — ヒアドキュメントで全テーブル定義

{ ... }: {
  networking.nftables.enable = true;
  networking.nftables.ruleset = ''
    table inet filter {
      chain forward {
        type filter hook forward priority filter; policy drop;
        iifname "enp1s0f1.1010" oifname "map-wan" accept
        iifname "enp1s0f1.1010" oifname "enp1s0f1.1100" accept
        iifname "enp1s0f1.1010" oifname "enp1s0f1.1110" tcp dport { 80, 443 } accept
        # ...
      }
    }
    table ip mangle {
      chain forward {
        type filter hook forward priority -150;
        oifname "map-wan" tcp flags syn tcp option maxseg size set 1414
      }
    }
    # 残り 4 テーブルも同様
  '';
}

要するに nftables の生ルールを文字列リテラルで埋め込めるだけ の薄いラッパー。これくらいで十分。 この文字列が /nix/store/<hash>-nftables.conf として store に書き出され、/etc/nftables.conf から symlink で参照される。手で書き換えても rebuild すると symlink が上書きされて元に戻る = 設定の真実は常に .nix ファイル

dns.nix — AdGuard Home と Unbound を 2 行で

{ ... }: {
  services.adguardhome = {
    enable = true;
    mutableSettings = true;  # WebUI で変更を許可 (= rebuild で潰さない)
    settings = {
      dns = {
        bind_hosts = [ "0.0.0.0" "::" ];
        port = 53;
        upstream_dns = [ "127.0.0.1:5335" ];  # Unbound
      };
      filtering.rewrites = [
        { domain = "*.chun37.com"; answer = "192.168.120.105"; }
      ];
    };
  };

  services.unbound = {
    enable = true;
    settings.server = {
      interface = [ "127.0.0.1" ];
      port = 5335;
      access-control = [ "127.0.0.0/8 allow" ];
      do-ip6 = "yes";
      harden-glue = "yes";
    };
  };
}

mutableSettings = true を付けると、WebUI 経由の変更を /var/lib/AdGuardHome/AdGuardHome.yaml に書いて永続化する (rebuild で潰されない)。リライト等のリスト操作を WebUI でやりたいときに便利。

monitoring.nix${pkgs.iperf3} で store path 埋め込み

{ pkgs, ... }: {
  services.netdata.enable = true;

  systemd.services.iperf3-gsnet = {
    description = "iperf3 server bound to gsnet address";
    after = [ "tinc.gsnet.service" ];
    requires = [ "tinc.gsnet.service" ];
    wantedBy = [ "multi-user.target" ];
    serviceConfig = {
      ExecStart = "${pkgs.iperf3}/bin/iperf3 -s -B 10.24.34.2";
      Restart = "on-failure";
    };
  };
}

${pkgs.iperf3}/bin/iperf3iperf3 パッケージの store path を Nix が評価時に解決して埋め込む。Debian で /usr/bin/iperf3 と書いていた感覚に近いが、パッケージ更新時にパスが自動で追従する

nixos-option で型・現在値を確認

# 「services.kea.dhcp4.enable は何?」を Nix 式の中に入る前に調べる
nixos-option services.kea.dhcp4.enable
# → 型, デフォルト値, 実際にどう設定されているか, 設定された場所(.nix:行) が出る

# REPL で nixpkgs の中身を覗く
nix repl '<nixpkgs>'
nix-repl> :l <nixpkgs/nixos>
nix-repl> config.services.kea.dhcp4.settings

rebuild ワークフロー

NixOS の運用は基本的にこのループ:

┌──────────────────────────────────────────────────────────────┐
│  1. /etc/nixos/modules/*.nix を編集                            │
│           │                                                  │
│  2. nix flake check (構文・型の事前チェック; flake 化していれば)  │
│           │                                                  │
│  3. nixos-rebuild dry-build  (ビルドのみ、活性化しない)          │
│           │                                                  │
│  4. nixos-rebuild test       (起動するが boot loader に書かない) │
│           │                                                  │
│  5. nixos-rebuild switch     (活性化 + boot loader 登録)         │
│           │                                                  │
│  6. (壊れた場合) nixos-rebuild switch --rollback                │
└──────────────────────────────────────────────────────────────┘

世代管理コマンド:

# 世代一覧
nix-env --list-generations -p /nix/var/nix/profiles/system
#  120   2026-03-19 12:00:01   (current)
#  119   2026-03-18 22:30:11

# 特定世代に切替
nixos-rebuild switch --switch-generation 119

# 古い世代の掃除 (30日より古いものを削除)
nix-collect-garbage --delete-older-than 30d

ルータでこの「壊れたら 1 コマンドで戻せる」が効くのは精神安定上とても大きい。深夜の作業で一番怖い「物理アクセスを伴うレスキュー」を回避できる。

物理ケーブル切替

一番ドキドキする瞬間。

[Phase A: 切替前]
  ONU ── (SFP+ DAC) ── Debian Router (enp1s0f0)
                                     │
                         CRS305 ── trunk ── Debian Router (enp1s0f1)

[Phase B: 切替中 (~30 秒)]
  ONU                  Debian Router (停止)
        \
         \             NixOS Router  (起動済み)
          \_____ (DAC 差し替え) _____/

[Phase C: 切替後]
  ONU ── (SFP+ DAC) ── NixOS Router (enp1s0f0)
                                    │
                         CRS305 ── trunk ── NixOS Router (enp1s0f1)
  1. Debian ルータの全サービス停止
  2. ONU → NixOS enp1s0f0 差し替え
  3. CRS305 trunk → NixOS enp1s0f1 差し替え
  4. NixOS 側で odhcp6c が DHCPv6-PD /56 取得 → MAP-E + Fixed IP + IPv6 SLAAC 自動構築

所要時間 30 秒。スマホの IPv6 が新プレフィクスに更新されるのを横目で見ながら確認:

$ curl -4 ifconfig.io
198.51.100.140
$ curl -4 --interface ipip-fixed ifconfig.io
203.0.113.80
$ curl -6 ifconfig.io
2001:db8:1010::1

検証結果

主要な機能をチェックリストで:

項目 結果
IPv4 MAP-E (VLAN 1010) 198.51.100.140
IPv4 Fixed IP 203.0.113.80
IPv6 (GUA) 2001:db8:1010::1
AdGuard Home → Unbound OK
DNS rewrite (*.chun37.com) 192.168.120.105
Kea DHCP4 active (5 サブネット)
tinc VPN (gsnet) active, 10.24.34.2 疎通
radvd (IPv6 SLAAC) active
nftables (6 テーブル) active
Netdata active (HTTP 200)

全部 OK。家族からの「ネット遅い」コールも無し。

ハマり集 — 4 件

実質ぶつかったのは下記の 4 件です。

ハマり 1: enp2s0 のルーティング競合

切替直後、IPv4 で 192.168.10.1 に SSH 不可。

# ip route
default via 192.168.10.254 dev enp2s0  proto static
192.168.10.0/24 dev enp2s0  proto kernel  scope link  src 192.168.10.1
192.168.10.0/24 dev enp1s0f1.1010  proto kernel  scope link  src 192.168.10.1

enp2s0 (linkdown) が 192.168.10.0/24 のルートと defaultGateway を持っていた。network.nix から enp2s0 の設定と networking.defaultGateway を削除して nixos-rebuild switch で復旧。

学び: NixOS は networking.interfaces.<n>.ipv4.addresses を書いた瞬間に link-scope route を載せる。linkdown でも route table には残るので、初期構築用の管理 NIC は構築後ちゃんと撤去すること。

ハマり 2: nixos-rebuild switch で IPv6 GUA がフラッシュ

switch の度に VLAN サブインターフェース上の IPv6 GUA が消える。NixOS のネットワーク再設定 (network-addresses-*.service の再 ExecStart) で ip addr flush 相当が走るため。fe80::/10 の link-local は残るが GUA だけ消えるという挙動。

当面の運用回避:

nixos-rebuild switch
/etc/router-scripts/assign-ipv6-prefix.sh /tmp/last-pd-prefix

恒久対策は assign-ipv6-prefix.servicepartOf / WantedBy=network-addresses-enp1s0f1.1010.service で連動させる予定 (これは別記事ネタ)。

ハマり 3: Kea DHCP4 の LPF ソケットロスト

nixos-rebuild switch 後に kea-dhcp4 の LPF (Linux Packet Filter, AF_PACKET) ソケットが無効化されて DHCP 応答が返らなくなることが稀にある。

ERROR [kea-dhcp4.dhcp4] DHCP4_PACKET_RECEIVE_FAIL failed to receive ...

Kea は I/F の up/down に追随しないので、再起動が必要:

# systemctl restart kea-dhcp4-server

Kea 側の挙動であって NixOS 起因ではないが、宣言的に書くからこそ rebuild 頻度が増えて踏みやすくなる。reloadTriggers ではなく restartTriggers に I/F 関連を含めるのが正解。

ハマり 4: Android の DoT (TCP 853) 不許可で AAAA 抑制

Android の「プライベート DNS: 自動」が tcp/853 で DoT 接続を試み、失敗すると AAAA クエリを抑制する 仕様。AdGuard Home は :53 でしか受けていなかったので、Android からだけ IPv6 名前解決が壊れた。

networking.firewall.allowedTCPPorts = [ ... 853 ];
# 加えて nftables input chain にも明示
# tcp dport 853 accept

を入れて解決。NixOS 移行とは直接無関係だが、Debian 時代に気付けなかった既存バグでもある。

切替後に得たもの

Before (Debian) After (NixOS)
設定が 10 箇所超に散在 /etc/nixos/ 配下に集約、git diff で読める
APT 外パッケージは自前管理 pkgs.tinc_pre / pkgs.adguardhomenix flake pin 可
バックアップ復元が祈り 別ハードに configuration.nix を持っていけば再現
切戻し = apt downgrade + 設定戻し nixos-rebuild switch --rollback 一発
apt full-upgrade が怖い チャンネル更新は意図したタイミングだけ

特に 「ロールバック (= 1 つ前に戻す)」が 1 コマンド なのは、ルータを触る心理的ハードルが激減しました。

移行後の進化 — NixOS で気軽に弄れるようになった例

NixOS 化してから、移行前ならとても踏み込めなかった変更を躊躇なく入れられるようになりました。 各機能を「1 モジュールの追加 or 差分」で完結できる のが効いている。代表的な後日談 4 件だけ:

後日談 日付 NixOS 上で起きたこと
VLAN 1020 (ゲスト) 新設 2026-04-30 network.nixvlanIds リストに 1020 追加 + nftables にゲスト隔離ルール追加。物理 AP の SSID 対応含めて 1 モジュールの diff
chrony 化 2026-04-14 services.timesyncd.enable = false; + services.chrony 有効化。CMOS 電池劣化で 起動時に RTC が 2017 年に巻き戻る事故 対策込み
vxlan-trunk 2026-06-07 〜 06-08 別拠点 (川越) との L2 ブリッジ (wg-remote underlay + vxlan1130 + VLAN 1130 で先行構築済み) を「単一 VLAN」から マルチ VLAN 対応 に拡張。br-trunk を VLAN-aware bridge にして 7 VID を per-VNI VXLAN でカプセル化
MSS clamp 両方向化事件 2026-06-08 vxlan-trunk 越しの WebSocket が 片方向 MSS clamp の見落とし で RST されるバグ。illust-notifier 不通で発覚

それぞれ、Debian 時代だったら 「動いてるルータを触りたくない」で先送り していたはず。詳しくは個別記事で書きますが、最後の MSS clamp 両方向化事件 だけは前回からの伏線回収なので少しだけ触れておきます。

後日談プレビュー: MSS clamp 両方向化事件

vxlan-trunk 越しに WebSocket セッションが長時間後に RST される 事象。原因は MSS clamp が片方向だけ (oifname 側) しか書かれていなかった こと:

  • SYN は通る (3-way OK)
  • 内側ホスト発信の SYN は MSS=1460 のまま出ていく
  • 相手側が「ピアの MSS は 1460」と記憶
  • データ送信時に MSS=1460 の TCP セグメントが vxt-<VID> (MTU 1366) で flood ドロップ
  • 長時間後に TCP RST

establish できるので一見正常に見えるのが厄介。修正は iifnameoifname両方 で MSS clamp する 2 行を nftables.nix に追加 → nixos-rebuild switch で即反映。この「即反映 → 駄目なら rollback」がすぐ手の届くところにあるから攻めた変更を試せる、という典型例でした。

まとめ — どの読者にも刺してほしい話

casual な読者へ: 「動いてるルータを別の OS で書き直す」は無謀に聞こえますが、要点は 「物理ケーブルだけ挿し替えて切戻し可能」 という戦略を最初に組んだことです。30 秒のダウンタイムで、何かあったら元に戻せる。家のインフラを攻めるときも、カナリア・ブルーグリーンの考え方 は使えます。

ソフトウェアエンジニアへ: ルータも infra-as-code の範疇です。nixos-rebuild switch = terraform apply--rollback = terraform state rollbackservices.<name> = Terraform module。Web 開発で当たり前にやっている「設定を PR、ロールバック可能、別環境で再現」がそのまま物理ルータに適用できる、というのが NixOS の現実的な意義です。

ネットワークエンジニアへ: VLAN / nftables / MAP-E / tc pedit / tinc 1.1pre / DHCPv6-PD という、業務機器なら別々のベンダ機を組み合わせる構成が、全部 1 つの宣言ファイルから生える 形になります。/etc/nftables.conf を手で nft add rule する運用バグが構造的に消える、/etc/protocols のような暗黙依存がサンドボックスで剥がれる、Kea の hook ライブラリパスが ${pkgs.kea} から動的に生える、といった「Debian で当たり前に踏んでいた地雷」が一通り解除されます。一方で「NIC 設定の link-scope ルートが残る」「rebuild で IPv6 GUA が消える」「Kea LPF ソケットがロスト」のような NixOS 固有の罠 が代わりに生えるので、トレードオフは見ておくべき。

NixOS 入門者へ: ルータという題材を通して、以下の NixOS 基礎機能を一通り使いました。

  • imports でモジュール分割
  • networking.* で IF・VLAN・nftables を宣言
  • services.<name> で既製サービス (Kea, AdGuard Home, Unbound, tinc, Netdata, radvd) を有効化
  • environment.etc."path".source でファイル配置
  • systemd.services.<name> で自前 unit を定義
  • pkgs.<name> でパッケージ参照、${pkgs.foo}/bin/foo で store path を埋め込み
  • nixos-rebuild switch / test / dry-build / --rollback で運用
  • nixos-option, nix repl '<nixpkgs>' で型と現在値を確認

「設定をコードで書き、ビルドして atomic に切替、壊れたら 1 コマンドで戻す」。これが体感できると、ルータ以外のサーバも NixOS で組みたくなります。続編 (vxlan-trunk, chrony, MSS clamp 両方向化など) はそれぞれ別記事で書く予定です。

Debianで10Gルータを作った話

家のインターネットの "玄関口" にあたる ルータ を自作した話を書きます。 一般の家庭で言うところの「プロバイダから渡される機械」「家電量販店で買う Wi-Fi ルータ」を、自分で PC パーツから組み立てて Debian で動かしました。

なぜそんな面倒なことをしたのか、何を頑張ったのか、どこに刺さってどう抜けたのかを、レイヤを分けて書きます。

  • まず比喩で全体像
  • 次にソフトウェアエンジニアっぽい言い回し (K8s Namespace / CORS / infra-as-code) で再説明
  • そのうえで実コマンド・version 番号・nftables ルール片で詰める

途中ところどころに 「(NixOS なら…)」 という囲みを挟みました。続編で同じ構成を NixOS に書き直すので、その伏線です。

この記事は Debian 13 trixie (13.2) で組んだ初代 の話。NixOS 版は次の記事で書きます。


なぜ自作したのか

家には少し変わった事情があります。

項目 普通の家 うち
インターネット側 (WAN) の速度 1Gbps 10Gbps
家の中 (LAN) の速度 だいたい 1Gbps 10Gbps
構成 パソコン・スマホ・テレビ ↑に加えてストレージサーバや Proxmox 数台

宅内のスイッチ間は 10G で組んでいて、ストレージサーバや Proxmox 間の通信、別拠点との L2 VPN ブリッジなど、「ルータを跨ぐ通信」が容赦なく 10G で飛んできます。家電量販店で売っている家庭用ルータは UTM (= セキュリティ機能) を有効化すると 1G すら出ない型番がほとんど、SFP+ を生で扱える小型市販品もまだ高価。それなら自作した方が早い、というのが今回の動機です。

ソフトウェアエンジニアの感覚に翻訳すると「マネージドサービスは高い & 機能が足りない & ベンダロックインがキツい、なら自前で書く」のと同じ判断。回線契約は enひかり (NTT フレッツ光クロス網経由) の 10Gbps、IPv6 は IPoE で v6プラス、IPv4 は v6プラスの MAP-E (通常用、NAT 共有)enひかり固定IPオプションの IP-in-IP トンネル (外公開用、固定グローバル 1 本) の 2 本立て。WAN は v6 ネイティブの上に IPv4 をトンネルで載せる構造です。

ハードウェア

筐体は ヤフオクで適当に拾ってきた Dell OptiPlex のスリムタワー。中古の法人払い下げ品で、しょっちゅう投げ売られている定番のやつです。これに PCIe で 10G NIC を 1 枚刺すだけ。

部品 型番 役割
筐体 Dell OptiPlex スリムタワー (中古) 本体
NIC #1 Broadcom BCM57810 (SFP+ 10GbE × 2) WAN + LAN トランク
NIC #2 Realtek RTL8111 (1GbE, オンボード) 管理用 (initial SSH)
ストレージ SATA SSD 465.8GB OS
OS Debian 13 trixie (13.2)

BCM57810 は中古市場で投げ売られている Dell の OEM カードで、bnx2x ドライバが Debian 標準カーネルに in-tree。apt install 不要でインストール直後から見えます。ethtool -k でオフロードを覗くと素直に乗っている:

# ethtool -k enp1s0f1 | egrep 'tcp-seg|gso|gro|tx-checksum|rx-checksum|rx-vlan|tx-vlan'
rx-checksumming: on
tx-checksumming: on
generic-segmentation-offload: on
generic-receive-offload: on
tx-tcp-segmentation: on
tx-tcp6-segmentation: on
rx-vlan-offload: on
tx-vlan-offload: on

1 ポートを ONU (フレッツ光クロスの 10G-EPON ONU) に、もう 1 ポートを コアスイッチ (MikroTik CRS305) に VLAN トランクで繋ぐ最小構成です。

                       +--------------------+
   10G-EPON ONU ───────┤ enp1s0f0  (WAN)    │ IPoE / DHCPv6-PD / MAP-E underlay
                       │                    │
                       │  Debian 10G Router │
                       │                    │
                       │ enp1s0f1  (LAN     ├──── CRS305 ──── 各 VLAN
                       │           trunk)   │        │
                       │ enp2s0   (mgmt)    │        ├── AP (Aruba)
                       +--------------------+        ├── Proxmox host
                                                    └── Workstation

予算はジャンク寄りの中古を組み合わせて 1 万円ちょっと。

ネットワーク設計 — VLAN で「区画分け」

宅内は機能ごとに VLAN (IEEE 802.1Q) で完全に分離しています。

家に例えると「同じ家の中だが、ゲスト用の玄関先・リビング・配電盤・物置を別扱いにする」という感覚。ソフトウェアエンジニア向けの言い方をするなら Kubernetes の Namespace に似てる: 物理的には同じクラスタ (= スイッチ + ケーブル) を共有しているけど、論理的には別の宇宙で、互いに触れない。

VID 名前 サブネット 用途
1001 mgmt 192.168.1.0/24 管理 / 工事用
1010 LAN 192.168.10.0/24 通常クライアント (信用ドメイン)
1083 gsnet 10.0.0.0/8 拠点間 L2 VPN
1100 server 192.168.100.0/24 Proxmox / Ceph public
1110 ipmi 192.168.110.0/24 IPMI / BMC (完全隔離)
1120 vm 192.168.120.0/24 VM / LXC コンテナ

ルータの物理 IF は enp1s0f0 (WAN: ONU) と enp1s0f1 (LAN: トランク)。 LAN 側は enp1s0f1.<VID>8021q サブインターフェース で終端し、それぞれの VLAN GW として <subnet>.1 を割り当てる、シンプルな構成です。

/etc/network/interfaces 抜粋:

auto enp1s0f1
iface enp1s0f1 inet manual
    up ip link set $IFACE up

auto enp1s0f1.1010
iface enp1s0f1.1010 inet static
    address 192.168.10.1/24
    vlan-raw-device enp1s0f1

# 他 VLAN 同様、5 本ぶん延々と書く

Linux 上ではこう見えます。

# ip -br link show type vlan
enp1s0f1.1001    UP    ...
enp1s0f1.1010    UP    ...
enp1s0f1.1083    UP    ...    master br-gsnet
enp1s0f1.1100    UP    ...
enp1s0f1.1110    UP    ...
enp1s0f1.1120    UP    ...

(NixOS なら…) networking.vlans."enp1s0f1.1010" = { id = 1010; interface = "enp1s0f1"; };networking.interfaces."enp1s0f1.1010".ipv4.addresses = [{ address = "192.168.10.1"; prefixLength = 24; }]; を並べるだけ。 mapAttrs を使えば VLAN 定義は 6 行のリスト から自動展開できる。続編の network.nix で実例を出します。

ファイアウォール: nftables

iptables ではなく nftables を選びました。理由は 3 点。

  1. テーブルを機能ごとに分けて書ける (機能別にレビュー可能)
  2. inet ファミリで v4/v6 を一本化できる
  3. ベンチで「ルールが増えても n でほぼ線形」(雪崩しない)

書いた人の感覚で言うと、iptables が古い手書き Apache httpd.conf なら nftables は今風の YAML 設定 + 型付き DSL

テーブル構成

Table Family 役割
inet filter inet input / forward / output、すべて policy drop
ip nat ip MASQUERADE (map-wan) + DNAT
ip mangle ip MSS clamp (MAP-E 越え 1460 → 1414)
inet raw inet TFTP conntrack helper (PXE boot)
ip caddy ip 固定 IP (203.0.113.80) → CT 105 Caddy DNAT
ip asterisk ip 固定 IP RTP UDP 10000-10010 → CT 144 DNAT
# nft list table inet filter | head
table inet filter {
    chain input {
        type filter hook input priority filter; policy drop;
        iifname "lo" accept
        ct state established,related accept
        ip6 nexthdr icmpv6 accept
        ip protocol icmp accept
        iifname { "enp1s0f1.1010", "enp1s0f1.1100", "enp1s0f1.1120" } tcp dport 22 accept
        ...
    }
}

VLAN フォワード ホワイトリスト

policy=drop なので、明示許可だけが通る。家のたとえで言うと「ゲスト用玄関先からはインターネットへは出られるが、リビング (LAN) や書斎 (サーバ) へは入れない」。Web 開発で言うなら CORS や RBAC のホワイトリスト に近い感覚です。

From To Proto / Port 用途
1010 (LAN) map-wan any 通常 LAN → Internet (MAP-E)
1010 10.0.0.0/8 any tinc 越しの拠点間
1010 1100 (server) any サーバ管理
1010 1120 (vm) tcp/22, udp/69, tcp/80 SSH / TFTP (PXE) / CT 130 HTTP
1010 1110 (ipmi) tcp/{80,443} BMC Web のみ
1100 1120 udp/69 TFTP (PXE)
1120 (CT 130) 1100 any Ceph RGW / PostgreSQL
1001 / 1100 / 1120 ipip-fixed any 固定 IP 出口
ipip-fixed 1120 (CT 105) tcp/{80,443} Caddy 受け
ipip-fixed 1120 (CT 144) udp/10000-10010 Asterisk RTP
gsnet 1120 (CT 144) udp/{5060, 10000-10010} SIP トランク
1110 * drop (BMC 完全隔離)

実装は iifname "enp1s0f1.<VID>" oifname "enp1s0f1.<VID>" ... でベタ書き。ルール数 200 行程度なら見通しは保てます。

後年の罠の伏線: ipencap

WAN 入口 (enp1s0f0) で 4in6 (= MAP-E と ipip-fixed underlay の両方) を受け入れるルールを ip6 nexthdr ipencap名前指定 で書いている。Debian は netbase パッケージが /etc/protocolsipencap を proto 4 の別名として登録してくれる ので動く。NixOS の iana-etc (IANA 正式名のみ) には ipencap は無く ipv4 しか登録されていない ので、移行時に Could not resolve protocol name "ipencap"nixos-rebuild が落ちます。続編で数値 4 への書き換えに繋がる伏線。

(NixOS なら…) networking.nftables.ruleset = '' ... ''; のヒアドキュメントに 6 テーブルぶん全部書く。 nixos-rebuild switch を通さないと反映されない = 手で nft add rule で足す運用が物理的に不可能になる。 Debian 時代に頻発していた「ファイルと実行状態の乖離」というバグ クラスが、構造的に消えます。

MTU バジェット — 家庭ルータと業務ルータの差が一番出る部分

トンネルを重ねるとパケットの「載せられる中身」が縮みます。MAP-E 越えと tinc 越えで MTU が違うので、整理しておきます。

                              +-- MAP-E -------- 1460 (MSS clamp で 1414)
  WAN 1500 (Ethernet) -------+
                              +-- ipip-fixed --- 1460 (4in6 / ip6tnl, IPv6 ヘッダ 40B)
                              |
                              +-- tinc (TAP) --- 1420 (UDP/IPv6 overhead)

  LAN trunk 1500 ------------- enp1s0f1.<VID> 1500

MSS clamp は ip mangle の POSTROUTING に MAP-E 出口で 1 行入れて済ませています。「SYN パケットの MSS option を書き換えて (= TCP のレイヤで宿主が大きいパケットを送ってこないように予防接種を打つ)」イメージ。

# nft list table ip mangle
table ip mangle {
    chain postrouting {
        type filter hook postrouting priority mangle; policy accept;
        oifname "map-wan" tcp flags syn tcp option maxseg size set 1414
    }
}

この時点では「内向きから外向き 1 方向」しか書いていません。後日 vxlan-trunk 越しで MSS clamp 両方向化を強いられる事件が起きる ので、これも伏線。詳細は次の記事で。

DNS: AdGuard Home + Unbound の二段構え

「グーグルにアクセスして」と言われたとき、コンピュータは google.com を機械が分かる住所 (IP アドレス) に変換します。これを DNS と呼びます。

家のルータでは 2 段構えにしました。

クライアント ──► AdGuard Home (0.0.0.0:53 / [::]:53, AAAA on)
                    │ (上流に問い合わせ)
                    ▼
                Unbound (127.0.0.1:5335)
                    │ (再帰解決 + DNSSEC 検証)
                    ▼
                ルート DNS / 権威 DNS
役割 担当 何をするか
前段 (受付) AdGuard Home v0.107.71 広告フィルタ、アクセスログ、クライアント別ポリシー、DNS rewrite
後段 (再帰) Unbound 1.22.0 本物のキャッシュ、再帰、DNSSEC 検証、内部 RR (local-data)

*.chun37.com (宅内向けワイルドカード) は AdGuard 側の DNS rewrite192.168.120.105 (Caddy CT) に振っています。ベアドメイン chun37.com は GitHub Pages を指したいので、AdGuard 側で書き換えずに上流に透過。

ハマり: Unbound の local-data ワイルドカード非対応

最初は Unbound 側の local-data だけで *.chun37.com を返そうとしましたが、Unbound の local-data はワイルドカードを展開してくれない。1 つずつ FQDN を列挙する必要があります。一方 AdGuard Home の rewrite はワイルドカード OK。ここで結構ハマって AdGuard 側に寄せました。

Debian での導入の苦しみ

# Unbound は APT
apt install unbound
vi /etc/unbound/unbound.conf.d/local-records.conf

# AdGuard Home は APT 外 (公式インストーラ)
curl -s -S -L https://raw.githubusercontent.com/AdguardTeam/AdGuardHome/master/scripts/install.sh | sh -s -- -v
# → /opt/AdGuardHome/ に展開、systemd unit を install.sh が自前で書き込む
vi /opt/AdGuardHome/AdGuardHome.yaml

AdGuard Home の アップデートは GUI からポチる必要があり、apt upgrade の対象外。「APT 外のソフトを覚えていないと、年単位でアップデート漏れする」という運用負債の典型例。

(NixOS なら…) services.adguardhome.enable = true;services.unbound.enable = true; の 2 行。 AdGuard Home のバイナリは pkgs.adguardhome で nixpkgs から取得 → APT 外という概念が消える。 上流のバージョン追跡は nixpkgs (実体は GitHub Actions の bump bot) に丸投げできる。

DHCP: Kea + 自作 WebUI

家の中の機器に「あなたの住所はこれだよ」と渡す係を DHCP と呼びます。これも Kea (ISC DHCP の後継) という Linux のソフトに任せています。Web エンジニアに馴染みのある JSON 設定 + REST 風 API (Control Agent, 127.0.0.1:8000) で操作できるのが最高。

# systemctl status kea-dhcp4-server
● kea-dhcp4-server.service - Kea IPv4 DHCP daemon
     Active: active (running) ...

Kea 2.6.3 を 5 サブネットぶん 設定。lease_cmds フックを有効にすると Control Agent 経由でリース情報を JSON で叩けるので、これに乗っかって Kea Manager という WebUI を自作しました (Go + 簡素な HTML、/usr/local/bin/kea-managerhttp://192.168.10.1:8080)。

$ curl -s http://127.0.0.1:8000/ -H 'Content-Type: application/json' \
       -d '{"command":"lease4-get-all","service":["dhcp4"]}' | jq '.[].arguments.leases | length'
84

家族から「Wi-Fi に繋がらない」と言われたときに、ブラウザでリース一覧と予約状況を見られるだけで サポートコストが劇的に下がりました。プラットフォームエンジニアなら共感してもらえると思うんですが、「社内向けのちょっとした管理画面の有無で運用負荷が桁で変わる」やつです。

なお kea-dhcp6kea-dhcp-ddns はパッケージ依存で勝手に上がってくるが、設定はデフォルトのまま実質未使用 (IPv6 は SLAAC で配るので困らない)。

Debian の Kea 設定ファイル

{
  "Dhcp4": {
    "interfaces-config": { "interfaces": ["enp1s0f1.1010", ...] },
    "subnet4": [ ... ],
    "hooks-libraries": [ { "library": "/usr/lib/.../libdhcp_lease_cmds.so" } ]
  }
}

Dhcp4 キーがトップに来るのがポイント。続編でこの階層が罠になります。

(NixOS なら…) services.kea.dhcp4.settings = { interfaces-config = ...; subnet4 = ...; }; と書く。 NixOS モジュールが 自動で Dhcp4 キーを付ける ので、Debian のファイルをそのまま貼ると {"Dhcp4":{"Dhcp4":...}} の二重ネストで起動失敗します。これも続編で詳しく。

IPv4: MAP-E + 固定 IP のデュアル運用

ここが一番ややこしい。

MAP-E って何?

フレッツ網は IPv6 が素のネットワーク で、IPv4 はその上を間借りしています。具体的には IPv4 パケットを IPv6 パケットの中に包んで (= IPv4-in-IPv6 カプセル化) ISP のゲートウェイまで運び、そこで IPv4 として吐き出す。

このカプセル化方式が MAP-E (RFC 7597)。「IPv6 アドレス + 決められたポート範囲」のセットで IPv4 グローバルアドレスを 1 本シェアする仕組みです (= 1 つの IPv4 を 16 ホストくらいで分け合う)。

ソフトウェアの世界で言うと VPC 上で NAT GW を共有してる ような気分の構成。ただし NAT GW 自体は ISP 側にあって、宅内ルータがそこに向けてトンネルを掘る、という形になります。

Fixed IP も別途

外から到達可能な 固定グローバル IPv4 (203.0.113.80)enひかりの IPv4 固定IPオプション で 1 本もらっていて、これは ipip-fixed トンネルで生やしている。実体は IPv4-in-IPv6 (4in6, RFC 2473) の ip6tnl で、underlay はフレッツ光クロスの NGN IPv6。enひかり側 GW (2001:db8:225:100::65) との間に IPv6 トンネルを張って、その中を IPv4 が流れる構造です。MAP-E と underlay は同じ (どちらも IPv4-in-IPv6) で、違うのは IPv4 をシェアするか (MAP-E) / 占有するか (固定IP) だけ。

# ip -d link show ipip-fixed
22: ipip-fixed@NONE: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1460 ...
    link/tunnel6 2001:db8::1 peer 2001:db8:225:100::65
    ip6tnl ipip6 remote 2001:db8:225:100::65 local 2001:db8::1 ...
Tunnel Type 出口 IP 用途
map-wan MAP-E (v6プラス / JPNE) 198.51.100.140 通常 IPv4 (NAT)
ipip-fixed IP-in-IP (enひかり IPv4 固定IPオプション) 203.0.113.80 外公開 / tinc underlay

出口を MAP-E / Fixed IP のどちらに流すかは ポリシールーティング (ip rule) で決めます。アプリのルーティングテーブルとほぼ同じ概念で、Web の middleware っぽい仕組み。

# ip rule
0:      from all lookup local
50:     from all fwmark 0x1 lookup fixed_v4    # tinc 発 (mark 0x1) は Fixed IP へ
99:     from 10.0.0.0/8 lookup main            # gsnet 宛は通常テーブルへ
32766:  from all lookup main
32767:  from all lookup default

MAP-E ソースポート集合の強制 (tc pedit)

MAP-E はソースポートが集合制約を受けるので、tc filterpedit で SNAT 後のソースポートを許可集合に強制している。これは MAP-E ルータ自作勢には定番ですが、業務機器 (Cisco / Juniper) では基本やらない芸:

# tc -s filter show dev map-wan
filter parent 1: protocol ip pref 1 u32 chain 0
filter parent 1: protocol ip pref 1 u32 chain 0 fh 800:: order 2048 key ht 800 ...
  action order 1:  pedit action pipe keys 1
    key #0  at 20: val 0xc0000000 mask 0x0000ffff offset 0 ...

MAP-E トンネル構築は計算が泥臭く、シェルスクリプト /etc/router-scripts/map-e-setup.sh に押し込んでいます。起動順序は /etc/network/interfacespost-up で叩いたり、自作 .service ファイルを /etc/systemd/system/ に書いて After= で並べたり、「どこにある何がいつ動くか」が頭の中だけにある 状態。これも辛さの原因の 1 つ。

(NixOS なら…) environment.etc."router-scripts/map-e-setup.sh".source = ./scripts/map-e-setup.sh; で配置。 systemd.services.map-e-setup = { wantedBy = [ "network.target" ]; serviceConfig.ExecStart = "/etc/router-scripts/map-e-setup.sh"; }; で起動順を宣言。 /etc/ を直接触らない」 のが Nix の作法。/etc/ は Nix が /nix/store/... への symlink として配置する。

IPv6: ネイティブ + DHCPv6-PD

v6プラスの IPv6 は IPoE ネイティブで、ONU の先で直接 IPv6 が見えます。ルータの仕事は:

  1. wide-dhcpv6-clientDHCPv6-PD /56 をもらう (ISP が「/56 のブロックをあげるから自由に分けて使って」と言ってくれる)
  2. /etc/wide-dhcpv6/assign-ipv6-prefix.sh で /56 を VLAN ごとに /64 へ機械的に切り分ける
  3. radvd で各 VLAN に RA (Router Advertisement) を撒く (RDNSS でルータの IPv6 を DNS 先として配布)
ONU ─► enp1s0f0 (RA 受信 / SLAAC で WAN GUA)
         │
         └─► wide-dhcpv6-client (DHCPv6-PD /56 取得)
                  │
                  ├─► assign-ipv6-prefix.sh (/56 → /64 × N VLAN)
                  └─► radvd.conf 自動生成 → radvd 起動
$ ip -6 addr show enp1s0f1.1010 | grep inet6
    inet6 2001:db8:1010::1/64 scope global
    inet6 fe80::xxxx/64 scope link

運用ルール: radvd.conf は手で触らない

スクリプトが書き換える方式なので、手で触らないことだけルール化 した。RA を間違えるとブラウザの PRIVATE_ADDRESS エラーで気付くしかなくなり、デバッグが面倒なので lint レベルで書き換え経路をスクリプトに一本化しました。

IPMI VLAN (1110) は IPv6 でも forward を切って 完全隔離。BMC ファームに脆弱性が出ても LAN からしか触れないことを保証したい。

(NixOS なら…) nixpkgs に wide-dhcpv6 は無い → OpenWrt 由来の odhcp6c に乗り換え ることになります (続編)。 ロジック (assign-ipv6-prefix.sh) は同じインタフェースで書いてあれば ロジック側無修正で済む。 言語の置き換えに耐えるよう 「外部依存はスクリプト内で吸収しておく」 のは、Nix 移行を見据えると地味に効く設計指針。

L2 VPN: tinc (gsnet)

複数拠点の物理 L2 をひとつのブロードキャストドメインに繋ぐために tinc 1.1pre を使っています。gsnet という名前のメッシュ VPN で、10.0.0.0/8 を切って各拠点に静的に割り当て。

+--- Debian router ---------------------------------+
|                                                   |
| enp1s0f1.1083 ────┐                               |
|                   ├── br-gsnet (MTU 1420) ────────┼── tinc TAP
| tinc.gsnet ───────┘                               |
+---------------------------------------------------+
  • ノード名: aibauiha
  • IP: 10.24.34.2/8 (br-gsnet 上)
  • MTU: 1420 (UDP/IPv6 overhead を引いた値)
  • BindToAddress: IPv4 (ipip-fixed) + IPv6 デュアル
  • ConnectTo: gsngw01, suzukautako, linuweb, kimon, rabbit_house (port 655)
  • Mode: switch (TAP モード、L2 そのまま流す)

WireGuard だと L3 トンネルになるので、L2 を持って行きたい (= 同じブロードキャストドメインに居たい) ときには tinc の TAP モードが今でも便利

tinc バージョンの罠

ソース バージョン
Debian dpkg tinc 1.0.36-2.1
実バイナリ (/usr/local/sbin/tincd) tinc 1.1pre18-242-g940d15c4 (自前ビルド)

1.1pre 系は SPTPS (新プロトコル) + ChaCha-Poly1305 cipher を喋れる。ピア同士が両方 1.1pre なら UDP 経路の暗号化処理が軽くなる 期待があり、10G 越しに L2 ブリッジで拠点間メッシュを張るならここが効くだろう、という動機でバージョンを上げた。Debian 公式 (1.0.36) のままでも疎通は問題なく回るが、暗号で頭打ちさせたくないので 1.1pre に寄せている (= 全ピアが 1.1pre なら新プロトコルに乗る、片方が 1.0 系ならその経路はレガシーに落ちる)。

# 自前ビルド
git clone https://github.com/gsliepen/tinc -b 1.1
./configure --prefix=/usr/local
make && make install
# → /usr/local/sbin/tincd

# systemd の ExecStart を override で差し替え
cat > /etc/systemd/system/tinc@gsnet.service.d/override.conf <<EOF
[Service]
ExecStart=
ExecStart=/usr/local/sbin/tincd -n %i -D
EOF
systemctl daemon-reload

(NixOS なら…) services.tinc.networks.gsnet = { package = pkgs.tinc_pre; ... }; の 1 行で 1.1pre18 に固定できる。 「自前ビルド + systemd override」という 3 ファイルの密結合が 消える。鍵 (rsa_key.priv, ed25519_key.priv, hosts/*) はそのまま scp でコピー。

監視: Netdata + iperf3

  • Netdata 2.9.0 を APT リポジトリ (netdata-repo) から入れて root 実行。1 秒間隔の細かいメトリクス (bnx2x の Rx/Tx パケット、conntrack エントリ数、nftables カウンタ) をブラウザで見られる。Prometheus を入れるほどじゃないけど Grafana 風の見た目が欲しいときに、apt install netdata 1 発で終わる軽さがちょうどいい。
  • iperf3-gsnet.service として iperf3 -s -B 10.24.34.2 を常駐 (tinc 越しの帯域測定用)。tinc@gsnet.service への依存を After=/Requires= で書いてあります。

iperf3 のサービス定義は手で /etc/systemd/system/iperf3-gsnet.service を書いた。これも git で追っていないと、半年後に「これ何のサービスだっけ?」となる。

(NixOS なら…) services.netdata.enable = true; で済む。 iperf3 のような単発常駐は systemd.services.iperf3-gsnet = { wantedBy = [ "multi-user.target" ]; after = [ "tinc.gsnet.service" ]; serviceConfig.ExecStart = "${pkgs.iperf3}/bin/iperf3 -s -B 10.24.34.2"; }; と Nix 式で直接書ける。/etc/systemd/system/ を直接編集する必要が無い

稼働サービス棚卸し (Debian 13 時代)

サービス バージョン 備考
nftables 1.1.3 起動時適用
AdGuard Home v0.107.71 /opt/AdGuardHome/
Unbound 1.22.0 127.0.0.1:5335
Kea DHCP4 2.6.3 5 subnets
Kea Control Agent 2.6.3 127.0.0.1:8000
Kea Manager (自作) カスタム Go, WebUI
Kea DHCP6 / DHCP-DDNS 2.6.3 パッケージ依存で稼働、設定はデフォルト
radvd 2.20
wide-dhcpv6-client 20080615 DHCPv6-PD
tinc (gsnet) 1.1pre18 自前ビルド + systemd override
Netdata 2.9.0
iperf3 3.18 gsnet 専用、bind 10.24.34.2
OpenSSH 10.0p1

動作実測

観点 実測
LAN → WAN (MAP-E 越え) スループット 800–900 Mbps (v6プラスの IPv4 実効に近い)
LAN 内 VLAN 跨ぎ (router 経由) 9.4 Gbps (ほぼ線速)
平常時 CPU 1 コア 5% 未満 (MAP-E + nftables + radvd 全部走らせて)
conntrack 平均 数千 (NAT は MAP-E 出口だけ)
電気代 知れている (アイドルのうち)

家庭の常用なら困らない。MAP-E 越えで 900Mbps 出るのは bnx2x + 1 コアで通すには十分です。

運用してみての所感 — どこが本質的に辛いか

「動く」状態は数日で作れた。が、運用 1 年で見えてきたのは 設定の散逸とパッケージ管理の摩擦 のほう。casual な言い方で並べると「レシピが冷蔵庫・食器棚・引き出し・机の上に分散していて、料理を作り直すたびに探し回る」状態です。

辛い 1: 設定の散逸

機能 設定の場所
ネットワーク /etc/network/interfaces
ファイアウォール /etc/nftables.conf
DHCP /etc/kea/*.conf
DNS (フィルタ) /opt/AdGuardHome/AdGuardHome.yaml
DNS (再帰) /etc/unbound/unbound.conf.d/*.conf
DHCPv6-PD /etc/wide-dhcpv6/*
IPv6 SLAAC /etc/radvd.conf (スクリプト生成)
MAP-E /etc/router-scripts/map-e-setup.sh
tinc /etc/tinc/gsnet/*
tinc override /etc/systemd/system/tinc@gsnet.service.d/
iperf3 unit /etc/systemd/system/iperf3-gsnet.service

どこに何があるかを覚えていないと、変更がレビューできない。git log で追えるようにはしてあるが、「何を入れた / 何を消した」を全体俯瞰するのが難しい。

辛い 2: APT 外パッケージとの戦い

  • tinc 1.1pre → 自前ビルド (/usr/local/sbin/)
  • AdGuard Home → 公式インストーラ (/opt/AdGuardHome/)
  • Kea Manager → 自作 Go バイナリ (/usr/local/bin/)
  • Netdata → APT 外リポジトリ

apt full-upgrade で壊れないように祈る運用。APT のメンテ責任範囲 (= APT パッケージ) と APT 外 (= 自分のメンテ責任) が頭の中にしか書かれていない のが本質的に辛い。

辛い 3: ロールバックがない

「rebuild して動かなければ前の状態に戻す」という操作が Debian には標準で無い/etc/ を git で管理しているとはいえ、git revertsystemctl daemon-reloadnft -f → … を 順序通り に再現する必要がある。深夜にこれを間違えてネットワーク全切断したら詰む。

辛い 4: バックアップ復元が "祈り"

もう 1 台に同じ環境を作る再現コストが高い。tar.gz を撒くだけでは systemd unit / override / 自前バイナリの依存関係が再現できない。ハードが壊れたら涙目。

エンジニア視点での言い換え

これって要するに infra-as-code が無いプロジェクト の苦しみそのもの。Web 開発で言えば「本番 EC2 に SSH で入って手で vim してる」状態。設定変更が PR にならない、ロールバックができない、誰がいつ何を変えたかが追えない

ルータという「絶対に止めたくない」かつ「設定ミスでネットワーク全切断する」装置こそ宣言的に書きたい、というのが結論。

次回予告

次は この構成をそっくり NixOS で書き直して infra-as-code 化 した話。

  • /etc/nixos/configuration.nix 1 本 (実際にはモジュール 9 分割) でルータ全体を宣言的に定義
  • 本記事で見た パス・ファイル・サービス定義 が、NixOS では どの Nix 式に変換されるか を対応表付きで詳しく書きます
  • nixos-rebuild switch --rollback で物理ルータがロールバック可能になる、という精神安定上ものすごく大きい話

続編に続きます。

おうちネットワーク遊び

やりたかったこと

  • MAP−E の v6 プラスで接続したい
  • v6 プラス固定オプションを使用してサーバを公開したい
  • サーバのネットワークと、メインのネットワークを分離したい(DMZ?用語わからん)
  • ゲストネットワークを用意したい

作業開始

Day0

構成としては、

  • RTX 830 で MAP-E トンネルを張る
  • Fortigate 50E で IPIP トンネルを張る
  • RTX 830 の LAN を Fortigate 50E の WAN に繋ぐ

の状態だった。

Day1

実現しようとした構成

  • RTX 830 で MAP-E トンネルを張る
  • Fortigate 50E で IPIP トンネルを張る
  • RTX 830 の LAN を Fortigate 50E の WAN に繋ぐ
  • Fortigate 50E のルーティング情報に、「デフォルトゲートウェイを MAP-E トンネルとする」「src がサーバのネットワークなら IPIP トンネルをゲートウェイとする」を追加する ←New✨

OpenWRT の Luci 上から静的経路設定をしても ip route コマンドから設定を確認出来ず、設定が悪いか OpenWRT が悪いかの2択に絞り込む。

iptables なら簡単に出来るのに…

Day2

Fortigate 50E の IPIP トンネルのインターフェースを削除して再度作成しようとしたら、IPIP トンネルがうまく張れない状態になる。 バックアップを取り忘れていた。

設定をこねくり回しても接続出来ないため、一旦諦める。

教訓 設定を変更するときは、バックアップはちゃんと取ろう!

Day3

設定をこねくり回す。

WAN インターフェースの ifaceid が設定出来ていないために、正しくパケットが返ってきていない状態だったことに気付く。 IPIP トンネルを確実に張ることが出来るようになる。

しかし、ルーティング情報が反映されないので色々調べていたら、ポリシーベースルーティングとやらにたどり着く。 ip rule というコマンドがあることを知った。

色々設定してみても、思ったとおりには動かなかった。

Day4

ソフトウェアの常識「1つのコンポーネントに複数の役割を持たせない」を用いることで、設定の破壊を防ごうと考える。 そこで考えた構成が以下の通り

  • RTX 830 で IPIP トンネルを張る ←New✨
  • 別のルータで MAP-E トンネルを張る ←New✨
  • Fortigate 50E の WAN にそれぞれの LAN をつないで、ルーティングを行う ←New✨

RTX 830 で IPIP トンネルを張ることには成功した。

急遽、稼働していない WX6000HP を拾いにいき、MAP-E をコイツに任せることにした。

起動して WAN を接続すると、「回線タイプを判別しています。しばらくお待ちください」のまま何分たっても返ってこない。微妙すぎる。 諦めて WAN の接続を外すことで回線タイプの判別をスキップ。管理画面に入ってから WAN を接続することでいい感じに操作が出来る状態になった。

IPIP トンネルと MAP-E トンネルが張れたので、Fortigate 50E の設定をする。 しかし、思ったとおりのルーティング情報が反映されない。

この Fortigate 50E が悪いのか?と考え始める。

Day5

この Fortigate 50E が悪い可能性を考え、別の Fortigate 50E を用意するために友人宅へ向かう。 2つの Fortigate 50E を入手したので、動作確認をする。

やはり設定が反映されないので、機体ではなく OpenWRT か設定が悪い状態へ絞り込めた。

YAMAHA に乗っかることで全てが解決する!」と思い込んだ私は、WAN が2つある Fortigate 50E の代わりを探すことにした。

WAN が2つあってヤフオクに転がっていていい感じの値段で買えるのは、RTX 1210 か RTX 3500 のどちらかであった。 「うーーーんデカい方が強い!」ということで、RTX 3500 を落札。

届くのを待つことにした。

Day6

RTX3500 が届いた。

組もうとした構成は以下

  • RTX 830 で MAP-E トンネルを張る
  • Fortigate 50E で IPIP トンネルを張る
  • RTX 3500 の WAN とそれぞれの LAN をつなぎ、ルーティングを行う ←New✨

RTX 3500 を起動したが、ファンの音があまりにもうるさすぎる。 作業部屋に置けるものではないが、仕方ないので置いたまま生活することになりそうだ。

RTX 3500 の設定を詰められず、疲れて1日が終わる

Day7

RTX 3500 の設定を詰める。

デフォルトゲートウェイと filter の設定がうまく反映されない。

諦める。

Day8

一旦状況の整理をするため、ホワイトボードに実装したい構成を書き出した。

友人に見てもらったところ、「どうしてそんなにルータが必要なの…?」「ソフトウェアの常識はハードウェアに通じないよ」などと言われる。

「じゃあどうするねんな」と言ったところ、MAP-E トンネルを張るルータと IPIP トンネルを張るルータで別のネットワークを作成すれば良い とのこと。

「お互いの LAN に接続したら DHCP のアドレス配布が混線するじゃろ…」と思ったが、ポートごとにネットワークを区切れば良いことに気付く。

RTX 830 の LAN 分割機能を用いて lan1.5 をルータ用ネットワークの IP アドレスに設定し、Fortigate 50E の eth5 をルータ用ネットワークの IP アドレスに設定する。 お互いのルータに静的経路設定を行い、反映されていることを確認した。

成功である。 こんなに簡単な話だったのか…

感想

ネットワーク構成は脳内で完結させるのではなく、書き出して他の人にレビューしてもらうことが大切だと感じた。

RTX 3500 が余ったので、有効活用する方法について考えている。

ネットワークは難しい。

JetBrains IDEでREADME.mdを開くとクラッシュする

環境

Ubuntu 24.04

6.6.0-14-generic

IntelliJ IDEA Ultimate 2023.3.3

原因を調査する

ディスプレイサーバのプロトコルを変更する

  • Wayland: 発現した
  • X: 発現した

IntelliJ IDEA のバージョンを変更する

  • IntelliJ IDEA Ultimate 2024.1 EAP: 発現した
  • 2023.3.4 Release Candidate: 発現した
  • 2023.3.3: 発現した
  • 2023.2.5: 発現した
  • 2023.1.5: 発現した
  • 2022.3.3: 発現しなかった
  • 2022.2.5: 発現しなかった

別の JetBrains IDE を使用する

  • GoLand 2023.3.3: 発現した

プラグインのクラッシュを疑う

ターミナルから起動する

FATAL:credentials.cc(127)] Check failed: . : Permission denied (13)

と出てきたので Google で検索すると、 https://youtrack.jetbrains.com/issue/IDEA-319751 が見つかる

調査結果

対処方法

https://youtrack.jetbrains.com/issue/IDEA-319751/IDE-exits-immediately-after-opening-the-folder#focus=Comments-27-7315116.0-0 を参照する

Kaede Higuchi Live 2021 "AIM" に行った

この記事は、オタクのお気持ち表明のような物です。

要点まとめ

  • チケット消えて、開演5分前まで会場前で待ち
  • オール着席・コール禁止ライブは面白くない
  • ライブの内容は良かった

チケットが消えた件

今回のライブは、イープラスアプリ内でのスマチケ(スマートチケットかな?)というシステムでチケットが発券されました。

「機種変更などは済ませてからチケットをダウンロードしてください」的なことが注意書きにあったので、前日夜にチケットをダウンロードしました。多分1回きりしかダウンロード出来ないんだろうな~ということを勝手に想像しました。

チケットをダウンロードしようとイープラスアプリを開くと、更新を求められました。

更新をしてアプリを開いたら、謎のエラーダイアログが出て起動しません。何かがクラッシュしてるようです。

仕方がないので、アプリを再インストールしてチケットをダウンロードします。インストール直後にうまく動いたので、アップデートで何かが失敗したのかな?と思っていました。会場に着いてから、同じエラーダイアログが出て起動できなくなるとも知らずに。

チケットをダウンロードしたら、席番がわかるようになります。偶然、友人に Discord 上で席の番号を伝えていました。この行動が運命を左右します。

当日会場に着いて、イープラスアプリを開いてチケットの確認をしようとしたら、昨日の夜に見たエラーダイアログが出てきます。

「あ、起動しないしこれは終わった。しかし再インストールすれば開ける。」ということで、イープラスアプリの再インストールを行います。

アプリを再インストールしたにも関わらず、エラーダイアログが出続けます。「あれ?これ死んだのでは?」と思い、会場前でアナウンス等を行っているスタッフに話をしに行きました。

起きた問題は、

  • チケットを確認しようとしたら、アプリがクラッシュして開けない
  • 別のスマホで確認したら、チケットが一度きりしかダウンロード出来ない

の2点です。

これらを伝えたら、スタッフさんは中に確認へ行ってくれました。「別の者が来る」ということで、寒さの中待っていました。

会場整理をしているスタッフの方とは違う見た目の方が来ました。少し権限を持ってる人だったのでしょうか。

先程と同じ内容の話をしたら、「開演5分前に席が空いていることを確認出来次第ご案内します。」という回答が得られました。

開場16時半・開演17時半で、私が会場に到着したのは16時40分でした。

開演5分前まで待機するように頼まれたのは16時54分なので、30分入場できず会場前で待ちぼうけをする事になりました。

イープラスアプリのバグのせいでチケットが消え、寒い中30分無意味に会場前で時間を潰す人になってしまったのです。

開演50分前に会場に着いたのにも関わらず、開演5分前に入場した弊害

前説が聞けない

通常ライブの前説では、ライブ中の禁止行為等を説明することが多いです。禁止行為の説明等が聞けないので、何をしたら駄目なのかわかりません。

公式サイトには、ライブ中の禁止行為等の説明が書かれていませんでした。「新型コロナの拡大対策をします」しか書かれていませんでした。

会場内に入りライブが始まり、周囲のオタクの行動を眺めていたところ、2つのレギュレーションが見えてきました。

  • オール着席
  • コール禁止

コロナ対策ということでやっているのでしょうか。「楽しめないレギュレーションだな」と感じました。

レギュレーションに対して感じたことは、下でもう少し掘り下げます。

怒りの感情でライブが楽しめない

自分の失敗で入場出来なくなったわけではないので、怒りというものが湧いてきます。

怒りの矛先はイープラスです。イープラスアプリを開発した人間でしょうか。

「こんなバグがあるアプリをリリースして、お金やチケットを扱うなんて酷すぎる!」とキレ散らかしていました。

ライブ前は、"推しのライブなので楽しみたい" という気持ちを持って会場に向かいます。

入場しようとしたら入場が出来るかわからない状態になり、かなり寒い中で待たされたら、楽しみたい気持ちはかき消されてしまいます。

入場しても場の盛り上がりにはついて行けず、一人イライラしながらライブを見る事になり、純粋に楽しむことが出来ませんでした。

オール着席・コール禁止というレギュレーション

コロナ禍で感染を広げないためには仕方がないレギュレーションだと思います。ライブ開催が原因で感染が広がったら、演者や運営も大迷惑です。

感染を広げないよう対策するのは良いのですが、楽しいか楽しくないかという問題は全く別です。

楽しくなかったです。

会場にいるオタクの大半が棒振り地蔵になっていました。キモい。

ライブでは、動いて声を出すことで体のリソースをたくさん使います。これによってライブに参加している気持ちが高まります。一体感とかいう奴かもしれません。

オール着席でコール禁止の場合すべてのリソースが余った状態になり、ライブを聞いているだけになります。

リソースが余った結果、Twitter を一生見てました。

オール着席のデメリット

曲に合わせて動くことが困難

座っていると足先でリズムを取ることしかできません。

私はリズムに合わせて体を動かすタイプなので、足先でリズムを取るのは物足りない感じがしました。頭も振りづらかったです。

周囲のオタクの振動が伝わってくる

ライブが行われるホールは、基本1列席が繋がっています。

人間が動くと椅子が振動します。周囲のオタクの振動がめちゃめちゃ自分に伝わってきて気持ち悪かったです。

自分が動くことによって発生する振動が他人に伝わってると思うと、なんか気持ち悪いです。

コール禁止のデメリット

もどかしい

コール曲は楽しい感じの曲が多いです。アルバムを初めて聴いた時、「コールするとしたらここだな~」など色々考えていました。

声を出したいのに出せない状況は、非常にもどかしく感じました。

ライブ内容について

ここからは、ただ語彙力が死んだオタクの感想です。

めちゃめちゃ良かったです。

しっかりストーリーがあって、それに合わせた曲順で歌われていました。

野球部監督、カエデ、22歳の樋口楓 と3つの世界が、現実の樋口楓に反映されていくような感じ、良かったです。

ファンメイド曲や響鳴など、ランティスと関係ない曲もやってくれて、激アツでした。

響鳴は KANA-DERO を思い出しました。

いそっち…好き……… KANA-DERO パーカー着てたのヤバい…

最後に

ライブ前に色々問題が発生しましたが、樋口楓のライブはやはり良かったです。

個人的には KANA-DERO のほうが良かったと感じています。

コロナ騒動が収まったら、再演をやってほしいと強く願います。

この記事を読んだオタクは AIM を見てください。3月始めまでネットチケット購入すれば無料で無限回見れます。

secure.live.nicovideo.jp

終わり

【あつ森】南半球でお金を稼ぐ方法【タランチュラ超え】

初めに

3月に北半球ではタランチュラが出るので日本人の8割くらいがタランチュラでお金を稼ごうと方法を編み出していました。

南半球を選択した私はタランチュラが出ない代わりにサソリで代用しようと思いましたが、蚊とスズムシとコオロギが走っても逃げないので諦めました。

離島ツアーの回数を重ねていたら、タランチュラ島と同じくらい稼げる島を見つけたので紹介します。

f:id:chun37:20200327023835j:plain

環境

  • 南半球
  • 3月

離島の詳細

  • 木は針葉樹のみ
  • 池や川は無し
  • ヤシの木が4本(右2本・左2本)
  • ニジイロクワガタ、ヨナグニサンが木に止まっている
  • 地上にはオオセンチコガネのみ

手順

  1. 叶式の要領で湧きを固定させる 参考動画
    • 花を取る
    • 木を切る(ヤシの木は残す)
    • 見やすくするために雑草を刈る
  2. 取らない虫を走って蹴散らす
  3. ゴライアスオオツノハナムグリがヤシの木に止まっていたら捕らえる
  4. 気が済むまで2と3を繰り返す

利点

  • 失敗しても島の最初に戻されない
  • サソリやタランチュラを捕まえるは難しいが木に止まっている虫を捕るのは比較的簡単
  • 同時に2匹出ることも

f:id:chun37:20200327023927j:plain

詳細

ヨナグニサンは1月, 2月, 3月, 10月, 11月, 12月に発生

オオセンチコガネは1月, 2月, 3月に発生

ニジイロクワガタは1月, 2月, 3月, 12月に発生

ゴライアスオオツノハナムグリは1月, 2月, 3月, 12月に発生

ゴライアスオオツノハナムグリはヤシの木のみに発生するため針葉樹を切っても問題なくスポーンする。

最後に

時間変更はしていないため1月と2月と12月の検証はしていないのですが、南半球の3月のお金稼ぎ方法を見つけられたので北半球の人たちにも負けずにお金が稼げて良かった。

macOSでPythonのmysqlclientをインストールする方法

mysqlclientがインストール出来ない

pip install mysqlclientと入力してもエラーが出てインストール出来ない。

赤文字でずらーっとエラーが出ますが2種類です。(私が確認した限りでは)

1つ目がmysql_configが見つからない。(エラー文は消えました)

2つ目が

ld: library not found for -lssl

Failed to build mysqlclientと書いてある行のいくつか上を確認するとどちらかのエラーが出ます。

対処法

mysql_configエラー

brewが使える環境で

brew install mysql

と入力してmysqlをインストールし、mysql_configコマンドが打てることを確認出来れば解決です。

ldエラー

brewが使える環境で

brew install openssl

opensslがインストール済みの方は

brew reinstall openssl

と入力し、インストールか再インストールをすると

For compilers to find openssl@1.1 you may need to set:
  export LDFLAGS="-L/usr/local/opt/openssl@1.1/lib"
  export CPPFLAGS="-I/usr/local/opt/openssl@1.1/include"

コンパイラがopenssl使うには環境変数を設定してね(意訳)

と言ってきてるのでLDFLAGSとCPPFLAGSの環境変数を設定すれば解決です。

おわりに

pythonmysqlを使うにはどのOSでもmysqlclientインストール時にコケるのでどうにかならないかなぁ〜と思っています。

ここに書いてないエラーが出た場合は環境とエラー文をコメントに記入してもらえば出来るだけ対処します。