Zenn
⚙️

Vultr VPSと自宅サーバの間にL2ネットワークを作り、グローバルの固定IPv6アドレスを自宅マシンに割り当てた

2025/02/11に公開
1

動機: グローバルの固定IPv6アドレスを自宅マシンで使いたい

VultrでVPSをデプロイすると、インターネットreachableなグローバルの固定IPv6プレフィックス/64が1つVPSに割り当てられます。これをVPSだけに使わせるのはもったいないので、VPSからL2トンネルを張って下流の自宅マシンにも同じ固定IPv6プレフィックスを割り当てられるようにしました。

結果として、VPS 1契約分のコストで、グローバルの固定IPv6アドレスを下流の任意の自宅マシンに割り当てできるようになりました。以下、本記事ではその構成と設定方法を記述します。

前提: VultrにおけるIPv6アドレス割り当ての仕組み

SLAAC(ステートレス・アドレス自動設定)が採用されている

VultrでデプロイしたVPSには標準でインターネット向けIF(enp1s0)が備わっていて、そのIFの上流(VPSのdefault GW)からRAが広報されてきます。そのRAには、VPSごとにユニークな固定IPv6プレフィックス/64が設定されています。

VPSはそのRAを受信することで、IPv6ホスト部をMACアドレスから生成したIPv6アドレスをIF(enp1s0)に自動設定し、さらにインターネットと疎通できるようにするためのIPv6ルーティングも自動設定します。いわゆるSLAAC(ステートレス・アドレス自動設定)です。

試しにVPS上でipコマンドを打てば、VPSが自動設定したIPv6アドレスやdefault GWへのIPv6ルーティングなどを確認できます。

例えば、以下のように。
2001:db8:7654:3210::/64 RAで広報されたVPSの固定IPv6プレフィックス/64
fe80::1234:5678:9abc:def0 RAの送信元IPv6 link-localアドレス。VPSのdefault GW

linuxuser@VPS
$ ip a show dev enp1s0
2: enp1s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq state UP group default qlen 1000
    link/ether xx:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff
    inet6 2001:db8:7654:3210:xxxx:xxxx:xxxx:xxxx/64 scope global dynamic mngtmpaddr noprefixroute
       valid_lft 2591679sec preferred_lft 604479sec
    inet6 fe80::xxxx:xxxx:xxxx:xxxx/64 scope link
       valid_lft forever preferred_lft forever
linuxuser@VPS
$ ip -6 route
2001:db8:7654:3210::/64 dev enp1s0 proto ra metric 100 expires 2591711sec mtu 1500 hoplimit 64 pref medium
fe80::/64 dev enp1s0 proto kernel metric 256 pref medium
default via fe80::1234:5678:9abc:def0 dev enp1s0 proto ra metric 100 expires 1511sec mtu 1500 hoplimit 64 pref medium

IPv6アドレスがVPS自身のIFのものかどうかは上流でチェックされない

Vultrでデプロイしたばかりの素のVPS上では、RAを受信してIPv6アドレスが自動設定されるIFはenp1s0のみです。つまりenp1s0だけがインターネットreachableな状態となっています。

ここで特筆すべき点は、VPS自身のIF(enp1s0)でRAを受信したかどうかは上流(VPSのdefault GW)でチェックされないということです。例えば、VPS上でenp1s0とは異なるMACアドレスのIFをユーザ定義してそのIFでRAを受信させると、そのユーザ定義のIFにもIPv6アドレスを自動設定でき、かつ、そのユーザ定義のIFでもインターネットreachableな状態となります。

上流(VPSのdefault GW)はあくまでステートレスであり、IPv6プレフィックスまでしか把握していないため、実際にIPv6で通信する際には下流に対してNeighbor Discovery Protocolで通信先IPv6アドレスのMACアドレスを探しにくる挙動が見られます。

このようなSLAACの仕組みを踏まえると、RAを広報するレイヤ2ネットワークを自分で構築してそこに任意のマシンを接続させれば、任意のマシンのIFにIPv6アドレスを自動設定でき、任意のマシンのIFをインターネットreachableな状態にできることになります。

以下、長くなりますが、そのための手順を順に記述していきます。

VPSと自宅サーバの間にレイヤ2ネットワークを作る手順

事前に用意するもの

  1. Vultr VPS (Ubuntu 24.04) 1台
    VPSデプロイ時の指定事項:
    ・Oerating System=Ubuntu 24.04 x64
    ・Public IPv4=Enabled
    ・Public IPv6=Enabled
    ・Limited User Login=Enabled
  1. 適当な自宅サーバ (Ubuntu 24.04) 1台
    指定事項:
    ・Ubuntu 24.04インストール済であること
    ・物理IFを2つ備えており、
     1番目の物理IFでIPv4でインターネットにアクセスできること (apt install等できること)
     2番目の物理IFにIPv4/v6アドレスを設定していないこと

