Dockerでpritunlを用いたVPNを構築した話

# 前置き

嫁から出先のwifiを安全に利用したいというリクエストがあったので、VPNを自宅に構築して出先から接続できるようにした。

## 選択肢と採用に至るまで

VPNを構築する方法はいくつかある。

- pritunl
- SoftEther VPN
- etc...

SoftEtherはAndroidやiPhoneに標準搭載されているクライアントで接続できるので魅力的だが、構築にそこそこの専門知識が必要っぽい。
pritunlはインストールしてブラウザ経由で簡単な設定をすれば利用できるようになる。

自分はソフト屋で、あんましインフラには詳しくないのよなー、ということでpritunlを採用した。

## なぜにDockerを使うのか

自宅にVPNを構築するとなったが、自宅にサーバー機など用意できる資金もなく、有り合わせのノートPCにCentOS7をインストールしてサーバー機として運用することにした。
で、Try&Errorで構築作業をすすめるにあたり、なるべく面倒がない方法でやりたいがために、Dockerを採用した。

# 構築

実際の成果物は[GitHub](https://github.com/loasnir/docker-vpn)で公開しています。

## マシンの準備

[CentOS7](https://www.centos.org/download/)のページからMinimal ISOをダウンロードしDVDを作成。
マシンにインストールします。

その後rootでログインし、まずは無線接続設定を行います。

```shell
# ネットワークインタフェースの一覧を確認
> nmcli d
デバイス         タイプ    状態      接続            
wlp2s0           wifi      管理無し  --              
enp1s0           ethernet  利用不可  --              
veth433c7fe      ethernet  管理無し  --              
veth8362024      ethernet  管理無し  --              
lo               loopback  管理無し  --              

# 利用可能なwifiを検索
> nmcli dev wifi list
*  SSID                              モード    CHAN  レート     信号  バー  セキュリティ 
   aterm-*****-g                    インフラ  9     54 Mbit/s  100   ▂▄▆█  WPA1 WPA2    

# コネクション名とSSIDを登録
> nmcli con add con-name {{cname}} ifname {{dname}} type wifi ssid aterm-*****-g

# 接続のセキュリティ設定
> nmcli con modify {{cname}} wifi-sec.key-mgmt wpa-psk

# wifiのパスワードを登録
> nmcli con modify {{cname}} wifi-sec.psk ********

# ネットワークインタフェースを立ち上げ
> nmcli con up {{cname}}

```

次に、ノートPCなので蓋を閉じてスリープなどにならないようにします。

```shell
# バックアップ
cp /etc/systemd/logind.conf{,.org}

# 値の書き換え
sed -i "s/#HandleLidSwitch=suspend/HandleLidSwitch=ignore/" /etc/systemd/logind.conf
sed -i "s/#HandlePowerKey=poweroff/HandlePowerKey=ignore/" /etc/systemd/logind.conf
sed -i "s/#HandleSuspendKey=suspend/HandleSuspendKey=ignore/" /etc/systemd/logind.conf
sed -i "s/#HandleHibernateKey=hibernate/HandleHibernateKey=ignore/" /etc/systemd/logind.conf

# サービスリスタート
systemctl restart systemd-logind.service
```

次にルーター側の設定ですが、これはお使いのルーターによって設定方法が異なるため、各自ググってください。
その際に必要なMACアドレスについては以下のコマンドで取得できます。

```shell
> nmcli
```

ここまで出来たら、電源に繋いで所定の位置に置きっぱなしにします。

## Gitから成果物をダウンロード&解答

wgetが標準では入ってないのでインストールして、GitHubのリリースページから最新の物をダウンロード。

```shell
> yum install -y wget
> wget https://github.com/loasnir/docker-vpn/archive/1.0.3.tar.gz
> tar -zxvf 1.0.3.tar.gz
> mv docker-vpn-1.0.3 vpn
```

## dockerとdocker-composeをインストール

docker-composeは標準のyumリポジトリに入ってないのでepelリポジトリを追加。
dockerサービスを動かして、firewallに穴を開けます。
必要なポートは、

- 80 http
- 443 https
- 1194 openvpn

の3つです。

```shell
> sh bin/setup.sh
```

```shell:bin/setup.sh
yum install -y epel-release
yum install -y docker docker-compose
systemctl start docker
systemctl enable docker

firewall-cmd --zone=public --add-service=http --permanent
firewall-cmd --zone=public --add-port=443/tcp --permanent
firewall-cmd --zone=public --add-port=1194/tcp --permanent
firewall-cmd --zone=public --add-port=1194/udp --permanent
firewall-cmd --complete-reload
```

## dockerで環境構築

イメージは[Docker Hub](https://hub.docker.com/)から[jippi/pritunl](https://hub.docker.com/r/jippi/pritunl/)と[mongo](https://hub.docker.com/_/mongo/)を選択しました。
pritunl側からmongo側にアクセスするため、environmentを定義しています。
mongo側はデータを外出しないとリスタートの度にデータが飛んでしまうので、volumesを定義しています。

```shell
> docker-compose up -d --build
```

```docker:docker-compose.yml
version: '2'
services:
  pritunl:
    container_name: pritunl
    restart: always
    image: jippi/pritunl
    privileged: true
    environment:
      - PRITUNL_MONGODB_URI=mongodb://mongo:27017/pritunl
    ports:
      - 80:80
      - 443:443
      - 1194:1194
  mongo:
    container_name: mongo
    restart: always
    image: mongo
    privileged: true
    volumes:
      - /data/db:/data/db
```

## ブラウザからVPNの設定

こちらが詳しいです。
http://christina04.hatenablog.com/entry/2014/11/01/141627

違うところは、ブラウザからのアクセスが

```
http://固定したIP/
```

というところです。
また、

| 項目 | 説明 | 値 |
|:--|:--|:--|
| Name | 名前。任意 | example-vpn |
| Port | 解放ポート。任意 | 12345 |
| Protocol | プロトコル。VPNは基本UDP | udp |

このうち、開放ポートとプロトコルも覚えておいてください。

## 開放ポート設定

ブラウザから設定した際に、新たにポートを開放する必要が生じましたので、まずfirewallのポートを開放します。

```shell
> firewall-cmd --zone=public --add-port=12345/udp --permanent
> firewall-cmd --complete-reload
```

次にdocker-compose.ymlを編集します。

```shell
> vi docker:docker-compose.yml
```

```docker:docker-compose.yml
version: '2'
services:
  pritunl:
    container_name: pritunl
    restart: always
    image: jippi/pritunl
    privileged: true
    environment:
      - PRITUNL_MONGODB_URI=mongodb://mongo:27017/pritunl
    ports:
      - 80:80
      - 443:443
      - 1194:1194
###### ここを追加 ###############################
      - 12345:12345/udp
###############################################
  mongo:
    container_name: mongo
    restart: always
    image: mongo
    privileged: true
    volumes:
      - /data/db:/data/db
```

最後にdockerコンテナに編集を反映します。

```shell
> docker-compose up -d --build
```

構築作業は以上になります。

# 作業を終えて

実際に手を動かしてみると、ハマりどころが多くて苦労しました。
ただ、これらの成果物を一度作ってしまえば環境が変わったときに再構築が容易だというのがDockerの旨味なので、それはしっかり享受していきたいですね。
ゆくゆくはサクラのVPSとかに移したいですし。