VyOSで高可用なルータを動かす

## きっかけ
自宅サーバを動かしたいけど、NWは適切に分離したい...。
高機能なルータが手元にないので、どうせなら仮想ルータを入れてしまえって思った。

### VyOSな理由
以前から「VyOS」にはお世話になっていたので、更新するついでに可用性を上げようと思ったのがきっかけ。
候補としては「pfSense」もあったけど、インストーラの入手がすこぶる面倒そうだったのでVyOSを使うことにした。


## 構成
### VM/装置
- Home Router: 一般的な家庭用ルータ。Internet接続を提供する
- Proxmox VE: 各種サーバ用の仮想環境。この上でいろんなサーバを立てる
- VyOS#1: 仮想ルータ1号機
- VyOS#2: 仮想ルータ2号機
### NW
- 192.168.0.0/24: HOME-NW
    - .251: `VyOS#1`のIPv4アドレス
    - .252: `VyOS#2`のIPv4アドレス
    - .253: VyOSのVIP、基本的に`VyOS#1`が持ってるけど落ちたら`VyOS#2`が持つ
    - .254: Internet方向のDefault GW
- 172.16.255.0/24: NAT-NW
    - .1 ～ .251: VM用のDHCP自動割当てレンジ
    - .252: `VyOS#1`のIPv4アドレス
    - .253: `VyOS#2`のIPv4アドレス
    - .254: VyOSのVIP、HOME-NW方向のDefault GW
### 構成概要図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3535545/ac2db429-700d-de51-a481-1a118233696c.png)

### VyOS バージョン
```shell
$ cat /etc/os-release
PRETTY_NAME="VyOS 1.5-rolling-202412140007 (current)"
NAME="VyOS"
VERSION_ID="1.5-rolling-202412140007"
VERSION="1.5-rolling-202412140007 (current)"
VERSION_CODENAME=bookworm
ID=vyos
BUILD_ID="64737049995158"
HOME_URL="https://vyos.io"
SUPPORT_URL="https://support.vyos.io"
BUG_REPORT_URL="https://vyos.dev"
DOCUMENTATION_URL="https://docs.vyos.io/en/latest"
```


## インストール
これを参照。

https://docs.vyos.io/en/latest/installation/install.html#permanent-installation

## 設定
### 方針
- VM用にInternet接続を提供するルータとして設定する
    - NAPT設定で`HOME-NW`側から隠ぺいする
    - DHCP設定でVMにアドレス自動割当てを実現する
- 経路の冗長をとって高可用性を狙う
    - 今回はVRRPで2台のVyOSによる冗長構成にする
    - `HOME-NW`と`NAT-NW`の両方に冗長設定を入れる
#### （参考）VRRPとは
https://www.infraexpert.com/study/fhrpz07.html

### 設定コマンド
機能別に分けて設定していく。

:::note warn
`VyOS#1`と`VyOS#2`で設定が変わる場合は併記したうえで末尾のコメントで補足している。
:::

#### `HOME-NW`側のVRRP
- `192.168.0.253/24`をVIPとして設定する
- Interfaceは`eth0`
- `VyOS#1`の優先度を最高(`255`)に設定する
    - `VyOS#2`では優先度を普通(`100`)に設定する
- `NAT-NW`側のInterfaceが落ちたら、自動的に系が切り替わるように設定する
- VRIDは`10`を設定する
- VRRPの同期設定を入れる
```shell
set high-availability vrrp group outer address 192.168.0.253/24
set high-availability vrrp group outer advertise-interval '1'
set high-availability vrrp group outer interface 'eth0'
set high-availability vrrp group outer priority '255' # `VyOS#1`
set high-availability vrrp group outer priority '100' # `VyOS#2`
set high-availability vrrp group outer track interface 'eth1'
set high-availability vrrp group outer vrid '10'
set high-availability vrrp sync-group syncgrp01 member 'outer'
```
#### `NAT-NW`側のVRRP
- `172.16.255.254/24`をVIPとして設定する
- Interfaceは`eth1`
- `VyOS#1`の優先度を最高(`255`)に設定する
    - `VyOS#2`では優先度を普通(`100`)に設定する