手順の概要

NOTE: 手順を進める中で下記のapt installを行います。

  1. VPSと自宅サーバにIncusを導入する
    VPSと自宅サーバになるべく変更を加えない方針でまずIncusを導入する。
    apt install incus
  2. Incusホストを設定する
    Incusゲストを動作させるためIncusホストを設定する。下準備。
  3. Incusゲストを生成する
    下準備を整えたら、
    ・VPS上でIncusゲスト 2台 (ubunt-ndppdとubuntu-l2vpn-s)を生成する。
    ・自宅サーバ上でIncusゲスト 1台 (ubuntu-l2vpn-c)を生成する。
  4. Incusゲスト ubuntu-ndppdを設定する
    Incusゲスト上でradvdとndppdを導入して設定する。
    ・radvd: 下流にRAを広報する。
    ・ndppd: 上流と下流の間でNeighbor Discovery Protocolをプロキシする。
    apt install radvd ndppd
  5. Incusゲスト ubuntu-l2vpn-s/-cを設定する
    Incusゲスト上でwireguardを導入して設定する。
    ・wireguard: Incusゲスト間でVPNを張って直接通信を可能とする。
    さらに、VPN上でL2TPのトンネルを張ってL2ネットワークを完成させる。
    ・L2TP: Linuxカーネルモジュールでapt install不要で使用可。
    apt install wireguard

ネットワーク構成

・上流(default GW)がRAを広報しますが、それと同等のRAをradvdから下流へ広報させます。
・上流と下流の間でNeighbor Discovery Protocolをプロキシするndppdを立てます。
・下流にL2TPトンネル over WireGuardを張り、自宅L2スイッチまで地続きのレイヤ2にします。

インタフェース一覧:
本手順で以下のインタフェースを作成します。(事前作成済のIFを除く)

  1. 事前作成済のIF
    ・VPS enp1s0
    ・自宅サーバ enp1s0, enp2s0
  2. Incus導入時に作成するIF
    ・VPS incusbr0
  3. Incusホスト設定時に作成するIF
    ・VPS br-internal0
    ・自宅サーバ br-internal0
  4. Incusゲスト生成時に作成するIF
    ・ubuntu-ndppd eth0 (nictype:macvlan), eth1 (nictype:bridged)
    ・ubuntu-l2vpn-s eth0 (network:incusbr0), eth1 (nictype:bridged)
    ・ubuntu-l2vpn-c eth0 (network:incusbr0), eth1 (nictype:bridged)
  5. Incusゲスト ubuntu-ndppd設定時に作成するIF
    ・none
  6. Incusゲスト ubuntu-l2vpn-s/-c設定時に作成するIF
    wireguard用
    ・ubuntu-l2vpn-s wg0
    ・ubuntu-l2vpn-c wg0
    L2TP用
    ・ubuntu-l2vpn-s br-l2tp0, l2tp-eth0
    ・ubuntu-l2vpn-c br-l2tp0, l2tp-eth0

IPアドレス一覧:

本手順で以下のIPアドレスを設定します。太字IPはグローバルIP。

  1. Vultr VPSデプロイ時に割当済みのIP
    ・VPSのGlobal IPv4アドレス: 203.0.113.103
    ・VPSのGlobal IPv6プレフィックス: 2001:db8:7654:3210::/64
  2. Incus導入時に割当されるIP
    ・VPSのincusbr0 Private IPv4アドレス: 10.91.163.1
  3. 本手順で指定するユーザ指定のIP/port
    ・自宅マシンのSLAAC IPv6アドレス: 2001:db8:7654:3210:1111:2222:3333:4444
    ・通信プロトコル (下表参照)
Protocol Role EndPoint 本手順での例示
1 wireguard/udp サーバ ubuntu-l2vpn-s(eth0) 10.91.163.3:53000
クライアント ubuntu-l2vpn-c(eth0) Don't care
2 ポート開放/udp 転送元(Global) VPS(enp1s0) 203.0.113.103:53000
転送先(Private) ubuntu-l2vpn-s(eth0) 10.91.163.3:53000
3 l2tp/udp サーバ ubuntu-l2vpn-s(wg0) 10.0.0.1:1701
クライアント ubuntu-l2vpn-s(wg0) 10.0.0.2:1701

手順1. VPSと自宅サーバにIncusを導入する

