RaspberryPiにVPNサーバ（softether）を立てる

# 概要
しゅっちょうｙオフラインのハンズオンなどが徐々に増えてきて、外出先から自宅のPCに接続したいことが増えてきました。
そこでRaspberryPi 3にSoftetherをインストールし、VPNサーバを立てたのでその手順を説明します。

RasphberryPiにSoftether VPNをインストールする解説記事はいくつもありますが、RaspberryPiのセットアップからOCNバーチャルコネクトを使っている場合のポート開放、クライアントの設定まで一連の流れを説明している記事はあまりなかったので、自身の忘備録をかねてまとめました。

今回実現したことは以下になります。
- 外出先でノートPC(ubuntu)から自宅のネットワークに接続
- 外出先でスマホ(Android)から自宅のネットワークに接続
- Raspberry Pi自身にもssh接続

この実現にあたりSoftetherの公式ページにある、[「リモートアクセスVPN」](https://ja.softether.org/4-docs/2-howto/1.VPN_for_On-premise/2.Remote_Access_VPN_to_LAN)を構築しました。

### 環境
- ハードウェア
    - サーバ側:
        - VPNサーバ: Raspberry Pi 3B+
        - ルータ: NEC Aterm WX3600HP
    - クライアント側:
        - Ubuntu Desktop 22.04
        - Xperia (Android)
- ソフトウェア
    - Softether v4.42
- 自宅のネットワーク環境
    - OCNバーチャルコネクト

### 流れ
1. 事前準備
1. RaspberryPiのセットアップ
1. OpenVPNサーバの設定
1. Ubuntuの設定
1. ルータのポート開放
1. クライアントの設定

構築は公式の[チュートリアル](https://ja.softether.org/4-docs/2-howto/1.VPN_for_On-premise/2.Remote_Access_VPN_to_LAN)の流れに沿って行いましたが、自宅にWindowsがないため直接コマンドを実行して各設定を行いました。
Windowsがある方はチュートリアルにあるようにGUIアプリを使ったほうが簡単だと思います。

# 1. 事前準備
### ssh鍵生成
クライアントPC上でRaspberryPiへログインする時に使用するssh鍵を生成します。
今回は最もセキュリティの高いed25518を使用しました。

```
$ cd .ssh
$ ssh-keygen -t ed25510 -f <key-file-name>
(パスフレーズ入力)

$ ls
<key-file-name> <key-file-name>.pub
```

### 開放可能なポート確認
自分のインターネット回線はOCN光のOCNバーチャルコネクトです。OCNバーチャルコネクトでは開放できるポートに制限があり、Softetherで標準で使用することになっているポートは基本的に使えません。
詳しくは「OCNバーチャルコネクト ポート開放」などでググって下さい。


開放できるポートとその設定方法は次のとおりです。「Aterm WX3600HP」での設定方法になります。
1. ルータの設定画面を開き「ポートマッピング設定」を選択します
1. 「追加」を選択します
1. 「利用可能ポート」の一覧にあるポートが開放可能なポートです
![port.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293692/e849b3ce-6a5b-2322-0e00-67d2be3ab77a.png)


# 2. RaspberryPiのセットアップ
### Ubuntu Server 22.04のイメージの準備
初めにOSのインストールを簡単に行えるRaspberry Pi Imagerをインストールし、次にImagerを使ってSDカードにOSイメージを書き込みます。
SDカードをPCに接続しておいて下さい。

1. パッケージを[公式サイト](https://www.raspberrypi.com/software/)からダウンロードする
2. Imagerインストール
    ```
    $ sudo apt install ./imager_1.7.5_amd64.deb
    ```
3. Imager起動
    ```
    $ rpi-imager
    ```
4. インストールするOSを選択
    「CHOOSE OS」-> Other general-purpose OS」->「ubuntu」->「ubuntu server 22.04.02 LTS (64-bit)」
    ![Screenshot from 2023-07-27 07-06-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293692/f1a824c6-71a2-f7d9-f28e-3df13adfdada.png)
5. 保存先のSDカードを選択
    「CHOOSE STORAGE」-> 表示されたリストからインストール先のSDカードを選択
6. OSを選択したら右下に設定メニューボタンが表示されるので、その設定メニューを選択
    OSイメージの書き込み時にホスト名やssh key等の設定ができる。RaspberryPiの起動後にやってもいいが、ここでやっておくのが簡単。
    設定できる項目は以下の通り。ssh鍵を設定する場合は事前準備で生成した公開鍵をここで使用する。
    - ホスト名
    - ssh設定
        - パスワード認証を許可するか
        - ssh公開鍵
    - ユーザ名とパスワード
    - wifi
    - locale
        - タイムゾーン
        - キーボード配置
7. 「WRITE」を選択し、SDカードにOSイメージを書き込む

### Ubuntuの設定
イメージを書き込んだSDカードをRaspberryPiにセットし、起動する。
OSイメージの書き込み時にホスト名などは設定済みとする。設定していない場合はここで手動設定する。

#### パッケージの更新・インストール
パッケージの更新と、Softetherのビルドに必要なパッケージをインストールする
```
$ sudo apt update
$ sudo apt upgrade -y
$ sudo apt install build-essential
$ sudo apt install make
```

#### ファイアウォールの設定
後ほどVPNで使用するポートを開放するが、まずは22番ポートだけ開放しておく
```
$ sudo ufw enable
$ sudo ufw allow 22
```
    
#### ネットワーク設定
これもSoftetherの設定時に変更するが、最低限の設定だけしておく。
```
$ cd /etc/netplan
$ sudo vi 99-customize.yaml
```

``` 99-customize.yaml
network:
    ethernets:
        eth0:
            dhcp4: true
    version: 2
```
```
$ sudo netplan apply
```

## 3. Softetherの設定
[公式のリモートアクセスVPNチュートリアル](https://ja.softether.org/4-docs/2-howto/1.VPN_for_On-premise/2.Remote_Access_VPN_to_LAN)
[VPN Server管理コマンド一覧](https://ja.softether.org/4-docs/1-manual/6/6.3)

### ダウンロード
[ここ](https://www.softether-download.com/ja.aspx?product=softether)から最新版をダウンロードします。各選択肢は以下とします。
- ダウンロードするソフトウェアを選択: SoftEther VPN (Freeware)
- コンポーネントを選択: SoftEther VPN Server
- プラットフォームを選択: Linux
- CPUを選択: ARM 64bit (64bit)
自分がインストールしたのは`v4.42`です。

例：
```
$ wget https://jp.softether-download.com/files/softether/v4.42-9798-rtm-2023.06.30-tree/Linux/SoftEther_VPN_Server/64bit_-_ARM_64bit/softether-vpnserver-v4.42-9798-rtm-2023.06.30-linux-arm64-64bit.tar.gz
```
### インストール
tarファイルを解凍し、移動
```
$ tar -xzvf softether-vpnserver-{version}-linux-arm64-64bit.tar.gz
$ sudo mv vpnserver /usr/local
```

### ビルド
```
$ cd /usr/local/vpnserver
$ make
```

### パーミッション設定
```
$ sudo chmod -R 600 *
$ sudo chmod 700 vpncmd
$ sudo chmod 700 vpnserver
```

### 動作確認
```
sudo ./vpncmd

# 以下の表示がされるので、3を入力する
Select 1, 2 or 3: 3

# 次に check コマンドを入力
VPN Tools> check
```
The command completed successfully. と表示されれば成功。`exit`と入力して終了する
```
VPN Tools> exit
```

### 設定値の準備
Softetherの設定の前に必要な設定値を決めておきます。以後の説明では「設定例」の値を使います。
| 設定項目 | 設定に使用するコマンド | 設定例 |
| - | - | - |
| VPNサーバの管理者パスワード| ServerPasswordSet | vpn_password |
| 仮想Hubの名前 | HubCreate | vhub |
| 仮想Hubのパスワード | HubCreate | vhub_password |
| ユーザ名 | UserCreate | vpn_user |
| ユーザパスワード | UserPasswordSet | user_password |
| IPsec事前共有キー | IPsecEnable | shared_key |
| TAPデバイス名 | BridgeCreate | vpn |
| リスナーポート | ListenerCreate | 10000 |
| OpenVPNで使用するポート番号 | OpenVpnEnable | 10001 |

なお、ここで使用するリスナーポートとOpenVPNのポート番号は、先に確認した開放可能なポート番号とします。
（違ってもいいのですが、自分はわかりやすさのためにそうしました）

### Softetherの設定
```
# 初めにサーバを起動する
sudo ./vpnserver start
sudo ./vpncmd

# 以下の表示がされるので、1を入力する
Select 1, 2 or 3: 1

# 以下の入力が促されるが、何も入力せずEnterを押す
Hostname of IP Address of Destination:
Specify Virtual Hub Name:
```

#### 管理者パスワードの設定
```
VPN Server> ServerPasswordSet

Password: vpn_password
Confirm input: vpn_password
```

`The command completed successfully.`と表示されれば成功です。
以後のコマンド実行時も同様です。

#### リスナーポートの追加
デフォルトで443、992、1194、5555の4つが設定されています。
不要な場合は削除します。
※ `./vpncmd`で起動するとき最初のIPアドレス/ホストの入力を空にするとデフォルトポートに接続するので、デフォルトのポートを削除する場合は起動時にポートの指定が必要となります

```
VPN Server> ListenerCreate 10000

# 不要な設定の削除
VPN Server> ListenerDelete {削除するリスナーポート}

# 設定値の確認
VPN Server> ListenerList
```

#### 仮想Hubの設定
```
VPN Server> HubCreate

Name of Virtual Hub to be created: vhub

Password: vhub_password
Confirm input: vhub_password

The command completed successfully.
```

#### ユーザの作成
```
# 初めに作成した仮想ハブを選択する
VPN Server>Hub vhub

# ユーザ作成
VPN Server/pi-vhub> UserCreate

User Name: vpn_user

# 以下の内容はオプション。必要なければ入力しなくていい
Assigned Group Name: 
User Full Name: 
User Description: 

The command completed successfully.

# ユーザパスワードセット
VPN Server/pi-vhub> UserPasswordSet

User Name: vpn_user

Password: user_oassword
Confirm input: user_password

The command completed successfully.

# 作成したユーザの確認
VPN Server/pi-vhub> UserList
```


これで仮想HUBに対する設定は終わりなので抜けます
```
VPN Server/pi-vhub> Hub
```

#### IPsecの設定
```
VPN Server> IPsecEnable

Enable L2TP over IPsec Server Function (yes / no): yes

Enable Raw L2TP Server Function (yes / no): no

Enable EtherIP / L2TPv3 over IPsec Server Function (yes / no): no

Pre Shared Key for IPsec (Recommended: 9 letters at maximum): {IPsec事前共有キー}

Default Virtual HUB in a case of omitting the HUB on the Username: {仮想Hub名}

The command completed successfully.
```

#### OpenVPNの設定
```
VPN Server> OpenVpnEnable

Enables OpenVPN Clone Server Function (yes / no): yes

UDP Ports to Listen for OpenVPN (Default: 1194 / Multiple Accepted): {OpenVPNで使用するポート番号}
```

#### ダイナミックDNSの確認
```
VPN Server> DynamicDnsGetStatus

# 各値が表示されればOK
```

もしDNSの値を変更したい場合は、以下のコマンドで設定可能です。

```
VPN Server> DynamicDnsSetHostname {ホスト名}
```

#### ローカルブリッジとTAPデバイスの設定
```
VPN Server> BridgeCreate {仮想Hub名} /DEVICE:{作成するTAPデバイス名} /TAP:yes
...
The command completed successfully.

# 作成したBridgeの確認
VPN Server> BridgeList
```

#### 補足
SecureNATを設定している例もありますが、自分はルータがDHCPサーバをかねており不要なので設定していません。
もしSecureNATが必要な場合は以下のコマンドで有効化できます。
```
VPN Server/pi-vhub> SecureNatEnable 

# 確認
VPN Server/pi-vhub> SecureNatStatusGet
```

# 4. Ubuntuの設定
設定の途中でsshが切れるので、sshではなく直接ログインしたほうがいいです。
ここの設定では以下を事前に決めておく必要があります。

| 設定項目 | 例 |
| - | - |
| Raspiの固定IPアドレス | 192.168.1.2 |
| ブリッジ名 | br0 |

また、以下の値を`ip`コマンドなどで確認しておいて下さい。
- デフォルトゲートウェイのIPアドレス
- 物理NIC名

### ネットワーク設定
#### ブリッジ設定
ブリッジの設定をするためbridge-utilsをインストール
```
$ sudo apt install bridge-utils
```

ブリッジの作成
```
$ sudo brctl addbr br0
```

物理NICと先ほど作成したtapデバイスのブリッジを設定します。TAPデバイス名は先程作成したデバイス名の先頭に`tap_`をつけた名前となります。この例では`tap_vpn`です。

```
# 初めに物理NICとTAPデバイスの名前を確認します。
$ ip addr

# ブリッジの設定
$ sudo brctl addif br0 eth0
$ sudo brctl addif br0 tap_vpn

# 設定の確認
$ brctl show
```

#### ネットワーク設定
IPアドレスなどの設定をします。

``` /etc/netplan/99-customize.yaml
network:
    ethernets:
        eth0:
            dhcp4: no
            dhcp6: no
        tap_vpn:
            dhcp4: no
            dhcp6: no
            addresses: [192.168.4.101/24]
            optional: true
            accept-ra: false
    bridges:
        br0:
            interfaces: [eth0, tap_vpn]
            addresses: [192.168.4.100/24]
            routes:
                - to: default
                  via: 192.168.4.1
            nameservers:
               addresses: [192.168.4.1, 8.8.8.8]
    version: 2
```

設定の反映
```
$ sudo netplan apply
```

### サービス登録
Raspi起動時に自動でVPNサーバが起動するようサービスに登録する
``` /etc/systemd/system/softether-vpn.service
[Unit]
Description=SoftEther VPN 
After=network.target

[Service]
Type=forking
ExecStart=/usr/local/vpnserver/vpnserver start
ExecStop=/usr/local/vpnserver/vpnserver stop
KillMode=process
Restart=on-failure

[Install]
WantedBy=multi-user.target
```

サービスの有効化
```
$ sudo systemctl enable softether-vpn
$ sudo systemctl start softether-vpn
$ sudo reboot
```

# 5. ルータのポート開放
Softetherで設定したリスナーポートとOpenVPNのポートを開放します。
1. ルータの設定画面を開き「ポートマッピング設定」を選択します
1. 「追加」を選択します
1. 画面下部の「NATエントリ追加」に必要な情報を入力します
    1. 優先度: 設定の優先度です。任意の値を入力します
    1. LAN側ホスト: RaspberryPiのIPアドレスを入力します
    1. プロトコル: リスナーポート用の設定はTCP、OpenVPN用のポートはUDPにします
    1. 変換対象ポート番号: リスナーポートとOpenVPNのポートを入力します
    1. 宛先ポート番号: 変換対象ポート番号と同じポートを入力します

# 6. クライアントの設定
UbuntuにSoftether clientの設定と、AndroidスマホにOpenVPNの設定をします。
設定にあたり必要な項目は以下の通りです。
| 設定項目 | 設定コマンド | 設定例 |
| - | - | - |
| 仮想NIC | NicCreate | vpn_nic |
| 接続設定の名前 | AccountCreate | home-vpn |

また、サーバ側で設定した以下の値も使用します。
- ホスト名
- ポート番号
- 仮想Hub名
- ユーザ名
- ユーザパスワード

参考:
- [公式のコマンド一覧](https://ja.softether.org/4-docs/1-manual/6/6.5_VPN_Client_Management_Command_Reference)


### Softether Client
#### ダウンロード
[ここ](https://jp.softether-download.com/files/softether/v4.42-9798-rtm-2023.06.30-tree/Linux/SoftEther_VPN_Client/64bit_-_ARM_64bit/softether-vpnclient-v4.42-9798-rtm-2023.06.30-linux-arm64-64bit.tar.gz)からクライアントソフトをダウンロードします。

#### インストール
tarファイルを解凍し、移動
```
$ tar -xzvf softether-vpnclient-v4.42-9798-rtm-2023.06.30-linux-arm64-64bit.tar.gz
$ sudo cd vpnclient /usr/local
```

#### ビルド
```
$ cd /usr/local/vpnclient
$ make
```

#### クライアントアプリの起動
```
$ sudo ./vpnclient start
```

#### 仮想NICの設定
起動
```
$ ./vpncmd 

1. VPN Server または VPN Bridge の管理
2. VPN Client の管理
3. VPN Tools コマンドの使用 (証明書作成や通信速度測定)

# 2を選択
1 - 3 を選択: 2
```

仮想NICの設定
```
VPN Client> NicCreate vpn_nic
```

#### アカウント設定
接続に使用するアカウント設定をします
```
VPN Client> AccountCreate          
AccountCreate コマンド - 新しい接続設定の作成
接続設定の名前: home-vpn

接続先 VPN Server のホスト名とポート番号: vpn650616521.softether.n
et:55726

接続先仮想 HUB 名: vhub

接続するユーザー名: vpn_user

使用する仮想 LAN カード名: vpn_nic
```

#### パスワード設定
アカウントのパスワードを設定します
```
VPN Client> AccountPasswordSet
接続設定の名前: home-vpn

パスワードを入力してください。キャンセルするには Ctrl+D キーを押してください。

パスワード: user_password
確認入力  : user_password

standard または radius の指定: standard
```

#### 自動接続設定
クライアントの起動時に自動でVPN接続する
```
VPN Client> AccountStartupSet
```

#### Ubuntuのネットワーク設定
```/etc/netplan/99-customize.yaml
network:
  version: 2
  ethernets:
    vpn_vpn_nic:
      dhcp4: true
```

設定の有効化
```
$ sudo netplan apply
```

外部のネットワークから自宅のネットワークに接続できれば成功です。自分はスマホのテザリングを使って確認しました。
また接続に成功していたら仮想NICに対して自宅ネットワークのIPアドレスがDHCPによって割当られています。`ip`コマンドなどで確認して下さい。

#### 補足
Ubuntuの起動時に自動でVPN接続することも可能ですが、任意のタイミングで起動したいため自分はしていません。
手動で起動する場合はUbuntuの起動後以下を実行します。

```
$ sudo ./vpnclient start
```

### OpenVPN
AndoridからOpenVPNにアクセスするためにAndroidにOpenVPNの設定をします

#### 設定ファイル出力
Softetherサーバ側でOpenVPNの設定ファイルを出力します
```
$ cd /usr/locao/vpnserver
$ sudo ./vpncmd

Select 1, 2 or 3: 1

VPN Server> OpenVpnMakeConfig openvpn_config.zip
```
出力されたopenvpn_config.zipファイルを回答し、`pi-vpn_openvpn_remote_access_l3.ovpn`というファイルがあることを確認します。

このファイル名がOpenVPNの設定名になるので分かりやすい設定名としたい場合はファイル名を任意の名前に変更します。
```
$ mv pi-vpn_openvpn_remote_access_l3.ovpn openvpn-config.ovpn
```

#### Androidの設定
以下の手順で設定します
1. Androidデバイスに`openvpn-config.ovpn`をコピー
2. AndroidにOpenVPNアプリをインストール
3. アプリを起動し、`import`から`openvpn-config.ovpn`を選択します
4. 以下の設定をします。
    1. UserName: {vpnのユーザ名}@{仮想HUB名}
    2. Save passwordにチェック
    3. Password: {vpnユーザのパスワード}

設定の参考：[リンク](https://solomon-review.net/construct-softether-vpn-19/#6%E8%A8%AD%E5%AE%9A%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E8%AA%AD%E3%81%BF%E8%BE%BC%E3%81%BF)

# 最後に
以上で設定は終わりです。
クライアントからの接続などがうまく行かない場合は`/usr/local/vpnserver`ディレクトリ下にsoftetherの3種類のログが、`/var/log/ufw.log`にファイヤーウォールのログ出力されているので、それぞれを確認するとよいです。

なお、自分が使っているルータ`NEC Aterm WX3600HP`はログが見れない仕様なので、ポート開放に失敗していた場合の確認に手間取りました。。。

自分が参考にしたサイトのリンクを貼っておきます。基本的には公式を読み、わからないところがあれば他のサイトを参照する、という読み方がいいと思います。

- 公式
    - [Softetherプロジェクト](https://ja.softether.org/)
    - [リモートアクセスVPNチュートリアル](https://ja.softether.org/4-docs/2-howto/1.VPN_for_On-premise/2.Remote_Access_VPN_to_LAN)
    - [サーバコマンド一覧](https://ja.softether.org/4-docs/1-manual/6/6.3)
    - [クライアントコマンド一覧](https://ja.softether.org/4-docs/1-manual/6/6.5_VPN_Client_Management_Command_Reference)
- その他サイト
    - [SoftEther VPN サーバをコマンド操作だけで構築 (設定) する方法](https://www.gadgets-today.net/?p=5651)
    - [Ubuntu(Linux)でVPNサーバー構築【SoftEther VPN】](https://cgbeginner.net/ubuntu-softether-vpn/)