OpenVPN構築つまづきポイントまとめ

# はじめに
OpenVPN構築の際に、つまずいたりハマってしまったポイントについて、メモとして書いていたものをまとめた記事です。あくまで自分用のメモをまとめたものなので、内容を保証することはできません。確実に正しい情報を知りたい場合は公式サイトを見ましょう。

**※この記事で "[ ]"（角括弧というらしいです）が出てきた時は、「自分の環境に合わせて入れてね」という意味で実際にこの記号を入れる必要は無いです。**

# どんなVPNを構築したか
今回、VPN構築にあたっての要件は以下の通り。

1. 最高にセキュアなVPNであること（構築時点）
2. フリーWi-Fi接続時に安全に通信できること
3. **ポート開放せずに**、外出先から自宅内のネットワークにアクセスできること
4. 接続元（クライアント）のIPアドレスを隠せること

これらの要件から、VPNサーバーはクラウド（Azure）上のVMに構築し、家の中に設置したVPNクライアントと常に接続させることで実現できると考えた。

# 環境
* Ubuntu Server 22.04.4
* OpenVPN 2.6.8

Azure上のVMには固定IPを割り当てている。

ネットワーク図

![VPNネットワーク構成図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3311657/fc0cb034-3ad4-cc68-6259-ad9ea3d6d75e.png)



# 変更履歴
追記したり、変更しなくてはいけないとこがあったらここに書く。

# つまづきポイント
## 1. tar.gz からの構築
### 現象
要件1を満たすために、OpenVPNの最新版をインストールしたかった。(aptなどのパッケージ管理ツールからでは古いバージョンになってしまうため)