PVSと自宅サーバそれぞれでIncusを導入します。
なお、incus導入後にip aコマンドを打つと、incusbr0が見えます。
Ref1: https://linuxcontainers.org/incus/docs/main/tutorial/first_steps/

linuxuser@VPS & linuxuser@自宅サーバ
sudo apt update
sudo apt install incus
sudo adduser linuxuser incus-admin
newgrp incus-admin
incus admin init --minimal
ip a

incusbr0を介した通信を許容するようにファイアウォール(ufw)を設定します。
Ref2: https://linuxcontainers.org/incus/docs/main/howto/network_bridge_firewalld/

linuxuser@VPS & linuxuser@自宅サーバ
sudo ufw status
sudo ufw allow in on incusbr0
sudo ufw route allow in on incusbr0
sudo ufw route allow out on incusbr0
sudo ufw status

手順2. Incusホストを設定する

VPS設定その1: Incusプロファイル用意

defaultのプロファイルを流用してIncusゲスト(ubuntu-ndppd)用のプロファイルを用意します。
ここで用意したプロファイルは、後でIncusゲスト生成時に指定します。

linuxuser@VPS
incus profile copy default custom-ndppd
incus profile show custom-ndppd
incus profile edit custom-ndppd

edit前:
・流用元のdefaultのプロファイル

linuxuser@VPS
$ incus profile show custom-ndppd
config: {}
description: Default Incus profile
devices:
  eth0:
    name: eth0
    network: incusbr0
    type: nic
  root:
    path: /
    pool: default
    type: disk
name: custom-ndppd
used_by: []

edit後:
・description(修正): 適当な文字列
・eth0(修正): ホストのenp1s0を親とするmacvlan IF
・eth1(追加): ホストのbr-internal0に接続するBridged IF

linuxuser@VPS
$ incus profile show custom-ndppd
config: {}
description: Custom Incus profile for ndppd
devices:
  eth0:
    name: eth0
    nictype: macvlan
    parent: enp1s0
    type: nic
  eth1:
    name: eth1
    nictype: bridged
    parent: br-internal0
    type: nic
  root:
    path: /
    pool: default
    type: disk
name: custom-ndppd
used_by: []

defaultのプロファイルを流用してIncusゲスト(ubuntu-l2vpn-s)用のプロファイルを用意します。
ここで用意したプロファイルは、後でIncusゲスト生成時に利用します。

linuxuser@VPS
incus profile copy default custom-l2vpn-s
incus profile show custom-l2vpn-s
incus profile edit custom-l2vpn-s

edit前:
・流用元のdefaultのプロファイル

linuxuser@VPS
$ incus profile show custom-l2vpn-s
config: {}
description: Default Incus profile
devices:
  eth0:
    name: eth0
    network: incusbr0
    type: nic
  root:
    path: /
    pool: default
    type: disk
name: custom-l2vpn-s
used_by: []

edit後:
・description(修正): 適当な文字列
・eth1(追加): ホストのbr-internal0に接続するBridged IF

linuxuser@VPS
$ incus profile show custom-l2vpn-s
config: {}
description: Custom Incus profile for l2vpn-s
devices:
  eth0:
    name: eth0
    network: incusbr0
    type: nic
  eth1:
    name: eth1
    nictype: bridged
    parent: br-internal0
    type: nic
  root:
    path: /
    pool: default
    type: disk
name: custom-l2vpn-s
used_by: []

VPS設定その2: l2tp用service設定

VPSのブート起動時にl2tp用のカーネルモジュール(l2tp_eth)の組み込みとブリッジIF(br-internal0)の作成を実行するoneshot serviceを定義します。

linuxuser@VPS
sudo bash -c 'cat > /etc/systemd/system/bridge-l2vpn-s.service' <<'EOS'
[Unit]
Description=Makes interfaces at boot
After=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/sbin/modprobe l2tp_eth
ExecStart=/usr/sbin/ip link add br-internal0 type bridge
ExecStart=/usr/sbin/ip link set dev br-internal0 up
TimeoutStartSec=0
RemainAfterExit=yes
[Install]
WantedBy=default.target
EOS

定義したserviceをstart・enableします。
また、lsmodでl2tp_ethが組み込まれたことと、ip aでbr-internal0が見えることを確認します。なお、bridge link showでbr-internal0をmasterとするIFの確認ができますがこの時点では何も表示されません。

linuxuser@VPS
sudo systemctl daemon-reload
sudo systemctl start bridge-l2vpn-s.service
sudo systemctl enable bridge-l2vpn-s.service
lsmod | grep l2tp
ip a
bridge link show | grep br-internal0