- `HOME-NW`側のInterfaceが落ちたら、自動的に系が切り替わるように設定する
- VRIDは`20`を設定する
- VRRPの同期設定を入れる
```shell
set high-availability vrrp group inner address 172.16.255.254/24
set high-availability vrrp group inner advertise-interval '1'
set high-availability vrrp group inner interface 'eth1'
set high-availability vrrp group inner priority '255' # `VyOS#1`
set high-availability vrrp group inner priority '100' # `VyOS#2`
set high-availability vrrp group inner track interface 'eth0'
set high-availability vrrp group inner vrid '20'
set high-availability vrrp sync-group syncgrp02 member 'inner'
```

#### NAPT
- SNATの外側Interfaceとして`HOME-NW`側(`eth0`)を設定する
- SNATの内側アドレスとして`NAT-NW`を設定する
- 変換アドレス設定を`masquerade`(NAPT)で設定する
```shell
set nat source rule 100 outbound-interface name 'eth0'
set nat source rule 100 source address '172.16.255.0/24'
set nat source rule 100 translation address 'masquerade'
```

#### Default GW
- `Home Router`をDefault GWとして設定する
```shell
set protocols static route 0.0.0.0/0 next-hop 192.168.0.254
```

#### DHCP
- DHCPのリース情報を2台で共有し、冗長化する
    - `VyOS#1`をprimary、`VyOS#2`をSecondaryとして設定する
- `NAT-NW`向けにDHCPを提供する
    - Default GW: 172.16.255.254
    - DNS Server: 1.1.1.1
    - Lease Range: .1 ～ .251 