公式サイトから最新バージョンのtar.gzをダウンロードし、[How To](https://www.openvpn.jp/document/how-to/#Installing "OpenVPN.JP How To")に従って進めようとした。

しかし、./configure、make、make install を順に実行しても構築できなかった。

### 解決方法
エラーが表示されるのでそれをよく見よう。

パッケージが足りない旨のエラーが表示されるので、それをもとに、aptで必要なパッケージを入れてから再度実行すれば構築できる。

私の環境の場合、足りなかったパッケージは以下の通り。
* pkg-config
* build-essential
* libnl-genl-3-dev
* libcap-ng-dev
* libssl-dev
* liblz4-dev
* liblzo2-dev
* libpam-dev

また、sudo権限で./configureなどを実行する必要があることに注意。

## 2. Azure上のVMから自宅内のPCにファイルを転送するには
### 現象
Azure上のVMから、自宅内に設置したCAにファイルを送りたい。
しかしWAN側から自宅内に通信するには、ポートを開放しなければならない。
めんどくさいし、ポート開放しないで自宅内に通信できるようにするのが今回の目的なので、一時的とはいえポート開放してしまえば本末転倒である。

### 解決方法
**WinSCPを使おう。**
ドラッグ&ドロップでファイルを移動できる。

※Azure Filesを使う方法もあるがめんどくさいぞ

## 3. VPNサーバーの自動起動ができない
### 現象
systemdを使って、VM起動時に自動的にOpenVPNサーバーも立ち上がるようにしたい。
しかしエラーを吐いて起動しない。

### 解決方法1
まずは**サーバーの秘密鍵にパスワードを設定していないか**確認。
パスワードを設定している場合は .serviceの設定だけでは起動できない。
(パスワードが書かれたファイルを作成することで、パスワードが設定されていても起動できる方法があった気がするが果たして意味はあるのか･･･？)


### 解決方法2

秘密鍵にパスワードを設定していなければ、**シェルスクリプトと .serviceを組み合わせた方法**でやってみる。

まずは好きなディレクトリに任意の名前のシェルスクリプトを作成。

```text:[任意の名前].sh
#!/bin/bash
openvpn /home/[ユーザー名]/openvpn-2.6.8/server.conf    #openvpn [server.confまでのパス]の形で書く
```

※`#!/bin/bash`を書くのを忘れないこと

**また、chmod 700 して実行権限を付与すること。**

<br>

次に、`/etc/systemd/system/`に[任意の名前].serviceファイルを作成する。
中身は以下

```text:[任意の名前].service
[Unit]
Description=[任意の名前]
After=network.target

[Service]
ExecStart=[作成した.shまでのパス]
Type=simple
Restart=no

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

※もちろん[Unit]、[Service]、[Install]には "[ ]" が必要です。

作成後、`sudo systemctl enable [上で作成した任意の名前].service`して、有効化する。

その後再起動し、`sudo systemctl status [任意の名前].service`で、正常に実行されたか確認。
active (running) となっていればよし。

## 4. サーバーを構築したのに接続できない
### 現象
How Toどおりに構築したはずなのに、なぜかクライアントから接続できない。
クライアント上では「接続中」と出たまま、ログが繰り返される。
などなど･･･

### ステップ1
まずはログをしっかり確認してみる。
[server or client].conf の中に、`log [logの出力先とファイル名のパス]`と、`verb 4`を書くことで、調査の手がかりを得やすくなる。

logの出力先はホームディレクトリがおすすめ。確認しやすい。
また、verbは"4"がおすすめ。数字を上げるともっと詳細なログが出力されるが、余計なもの（RwRwwwwRWrrrrwwwみたいなやつ) (パケットの読み書き(?)らしい）が出てくるので見づらい。

Serverの場合、正常に起動できれば、logの最後は `Initialization Sequence Completed` と表示される(はず･･･)。

それ以外のものが表示されていたり、エラーが出ていたりすればそれが怪しい。

### ステップ2
logを確認し、エラーが出ていたときは、たいてい .conf の記述ミスだったりする。

ありがちな記述ミスとして、
* スペルミス
* Client側と設定が合っていない

 の二つがある。

 前者は目を皿のようにして探してください。
 
 後者はこの記事を見るとよい。

 https://community.openvpn.net/openvpn/wiki/Openvpn24ManPage

 ここではハイフンが二つならんだ形のあとにオプション名が書いてあるが、.conf にオプションを書くときにはハイフンは要らない。

 ブラウザのページ内検索機能を使って、自分が設定しているオプションの説明書きを見るとよい。たまに、「このオプションはクライアント側と合わせる必要がある」的なことが書いてある。圧縮の設定とかそうだった気がする。（違ってたらごめんなさい）

 ### ステップ3
 logにエラーが出ていない人はネットワークの設定を疑いましょう。
 
ポイント

 * 通信に必要なポートは空いているか？
 * Serverから外に向けてpingは通るか？
 * **(安全な環境の場合のみ)** iptables や ufw のデフォルトポリシーをACCEPTにして試してみたか？
 * iptablesでlogを取る設定にして、dropされたパケットを見てみたか？
 * tapもしくはtunインターフェースは作成されているか？
 * (iptables の場合) filtersテーブルのFORWARD も許可する設定になっているか？
 * 設定ファイルでフォワードは許可されているか？

特に最後の項目。
ufw を使っている人は、

```diff_shell:/etc/default/ufw
- DEFAULT_FORWARD_POLICY="DROP"
+ DEFAULT_FORWARD_POLICY="ACCEPT"
```

```diff_shell:/etc/ufw/sysctl.conf
- #net/ipv4/ip_forward=1
+ net/ipv4/ip_forward=1
```

iptables を使っている人は、

```diff_shell:/etc/sysctl.conf
- #net.ipv4.ip_forward
+ net.ipv4.ip_forward
```

の設定を忘れずにすること。
これをしないと、ファイアウォール上は許可されているのに、何故かパケットが捨てられてるとかいう謎現象に遭遇し、時間を溶かすので要注意。


 ### ステップ4
 これらステップを経ても解決しない場合は、以下をループしてやってみてください。

 1. (エラーが出ているときは、エラー文で検索してみる)
 2. 原因を考え切り分ける
 3. 解決策を考える
 4. 解決策を片っ端から試す
 5. 疲れたらベッドに寝っ転がって、頭の中を空っぽにする

おすすめです。

## 5. OpenVPN for Androidから接続できない
### 現象
Android端末に OpenVPN for Android を入れ、作成した .ovpnファイルや鍵をスマホに転送し、アプリ上でインポートもしたのに接続することができない。
「接続中」となっていたり、「Connecting」となっていて永遠に接続できない。

### 解決方法
他の端末（Windowsなど）からVPNサーバーに接続できるなら、恐らく原因は OpenVPN for Android 側にある。
私の場合は、プロファイル内の設定の、以下の設定が原因だった。

* BASIC の中にある「LZO Compression」の無効化（サーバー側と設定を合わせる）
* IP AND DNS の中にある「Pull Setting」の有効化（手動でIPアドレスやDNSを設定するのではなく、サーバーからそれらの設定を取得する設定）
* AUTHENTICATION/ENCRYPTION の中にある「Encryption ciphers」の設定（サーバー側と設定を合わせる）
* AUTHENTICATION/ENCRYPTION の中にある「TLS Security Profile」の設定（内容を確認してサーバーと合わせる）

やはりサーバー側との設定の違いで接続できないことが多かった。

<br>

※余談だが、圧縮設定は行わない方が良いとの文を見かけた。
暗号と圧縮は、組み合わせてしまうと、ときに暗号を破る手掛かりになってしまうことがあるらしい。
しっかり暗号化することに重点を置くのか、パフォーマンスに重点を置くかによって、圧縮の設定をするか否か決めると良いだろう。


引用元：[Openvpn24ManPage](https://community.openvpn.net/openvpn/wiki/Openvpn24ManPage#:~:text=%2D%2Dcompress%20%5Balgorithm%5D "Openvpn24ManPage") の --compress の一部

原文

>>Compression and encryption is a tricky combination. If an attacker knows or is able to control (parts of) the plaintext of packets that contain secrets, the attacker might be able to extract the secret if compression is enabled. See e.g. the CRIME and BREACH attacks on TLS which also leverage compression to break encryption. If you are not entirely sure that the above does not apply to your traffic, you are advised to *not* enable compression.

訳文（DeepL）

>>圧縮と暗号化は厄介な組み合わせである。攻撃者が秘密を含むパケットの平文（の一部）を知っているか、制御できる場合、圧縮が有効になっていると、攻撃者は秘密を引き出すことができるかもしれない。TLSに対するCRIME攻撃やBREACH攻撃も、圧縮を利用して暗号化を破っている。自分のトラフィックに上記が適用されないことが完全に確実でない場合は、圧縮を有効にしないことを推奨する。


## 6. VPNを自動的に再接続させるには？
### 現象
私の環境は、AzureのVMに作成したVPNサーバーと、自宅に設置したVPNクライアントとを常に接続することで、VPNに参加した端末が自宅にアクセスできるようにしている。
しかし、常にVMを起動しておくのはお金がかかる。
また、常時起動ではセキュリティが少し心配。（常に起動するということは、常に攻撃に曝されることになるということ）

ということで、VMを停止させたのち再び起動したときでも、サーバーと自宅間で、自動的にVPNが張られるようにしたいのだが、どうすればよいのだろうか。

### 解決方法
**再接続に関するオプションを設定すればよい。**

`connect-retry n [max]`がそのオプションである。
[Openvpn24ManPage --connect-retry](https://community.openvpn.net/openvpn/wiki/Openvpn24ManPage#:~:text=%2D%2Dconnect%2Dretry%20n%20%5Bmax%5D "connect-retryについて")


n は接続を再試行するときの間隔（秒）
max は、n秒間隔の再試行を4~5回したのち、最終的に再接続の間隔を何秒空けるかの設定。4~5回の再試行後は、間隔が倍に増えていく。

例を示す。


```text:例１
connect-retry 1
```

 上記の場合は、再試行の間隔はずっと１秒となる。


```text:例２
connect-retry 5 30
```

上記の場合では、言葉での説明がめんどいので以下に示す。

接続試行→５秒待つ→試行→５秒→試行→５秒→試行→５秒→試行→５秒→試行→**10秒**→試行→**20秒**→試行→**30秒**→試行→30秒→試行→30秒→･･･

といった形になる。

よって、このオプションを自宅のクライアントに設定し、好きな間隔を指定してあげれば、VMを停止させて再度起動したときでも、勝手に接続してくれる。

接続の試行の回数を設定できるオプションもあったので（確かデフォルトでは無限）、それと併用することをおすすめする。

**ただし、この方式では１つだけ問題がある。**

**ログが肥大化することだ。**

永遠に接続を試行するので、接続に失敗したときにログが出力されてしまい、ちりつもでログが大きくなってしまう。
そのため、クライアントを常時起動する人はログを残さない設定にするか、あるいはクライアント起動時に、新しくログを作りなおす方式のログの出力オプションにして、定期的に再起動させるとよい。

ちなみに参考までに、私が（多分)１か月放置したときのログのサイズは、**8メガバイト程度**だった。

## 7. VPNサーバーを起動するとコマンドが打てなくなる！
### 現象
openvpn [server.confのパス] をすると、CLIが何も操作を受け付けなくなる！
Ctrl+C しちゃうと、コマンドは打てるようになるけどVPNサーバーも閉じちゃう！
クライアントでも同じ症状！！

### 解決方法
**仕様です（多分）**

SSHで繋いでいるなら、新しいウィンドウを開いて、そっちから接続しなおしましょう。

## 8. iptablesの設定をした後から起動が遅くなった
### 現象
iptablesでデフォルトポリシーを DROP にしてから、起動に時間がかかるようになった。
具体的には2分くらい。
SSHも繋げられない。
時間が経てば普通に使える
なおAzureの場合のみ。

### 解決方法
あとで別の記事にまとめてみようと思う。
簡単に言うと、169.254.169.254との通信をDROPしちゃってたため。



## 9. sudoを付けてコマンドを実行するとめちゃ遅い
### 現象
iptablesの設定をしてから、sudoを付けてコマンドを実行すると、正しく実行はされるものの応答が遅い。
なおAzureの場合のみ。

### 解決方法
あとで別の記事にまとめてみようと思う。
これも簡単に言うと、168.63.129.16との通信をDROPしちゃってたため。


## 8. 自宅内にアクセスできるようにするには？
### 現象
外出先から自宅内のパソコンに安全にアクセスしたい！
でもルーターのポートは開けたくない！！

### 解決方法
時間があれば、後で別の記事として書いてみようと思う。
までもHow Toにしたがって設定をすればいいだけ。
１つつまづきそうなのが、クライアントのルーティングテーブルに、自宅側へ通信するためのルートを設定しなければいけないこと。


# 最後に
これからOpenVPNでVPNを構築しようとしている人や、現在進行形で詰んでて困ってる人の助けになれば嬉しいです。

<br>
以上。
間違ってるところなどありましたら教えていただけると幸いです。