自宅サーバ設定その1: Incusプロファイル用意

defaultのプロファイルを流用してIncusゲスト(ubuntu-l2vpn-c)用のプロファイルを用意します。
ここで用意したプロファイルは、後でIncusゲスト生成時に指定します。

linuxuser@自宅サーバ
incus profile copy default custom-l2vpn-c
incus profile show custom-l2vpn-c
incus profile edit custom-l2vpn-c

edit前:
・流用元のdefaultのプロファイル

linuxuser@自宅サーバ
$ incus profile show custom-l2vpn-c
config: {}
description: Default Incus profile
devices:
  eth0:
    name: eth0
    network: incusbr0
    type: nic
  root:
    path: /
    pool: default
    type: disk
name: custom-l2vpn-c
used_by: []

edit後:
・description(修正): 適当な文字列
・eth1(追加): ホストのbr-internal0に接続するBridged IF

linuxuser@自宅サーバ
$ incus profile show custom-l2vpn-c
config: {}
description: Custom Incus profile for l2vpn-c
devices:
  eth0:
    name: eth0
    network: incusbr0
    type: nic
  eth1:
    name: eth1
    nictype: bridged
    parent: br-internal0
    type: nic
  root:
    path: /
    pool: default
    type: disk
name: custom-l2vpn-c
used_by: []

自宅サーバ設定その2: l2tp用service設定

自宅サーバのブート起動時にl2tp用のカーネルモジュール(l2tp_eth)の組み込みとブリッジIF(br-internal0)の作成、自宅サーバの自宅L2スイッチ向け物理IF(enp2s0)をブリッジIFに差し込むことを実行するoneshot serviceを定義します。

linuxuser@自宅サーバ
sudo bash -c 'cat > /etc/systemd/system/bridge-l2vpn-c.service' <<'EOS'
[Unit]
Description=Makes interfaces at boot
After=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/sbin/modprobe l2tp_eth
ExecStart=/usr/sbin/ip link add br-internal0 type bridge
ExecStart=/usr/sbin/ip link set dev br-internal0 up
ExecStart=/usr/sbin/ip link set dev enp2s0 master br-internal0
ExecStart=/usr/sbin/ip link set dev enp2s0 up
TimeoutStartSec=0
RemainAfterExit=yes
[Install]
WantedBy=default.target
EOS

定義したserviceをstart・enableします。
また、lsmodでl2tp_ethが組み込まれたことと、ip aでbr-internal0が見えることを確認します。なお、bridge link showでbr-internal0をmasterとするIFの確認ができ、この時点ではenp2s0が表示されます。

linuxuser@自宅サーバ
sudo systemctl daemon-reload
sudo systemctl start bridge-l2vpn-c.service
sudo systemctl enable bridge-l2vpn-c.service
lsmod | grep l2tp
ip a
bridge link show | grep br-internal0

自宅サーバ設定その3: l2tp用netplan設定

netplanで自宅スイッチ向けIF(enp2s0)のIPアドレス自動設定を無効化します。

自宅サーバがUbuntu Desktopの場合 - NetworkManagerを指定

linuxuser@自宅サーバ
sudo bash -c 'cat > /etc/netplan/96-manualipv6.yaml' <<'EOS'
network:
    version: 2
    renderer: NetworkManager
    ethernets:
        enp2s0:
            dhcp4: false
            dhcp6: false
            accept-ra: false
            link-local: []
EOS

自宅サーバがUbuntu Serverの場合 - networkdを指定

linuxuser@自宅サーバ
sudo bash -c 'cat > /etc/netplan/96-manualipv6.yaml' <<'EOS'
network:
    version: 2
    renderer: networkd
    ethernets:
        enp2s0:
            dhcp4: false
            dhcp6: false
            accept-ra: false
            link-local: []
EOS
linuxuser@自宅サーバ
sudo chmod 600 /etc/netplan/96-manualipv6.yaml
sudo netplan try

手順3. Incusゲストを生成する

VPSサーバで、準備済みのプロファイルを用いてIncusゲストを生成・起動します。incus listコマンドにより、生成したIncusゲストがRUNNINGステートであることを確認します。

linuxuser@VPS
incus list
incus launch -p custom-ndppd images:ubuntu/noble ubuntu-ndppd
incus list
incus launch -p custom-l2vpn-s images:ubuntu/noble ubuntu-l2vpn-s
incus list

bridge link showでbr-internal0をmasterとするIF(veth)が2個表示されることを確認します。
NOTE: 表示されるvethはIncusゲストのeth1に相当。
・ubuntu-ndppdのeth1 (nictype:bridged)
・ubuntu-l2vpn-sのeth1 (nictype:bridged)