```shell
set service dhcp-server high-availability name 'vyos'
set service dhcp-server high-availability remote '172.16.255.253' # `VyOS#1`
set service dhcp-server high-availability remote '172.16.255.252' # `VyOS#2`
set service dhcp-server high-availability source-address '172.16.255.252' # `VyOS#1`
set service dhcp-server high-availability source-address '172.16.255.253' # `VyOS#2`
set service dhcp-server high-availability status 'primary'   # `VyOS#1`
set service dhcp-server high-availability status 'secondary' # `VyOS#2`
set service dhcp-server listen-interface 'eth1'
set service dhcp-server shared-network-name nat-network subnet 172.16.255.0/24 option default-router '172.16.255.254'
set service dhcp-server shared-network-name nat-network subnet 172.16.255.0/24 option name-server '1.1.1.1'
set service dhcp-server shared-network-name nat-network subnet 172.16.255.0/24 range 1 start '172.16.255.1'
set service dhcp-server shared-network-name nat-network subnet 172.16.255.0/24 range 1 stop '172.16.255.251'
set service dhcp-server shared-network-name nat-network subnet 172.16.255.0/24 subnet-id '100'
```

#### その他
- Interface設定
- ホスト名設定
- システム側のDNS設定を`1.1.1.1`に設定
- キーボード入力を日本語に設定
- タイムゾーンを`Asia/Tokyo`に設定
```shell
set interfaces ethernet eth0 address '192.168.0.251/24' # `VyOS#1`
set interfaces ethernet eth0 address '192.168.0.251/24' # `VyOS#2`
set interfaces ethernet eth1 address '172.16.255.252/24' # `VyOS#1`
set interfaces ethernet eth1 address '172.16.255.252/24' # `VyOS#2`
set system host-name 'vyos1' # `VyOS#1`
set system host-name 'vyos2' # `VyOS#2`
set system name-server '1.1.1.1'
set system option keyboard-layout 'jp106'
set system time-zone 'Asia/Tokyo'
```

## 設定結果
それぞれのVyOSでVRRPの詳細とDHCPのリース情報を確認する。
なお、リース先は`NAT-NW`側に建てたVM(`Ubuntu Server 24.04 LTE`)になる。


### `VyOS#1`
```shell-session
vyos@vyos1:~$ show vrrp detail

 VRRP Instance: outer
   VRRP Version: 2
   State: MASTER
   Wantstate: MASTER
   Last transition: 1734187765.79408
   Interface: eth0
   Gratuitous ARP delay: 5
   Gratuitous ARP repeat: 5
   Gratuitous ARP refresh: 0
   Gratuitous ARP refresh repeat: 1
   Gratuitous ARP lower priority delay: 5
   Gratuitous ARP lower priority repeat: 5
   Send advert after receive lower priority advert: true
   Send advert after receive higher priority advert: false
   Virtual Router ID: 10
   Priority: 255
   Effective priority: 255
   Advert interval: 1 sec
   Accept: Enabled
   Preempt: Enabled
   Promote secondaries: Disabled
   Authentication type: NONE

   Virtual IP (1):
       192.168.0.253/24 dev eth0 scope global set

   Tracked interfaces:
       eth1

   Using smtp notification: no
   Notify deleted: Fault

 VRRP Instance: inner
   VRRP Version: 2
   State: MASTER
   Wantstate: MASTER
   Last transition: 1734187765.793804
   Interface: eth1
   Gratuitous ARP delay: 5
   Gratuitous ARP repeat: 5
   Gratuitous ARP refresh: 0
   Gratuitous ARP refresh repeat: 1
   Gratuitous ARP lower priority delay: 5
   Gratuitous ARP lower priority repeat: 5
   Send advert after receive lower priority advert: true
   Send advert after receive higher priority advert: false
   Virtual Router ID: 20
   Priority: 255
   Effective priority: 255
   Advert interval: 1 sec
   Accept: Enabled
   Preempt: Enabled
   Promote secondaries: Disabled
   Authentication type: NONE

   Virtual IP (1):
       172.16.255.254/24 dev eth1 scope global set

   Tracked interfaces:
       eth0

   Using smtp notification: no
   Notify deleted: Fault
   
vyos@vyos1:~$ show dhcp server leases
IP Address    MAC address        State    Lease start          Lease expiration     Remaining    Pool         Hostname    Origin
------------  -----------------  -------  -------------------  -------------------  -----------  -----------  ----------  --------
172.16.255.5  bc:24:11:64:27:01  active   2024/12/17 17:53:53  2024/12/18 17:53:53  20:04:23     nat-network  thrust2799  local
```
### `VyOS#2`
```shell-session
vyos@vyos2:~$ show vrrp detail

 VRRP Instance: outer
   VRRP Version: 2
   State: BACKUP
   Master priority: 255
   Wantstate: BACKUP
   Last transition: 1734187754.626706
   Interface: eth0
   Gratuitous ARP delay: 5
   Gratuitous ARP repeat: 5
   Gratuitous ARP refresh: 0
   Gratuitous ARP refresh repeat: 1
   Gratuitous ARP lower priority delay: 5
   Gratuitous ARP lower priority repeat: 5
   Send advert after receive lower priority advert: true
   Send advert after receive higher priority advert: false
   Virtual Router ID: 10
   Priority: 100
   Effective priority: 100
   Advert interval: 1 sec
   Accept: Enabled
   Preempt: Enabled
   Promote secondaries: Disabled
   Authentication type: NONE

   Virtual IP (1):
       192.168.0.253/24 dev eth0 scope global

   Tracked interfaces:
       eth1

   Using smtp notification: no
   Notify deleted: Fault

 VRRP Instance: inner
   VRRP Version: 2
   State: BACKUP
   Master priority: 255
   Wantstate: BACKUP
   Last transition: 1734187754.627637
   Interface: eth1
   Gratuitous ARP delay: 5
   Gratuitous ARP repeat: 5
   Gratuitous ARP refresh: 0
   Gratuitous ARP refresh repeat: 1
   Gratuitous ARP lower priority delay: 5
   Gratuitous ARP lower priority repeat: 5
   Send advert after receive lower priority advert: true
   Send advert after receive higher priority advert: false
   Virtual Router ID: 20
   Priority: 100
   Effective priority: 100
   Advert interval: 1 sec
   Accept: Enabled
   Preempt: Enabled
   Promote secondaries: Disabled
   Authentication type: NONE

   Virtual IP (1):
       172.16.255.254/24 dev eth1 scope global

   Tracked interfaces:
       eth0

   Using smtp notification: no
   Notify deleted: Fault

vyos@vyos2:~$ show dhcp server leases
IP Address    MAC address        State    Lease start          Lease expiration     Remaining    Pool         Hostname    Origin
------------  -----------------  -------  -------------------  -------------------  -----------  -----------  ----------  --------
172.16.255.5  bc:24:11:64:27:01  active   2024/12/17 17:53:53  2024/12/18 17:53:53  20:04:59     nat-network  thrust2799  local
```