linuxuser@VPS
bridge link show | grep br-internal0
xx: veth41afc649@if12: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master br-internal0 state forwarding priority 32 cost 2
xx: veth41226d17@if18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master br-internal0 state forwarding priority 32 cost 2

自宅サーバで、準備済みのプロファイルを用いてIncusゲストを生成・起動します。incus listコマンドにより、生成したIncusゲストがRUNNINGステートであることを確認します。

linuxuser@自宅サーバ
incus list
incus launch -p custom-l2vpn-c images:ubuntu/noble ubuntu-l2vpn-c
incus list

bridge link showでbr-internal0をmasterとするenp2s0およびvethが表示されることを確認します。
NOTE: enp2s0のstateは、L2スイッチに接続していないとdisabled。接続しているとforwarding。
NOTE: 表示されるvethはIncusゲストのeth1に相当。
・ubuntu-l2vpn-cのeth1 (nictype:bridged)

linuxuser@自宅サーバ
bridge link show | grep br-internal0
xx: enp2s0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 master br-internal0 state disabled priority 32 cost 100
xx: veth931add8c@if8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master br-internal0 state forwarding priority 32 cost 2

手順4. Incusゲスト ubuntu-ndppdを設定する

VPSサーバで、ubuntu-ndppdに入ります。
root@ubuntu-ndppdのコマンドプロンプトが表示されます。

linuxuser@VPS
incus exec ubuntu-ndppd -- bash
root@ubuntu-ndppd:~#

IPv6 fowrwarding設定

eth0とeth1で受信した自分宛てではないIPv6パケットを転送できるようにするため(ルータ動作できるようにするため)、/etc/sysctl.confのnet.ipv6.conf.all.forwarding=1のコメントアウトを外します。
・修正前: #net.ipv6.conf.all.forwarding=1
・修正後: net.ipv6.conf.all.forwarding=1
修正を反映させるためsysctl -pを実行します。

root@ubuntu-ndppd
vi /etc/sysctl.conf
sysctl -p

radvd service設定

radvdをインストールします。

root@ubuntu-ndppd
apt install radvd

radvdの設定ファイル/etc/radvd.confを作成します。

root@ubuntu-ndppd
bash -c 'cat > /etc/radvd.conf' <<'EOS'
interface eth1
{
        AdvSendAdvert on;

        prefix 2001:db8:7654:3210::/64
        {
                AdvOnLink on;
                AdvAutonomous on;
        };
};
EOS

radvdの設定ファイルを反映させるためrestartします。
NOTE: 既にenableされており、enableは不要。

root@ubuntu-ndppd
systemctl daemon-reload
systemctl restart radvd
systemctl status radvd

(status表示例)

# systemctl status radvd
● radvd.service - Router advertisement daemon for IPv6
     Loaded: loaded (/usr/lib/systemd/system/radvd.service; enabled; preset: enabled)
(...)
Feb 11 07:31:28 ubuntu-ndppd systemd[1]: Starting radvd.service - Router advertisement daemon for IPv6...
Feb 11 07:31:28 ubuntu-ndppd radvd[549]: config file, /etc/radvd.conf, syntax ok
Feb 11 07:31:28 ubuntu-ndppd radvd[551]: version 2.19 started
Feb 11 07:31:28 ubuntu-ndppd systemd[1]: Started radvd.service - Router advertisement daemon for IPv6.

ndppd service設定

ndppdをインストールします。

root@ubuntu-ndppd
apt install ndppd

ndppdの設定ファイル/etc/ndppd.confを作成します。

root@ubuntu-ndppd
bash -c 'cat > /etc/ndppd.conf' <<'EOS'
proxy eth0 {
   router no
   autowire yes
   rule ::/0 {
      iface eth1
   }
}
proxy eth1 {
   rule ::/0 {
      iface eth0
   }
}
EOS

ndppdの設定ファイルを反映させるためrestartします。
NOTE: 既にenableされており、enableは不要。

root@ubuntu-ndppd
systemctl daemon-reload
systemctl restart ndppd
systemctl status ndppd

下流向けのIPv6静的route設定

下流向けに、自宅マシン(IPv6ノード)ごとに1つのIPv6静的routeを設定します。

一時的にroute追加する場合:
NOTE: 複数の自宅マシンを追加する場合はroute addを複数実行。

root@ubuntu-ndppd
ip -6 route add 2001:db8:7654:3210:1111:2222:3333:4444/128 dev eth1
ip -6 route

一時的に追加したrouteを削除する場合:

root@ubuntu-ndppd
ip -6 route del 2001:db8:7654:3210:1111:2222:3333:4444/128 dev eth1
ip -6 route

恒久的にroute追加する場合:
NOTE: 複数の自宅マシンを追加する場合は-to:行を複数追加。

root@ubuntu-ndppd
bash -c 'cat > /etc/netplan/95-manualconf.yaml' <<'EOS'
network:
    version: 2
    renderer: networkd
    ethernets:
        eth1:
          routes:
          - to: 2001:db8:7654:3210:1111:2222:3333:4444/128
EOS
root@ubuntu-ndppd
chmod 600 /etc/netplan/95-manualconf.yaml
netplan try
ip -6 route

恒久的に追加したrouteを削除する場合:

root@ubuntu-ndppd
rm /etc/netplan/95-manualconf.yaml
netplan try
ip -6 route

Incusゲストから抜け、Incusホストに戻ります。

root@ubuntu-ndppd
exit

手順5. Incusゲスト ubuntu-l2vpn-s/-cを設定する

wireguardサーバ用のポート開放設定

VPS上で、wireguardサーバ側となるubuntu-l2vpn-sをいったん停止します。

linuxuser@VPS
incus stop ubuntu-l2vpn-s
incus list

ipコマンドでenp1s0のGlobal IPv4アドレスを確認します。(例: 203.0.113.103)

linuxuser@VPS
ip -4 a show dev enp1s0
2: enp1s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq state UP group default qlen 1000
    inet 203.0.113.103/xx metric 100 brd xxx.xxx.xxx.xxx scope global dynamic enp1s0
       valid_lft 75440sec preferred_lft 75440sec

ipコマンドでincusbr0のPrivate IPv4アドレスを確認します。(例: 10.91.163.1)

linuxuser@VPS
ip -4 a show dev incusbr0
6: incusbr0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    inet 10.91.163.1/24 scope global incusbr0
       valid_lft forever preferred_lft forever

デフォルトではincusbr0に接続する各IncusゲストのIFのIPv4アドレスはDHCPで動的IPになっていますが、これを静的IPに設定変更します。(例: 静的IP 10.91.163.3に設定)

また、その静的IPアドレスの特定ポート(例: 53000)にインターネットからアクセスできるようにするためのポート開放(ポートフォワーディング)を設定します。

linuxuser@VPS
incus config device override ubuntu-l2vpn-s eth0 ipv4.address=10.91.163.3
incus config device add ubuntu-l2vpn-s port53000 proxy listen=udp:203.0.113.103:53000 connect=udp:10.91.163.3:53000 nat=true

ubuntu-l2vpn-sに適用されているconfigを確認します。プロファイルをオーバライドしたeth0デバイス設定、および、プロファイルには無かったport53000という名のproxyタイプのデバイス設定がdevicesパートに表示されること確認します。

linuxuser@VPS
incus config show ubuntu-l2vpn-s
(...)
devices:
  eth0:
    ipv4.address: 10.91.163.3
    name: eth0
    network: incusbr0
    type: nic
  port53000:
    connect: udp:10.91.163.3:53000
    listen: udp:203.0.113.103:53000
    nat: "true"
    type: proxy
(...)

停止させていたubuntu-l2vpn-sを起動します。(configが適用されます。)

linuxuser@VPS
incus start ubuntu-l2vpn-s
incus list

wireguard設定

Ref3: https://pc.watch.impress.co.jp/docs/column/ubuntu/1606110.html
Ref4: https://hachune.net/blog/2022/05/20/l2tp-wireguard.html
Ref5: https://www.man7.org/linux/man-pages/man8/ip-l2tp.8.html

VPSで、ubuntu-l2vpn-sに入ります。
root@ubuntu-l2vpn-sのコマンドプロンプトが表示されます。

linuxuser@VPS
incus exec ubuntu-l2vpn-s -- bash
root@ubuntu-l2vpn-s:~#

wireguardをインストールします。

root@ubuntu-l2vpn-s
apt install wireguard

wireguardサーバ側の秘密鍵を生成してserver.keyファイルに保存します。
wireguardサーバ側の公開鍵を生成してserver.pubファイルに保存します。

root@ubuntu-l2vpn-s
wg genkey | tee /etc/wireguard/server.key
cat /etc/wireguard/server.key | wg pubkey | tee /etc/wireguard/server.pub
chmod 600 /etc/wireguard/server.{key,pub}

続けて、自宅サーバで、ubuntu-l2vpn-cに入ります。
root@ubuntu-l2vpn-cのコマンドプロンプトが表示されます。