#### 疎通確認
```shell-session
thrust2799@thrust2799:~$ tracepath 192.168.0.254
 1?: [LOCALHOST]                      pmtu 1500
 1:  172.16.255.252                                        0.413ms
 1:  172.16.255.252                                        0.341ms
 2:  192.168.0.254                                         1.093ms reached
     Resume: pmtu 1500 hops 2 back 2
thrust2799@thrust2799:~$ ping -c 3 www.google.co.jp
PING www.google.co.jp (172.217.161.227) 56(84) bytes of data.
64 bytes from kix06s05-in-f3.1e100.net (172.217.161.227): icmp_seq=1 ttl=117 time=6.00 ms
64 bytes from kix06s05-in-f3.1e100.net (172.217.161.227): icmp_seq=2 ttl=117 time=5.28 ms
64 bytes from kix06s05-in-f3.1e100.net (172.217.161.227): icmp_seq=3 ttl=117 time=5.00 ms

--- www.google.co.jp ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 5.001/5.427/6.002/0.421 ms
```

#### 系切り替わり確認 @`VyOS#2`

```shell-session
vyos@vyos2:~$ # ここで`VyOS#1`のeth0を切断
vyos@vyos2:~$ 
vyos@vyos2:~$ show vrrp
Name     Interface      VRID  State      Priority  Last Transition
-------  -----------  ------  -------  ----------  -----------------
outer    eth0             10  MASTER          100  17s
inner    eth1             20  MASTER          100  17s
vyos@vyos2:~$ 
vyos@vyos2:~$ # ここで`VyOS#1`のeth0を接続
vyos@vyos2:~$ 
vyos@vyos2:~$ show vrrp
Name     Interface      VRID  State      Priority  Last Transition
-------  -----------  ------  -------  ----------  -----------------
outer    eth0             10  BACKUP          100  5s
inner    eth1             20  BACKUP          100  5s
```


## ふりかえり
うまいこと冗長ルータが建立し、DHCPのリース情報もルータ間で共有することができた。VRRPの系切り替わりも対象Interfaceと監視Interfaceのいずれかが落ちた時に設定したので、最低限遊べるだけの設定はできた感触。

ただ今回はVMで建てているので、Interfaceが落ちることは基本的にない上にそのままネクストホップへ接続できない状態が容易に想像できる。

:::note warn
例えば、ホスト側の物理Interfaceが落ちるとVyOSはHOME-NWとの接続性を失う。
一方でVMの論理Interfaceは生き残っているので系切り替わりが発生しない。
:::

こういう場合はネクストホップへの接続性を確認対象に設定すべきだが、そもそも物理側でInterface冗長すればいい話だったりもあるので今回はここまでで満足することにする。
~~逸般の誤家庭は電気通信事業者ではないのだ。（個人の意見）~~

あと、ACL設定も入れてないのでそのあたりも課題。
forwardルールとかConntrack Syncとかの設定も考えねば...。

##### P.S.
なんか疎通確認用に建てたVMのホスト名が気づいたら自分の名前になってるが...。（設定ミス）