linuxuser@自宅サーバ
incus exec ubuntu-l2vpn-c -- bash
root@ubuntu-l2vpn-c:~#

wireguardをインストールします。

root@ubuntu-l2vpn-c
apt install wireguard

wireguardクライアント側の秘密鍵を生成してclient.keyファイルに保存します。
wireguardクライアント側の公開鍵を生成してclient.pubファイルに保存します。

root@ubuntu-l2vpn-c
wg genkey | tee /etc/wireguard/client.key
cat /etc/wireguard/client.key | wg pubkey | tee /etc/wireguard/client.pub
chmod 600 /etc/wireguard/client.{key,pub}

wireguardサーバ側の設定ファイルを作成します。
・PrivateKey: 自分(サーバ側)の秘密鍵を指定
・Address: 自分(サーバ側)のwg0インタフェースに割り当てるIPアドレスを指定
・ListenPort: wireguardクライアントからの接続を待ち受けるサーバ側のudpポート番号を指定
・PublicKey: 相手(クライアント側)の公開鍵を指定
・AllowedIPs: wg0インタフェースへrouteするroute先のIPまたはサブネットを指定

root@ubuntu-l2vpn-s
bash -c 'cat > /etc/wireguard/wg0.conf' <<'_EOS_'
[Interface]
PrivateKey = sssssssssssssssssssssssssssssssssssssssssss=
Address = 10.0.0.1
ListenPort = 53000

[Peer]
PublicKey = ccccccccccccccccccccccccccccccccccccccccccc=
AllowedIPs = 10.0.0.2/32
_EOS_

wireguardクライアント側の設定ファイルを作成します。
・PrivateKey: 自分(クライアント側)の秘密鍵を指定
・Address: 自分(クライアント側)のwg0インタフェースに割り当てるIPアドレスを指定
・PublicKey: 相手(サーバ側)の公開鍵を指定
・EndPoint: wireguardサーバのIPアドレスとudpポート番号を指定
 NOTE: EndPointにはポート開放したVPSのGlobal IPアドレスを指定することに注意
・AllowedIPs: wg0インタフェースへrouteするroute先のIPまたはサブネットを指定

root@ubuntu-l2vpn-c
bash -c 'cat > /etc/wireguard/wg0.conf' <<'_EOS_'
[Interface]
PrivateKey = ccccccccccccccccccccccccccccccccccccccccccc=
Address = 10.0.0.2

[Peer]
PublicKey = sssssssssssssssssssssssssssssssssssssssssss=
EndPoint = 203.0.113.103:53000
AllowedIPs = 10.0.0.0/24 
_EOS_

wg0指定でwireguardサーバを起動します。ip aコマンドでwg0が表示されることを確認します。
NOTE: サーバ側は常時起動のためenableにします。

root@ubuntu-l2vpn-s
systemctl enable --now wg-quick@wg0
systemctl status wg-quick@wg0
ip a

(status表示例)

# systemctl status wg-quick@wg0
● wg-quick@wg0.service - WireGuard via wg-quick(8) for wg0
     Loaded: loaded (/usr/lib/systemd/system/wg-quick@.service; enabled; preset: enabled)
(...)
Feb 11 13:03:33 ubuntu-l2vpn-s systemd[1]: Starting wg-quick@wg0.service - WireGuard via wg-quick(8) for wg0...
Feb 11 13:03:33 ubuntu-l2vpn-s wg-quick[672]: [#] ip link add wg0 type wireguard
Feb 11 13:03:33 ubuntu-l2vpn-s wg-quick[672]: [#] wg setconf wg0 /dev/fd/63
Feb 11 13:03:33 ubuntu-l2vpn-s wg-quick[672]: [#] ip -4 address add 10.0.0.1 dev wg0
Feb 11 13:03:33 ubuntu-l2vpn-s wg-quick[672]: [#] ip link set mtu 1420 up dev wg0
Feb 11 13:03:33 ubuntu-l2vpn-s wg-quick[672]: [#] ip -4 route add 10.0.0.2/32 dev wg0
Feb 11 13:03:33 ubuntu-l2vpn-s systemd[1]: Finished wg-quick@wg0.service - WireGuard via wg-quick(8) for wg0.

wireguardクライアントを起動し、ip aコマンドでwg0が表示されることを確認します。
wireguardサーバにpingが通ることを確認します。

root@ubuntu-l2vpn-c
wg-quick up wg0
ip a
ping 10.0.0.1

pingが通ったらwireguardクライアントをいったん停止します。

root@ubuntu-l2vpn-c
wg-quick down wg0

l2tp設定

wireguardサーバ側のl2tp設定を行うシェルスクリプトを作成します。

root@ubuntu-l2vpn-s
bash -c 'cat > ./l2vpn-s.sh' <<'EOS'
#!/bin/sh

# L2TP
ip l2tp add tunnel \
        tunnel_id 3939 \
        peer_tunnel_id 3940 \
        encap udp \
        local 10.0.0.1 \
        remote 10.0.0.2 \
        udp_sport 1701 \
        udp_dport 1701
ip l2tp add session \
        tunnel_id 3939 \
        session_id 3941 \
        peer_session_id 3942
ip link set dev l2tpeth0 up mtu 1500

# Bridge
ip link add br-l2tp0 type bridge
ip link set dev br-l2tp0 up
ip link set dev l2tpeth0 master br-l2tp0
ip link set dev eth1 master br-l2tp0
ip link set dev eth1 up
EOS
root@ubuntu-l2vpn-s
chmod 755 ./l2vpn-s.sh

wireguardクライアント側のl2tp設定を行うシェルスクリプトを作成します。
NOTE: wireguardクライアントの起動もシェルスクリプトの中で実行します。

root@ubuntu-l2vpn-c
bash -c 'cat > ./l2vpn-c.sh' <<'EOS'
#!/bin/sh

# WireGuard
wg-quick up wg0

# L2TP
ip l2tp add tunnel \
        tunnel_id 3940 \
        peer_tunnel_id 3939 \
        encap udp \
        local 10.0.0.2 \
        remote 10.0.0.1 \
        udp_sport 1701 \
        udp_dport 1701
ip l2tp add session \
        tunnel_id 3940 \
        session_id 3942 \
        peer_session_id 3941
ip link set dev l2tpeth0 up mtu 1500

# Bridge
ip link add br-l2tp0 type bridge
ip link set dev br-l2tp0 up
ip link set dev l2tpeth0 master br-l2tp0
ip link set dev eth1 master br-l2tp0
ip link set dev eth1 up
EOS
root@ubuntu-l2vpn-c
chmod 755 ./l2vpn-c.sh

サーバ側のシェルスクリプトを実行します。

root@ubuntu-l2vpn-s
./l2vpn-s.sh

クライアント側のシェルスクリプトを実行します。

root@ubuntu-l2vpn-c
./l2vpn-c.sh

自宅L2スイッチ先に適当な自宅マシン(IPv6ノード)を用意し、そこからインターネットへpingが通ることを確認します。(例: Google DNSへping)

ping -6 2001:4860:4860::8888

Incusゲストから抜け、Incusホストに戻ります。以上で手順完了です。

root@ubuntu-l2vpn-s
./exit
root@ubuntu-l2vpn-c
./exit

付録: 運用手順

VPSをrebootした後の復旧手順

reboot前にRUNNINGステートだったIncusゲストは、reboot後にRUNNINGステートに戻ります。ただし再開しているためシェルスクリプトを再度実行する必要があります。

linuxuser@VPS
incus exec ubuntu-l2vpn-s -- ./l2vpn-s.sh

自宅サーバをrebootした後の復旧手順

reboot前にRUNNINGステートだったIncusゲストは、reboot後にRUNNINGステートに戻ります。ただし再開しているためシェルスクリプトを再度実行する必要があります。

linuxuser@自宅サーバ
incus exec ubuntu-l2vpn-c -- ./l2vpn-c.sh

WireGuard/L2TPを一時的に切断/復旧する手順

自宅サーバ側のubuntu-l2vpn-cを停止することで切断となります。

linuxuser@自宅サーバ
incus stop ubuntu-l2vpn-c

接続を復旧させる場合は、ubuntu-l2vpn-cを開始し、シェルスクリプトを再度実行します。

linuxuser@自宅サーバ
incus start ubuntu-l2vpn-c
incus exec ubuntu-l2vpn-c -- ./l2vpn-c.sh

下流の自宅マシン(IPv6ノード)を追加する手順

Incusゲストubuntu-ndppdのnetplan設定ファイルに- to:行を追加してnetplanコマンドで反映させます。
例) 2001:db8:7654:3210:5555:6666:7777:8888/128を行追加

root@ubuntu-ndppd
vi /etc/netplan/95-manualconf.yaml
(...)
    ethernets:
        eth1:
          routes:
          - to: 2001:db8:7654:3210:1111:2222:3333:4444/128
          - to: 2001:db8:7654:3210:5555:6666:7777:8888/128
netplan try
ip -6 route

以上

1

Discussion

ログインするとコメントできます