🌏

Docker 内に VPN サーバを導入してスマホから接続する

2023/09/16に公開

背景

海外旅行先で、日本国外のIPアドレスだと利用できない日本のサービスがいくつかあります。

私は NordVPN を使用した経験があります。しかし、「日本」と表示されているノード(サーバ番号)に接続しても、日本からの接続では無い、とエラーが表示され 利用できないサービス ( dアニメストア ) がありました。ノードはランダムで選択されます。全部の「日本」ノードがダメという訳ではありませんが、試した限り、体感8割ぐらいの「日本」ノードからは利用できなかったです。

ちなみに NotdVPN 自体は、回線速度や接続可能な国の数の観点から総合的に良いサービスであり、インターネットのセキュリティ保護の目的で利用を続けています。

しかしながら、確実に接続可能な日本のVPNサーバ、の目的は達成されていません。無料の VPN はセキュリティ的に怪しいので、それならば自前で作ってしまおう、というのが今回の記事の動機になります。

構成図


全体構成図

Docker がインストールされた Ubuntu サーバに、VPN サービスをインストールしたコンテナを用意し、スマホからコンテナ内 VPN に接続します。Docker を利用しているのは、基本的にホスト環境での様々な検証や変更を避けたいからです。

VPN ライブラリ - strongSwan -

あまり VPN の技術的なところは詳しくないのですが、ひとえに VPN といっても様々なプロトコルが存在します。やりたい事はスマホからの VPN 接続ですが、手持ちの Android 12 では IKEv2 プロトコルしかデフォルトで対応していませんでした。


Android 12 の VPN接続画面

オープンソースで有名な VPN プロジェクトとして、OpenVPNSoftEther VPN が挙げられますが、2022年10月時点ではどちらも IKEv2 プロトコルに対応していなかったため、strongSwan を利用して VPN 接続を試みます。

参考サイト

特に参考にしたサイトはここ(紹介元の日本語サイトはここ)。ほぼ丸パクリと言っても良いです。今回の構成において、微妙に分かりにくかった設定について補足するものとします。

事前準備

Ubuntu

確実な日本のIPアドレスを用意するには、自宅に設置したサーバを使うのが良いです。自宅の適当なパソコンに Ubuntu 22.04 をインストールします。

Docker

公式HP を参考にインストールします。

作成手順

VPN コンテナ作成

Image pull

Ubuntu 20.04 image を Docker Hub から pull します。

sudo docker pull ubuntu:20.04

Create docker network

独立した docker network にコンテナを置きたいので、次のようにネットワークを作成します。ここではサブネットを 172.18.1.XXX としています。

sudo docker network create --subnet=172.18.1.0/24 vpnnw

Container run

IKEv2 では UDP の 500, 4500 port を使用するので、-p オプションでポートを開けます。セキュリティ上、これらのポート番号は変えた方が良いと思われますが、ポート番号の設定箇所が分からなかったので断念します

ちなみに、後の作業で一部証明書の取得が必要なので、-v オプションで共有ディレクトリを設定した方が便利です。

sudo docker run -itd --privileged --name vpn --net=vpnnw --ip=172.18.1.2 -p 4500:4500/udp -p 500:500/udp  ubuntu:20.04 /bin/bash --login
sudo docker exec -it vpn /bin/bash

Module install

必要なモジュールをインストールします。

apt-get update
apt install -y strongswan strongswan-pki libcharon-extra-plugins libcharon-extauth-plugins libstrongswan-extra-plugins tzdata libtss2-tcti-tabrmd0 vim systemctl ufw

tzdata での日時設定は日本/東京を選択します。


tzdata の config. 赤アンダーライン箇所で、各数字を入力してEnterを押す

証明書の作成

VPN 接続で使用する各証明書の準備です。"VPN root CA" はCA証明書の名前なので、適宜変更してください。

mkdir -p ~/pki/{cacerts,certs,private}
chmod 700 ~/pki
ipsec pki --gen --type rsa --size 4096 --outform pem > ~/pki/private/ca-key.pem
ipsec pki --self --ca --lifetime 3650 --in ~/pki/private/ca-key.pem --type rsa --dn "CN=VPN root CA" --outform pem > ~/pki/cacerts/ca-cert.pem
pki --gen --type rsa --size 4096 --outform pem > ~/pki/private/server-key.pem

次のコード内で、PUBLIC IPアドレスを入力する必要があります。
“111.111.111.111" をインターネット側で見えている IPアドレスに置き換えて入力してください。

pki --pub --in ~/pki/private/server-key.pem --type rsa | pki --issue --lifetime 1825 \
    --cacert ~/pki/cacerts/ca-cert.pem \
    --cakey ~/pki/private/ca-key.pem \
    --dn "CN=111.111.111.111" --san @111.111.111.111 --san 111.111.111.111 \
    --flag serverAuth --flag ikeIntermediate --outform pem \
    >  ~/pki/certs/server-cert.pem

IPアドレスの調べ方は、例えばこのサイトです。82.102.28.37 がPUBLIC IPアドレスです。


PUBLIC IPアドレス

作成した証明書ファイルを、所定の場所にコピーします。

cp -r ~/pki/* /etc/ipsec.d/

VPN 設定ファイルの編集

設定ファイルを編集します。バックアップを取ってから編集します。
※vi コマンドで編集しますが、他ツールで編集しても問題ありません。

cp /etc/ipsec.conf /etc/ipsec.conf.original
vi /etc/ipsec.conf

線を引いた箇所を削除し、以降の設定を貼り付けします。"111.111.111.111″ は先ほどの PUBLIC IPアドレスに変更してください。
“10.10.10.0/24" は、VPN で割り当てられるIPアドレスです。変更しても問題ありませんが、以降で設定するIPルーティングの設定は、この割り当てを基準に記述します。

/etc/ipsec.conf
- config setup
-         # strictcrlpolicy=yes
-         # uniqueids = no

config setup
    charondebug="ike 1, knl 1, cfg 0"
    uniqueids=no

conn ikev2-vpn
    auto=add
    compress=no
    type=tunnel
    keyexchange=ikev2
    fragmentation=yes
    forceencaps=yes
    dpdaction=clear
    dpddelay=300s
    rekey=no
    left=%any
    leftid=111.111.111.111
    leftcert=server-cert.pem
    leftsendcert=always
    leftsubnet=0.0.0.0/0
    right=%any
    rightid=%any
    rightauth=eap-mschapv2
    rightsourceip=10.10.10.0/24
    rightdns=8.8.8.8,8.8.4.4
    rightsendcert=never
    eap_identity=%identity
    ike=chacha20poly1305-sha512-curve25519-prfsha512,aes256gcm16-sha384-prfsha384-ecp384,aes256-sha1-modp1024,aes128-sha1-modp1024,3des-sha1-modp1024!
    esp=chacha20poly1305-sha512,aes256gcm16-ecp384,aes256-sha256,aes256-sha1,3des-sha1!

接続ユーザの作成

パスワード認証でVPN接続するためのユーザ/パスワードの設定を行います。
※上記以外の接続方法については分かりません。

まずは設定ファイルを開きます。

vi /etc/ipsec.secrets

次のように追記します。user_id に使用したいユーザ名を、"password" にパスワードを適宜入力してください。
※このままでも、セキュリティ的には問題ありますが、接続は可能です。

/etc/ipsec.secrets
: RSA "server-key.pem"
user_id : EAP "password"

編集が終わったら、次のように権限を変更しておきます。

chmod 600 /etc/ipsec.secrets

UFW

これまでの設定で、VPN 接続自体は可能です。※サービスの起動が必要です(/etc/init.d/ipsec restart)
しかし、これだけでは 10.10.10.0/24 のネットワークから外に出られず、つまり肝心のインターネットに接続できません。インターネットに接続するためのIPフォワードの設定を行います。

まず、ufw を有効化して、使用するUDPポートへのアクセスを許可します。

ufw enable
ufw allow 500,4500/udp

次に、NATの設定と、IPフォワードの設定をします。
※ここの設定ファイルの内容はよく分かりません。

vi /etc/ufw/before.rules

次の箇所を追記してください。

/etc/ufw/before.rules
+ *nat
+ -A POSTROUTING -s 10.10.10.0/24 -o eth0 -m policy --pol ipsec --dir out -j ACCEPT
+ -A POSTROUTING -s 10.10.10.0/24 -o eth0 -j MASQUERADE
+ COMMIT

+ *mangle
+ -A FORWARD --match policy --pol ipsec --dir in -s 10.10.10.0/24 -o eth0 -p tcp -m tcp --tcp-flags SYN,RST SYN -m tcpmss --mss 1361:1536 -j TCPMSS --set-mss 1360
+ COMMIT

# Don't delete these required lines, otherwise there will be errors
*filter
:ufw-before-input - [0:0]
:ufw-before-output - [0:0]
:ufw-before-forward - [0:0]
:ufw-not-local - [0:0]
# End required lines

+ -A ufw-before-forward --match policy --pol ipsec --dir in --proto esp -s 10.10.10.0/24 -j ACCEPT
+ -A ufw-before-forward --match policy --pol ipsec --dir out --proto esp -d 10.10.10.0/24 -j ACCEPT

ufw を再起動して設定を反映します。

ufw disable
ufw enable

strongSwan のサービス起動

/etc/init.d/ipsec restart

ルーターの設定

今回の構成ではルーターがあるので、インターネット側からのUDPポートへの接続を許可してあげる必要があります。

こちらの設定はルーターのメーカーに依存するのでそれぞれで設定してください。
設定ページは、ほとんどの場合、ルーターのLAN側のゲートウェイアドレスにブラウザから接続すれば開くと思います。(今回の構成では、http://192.168.1.1

Android 12 からのVPN接続

クライアントとなるスマホ側での設定です。

CA証明書のインストール

VPN接続するために、CA証明書のインポートが必要になります。
コンテナ内にある、/etc/ipsec.d/cacerts/ca-cert.pem ファイルをどうにかしてスマホに持ってきます。※Google Drive内でも良いです。


Android 12 CA証明書インストール手順

VPN接続設定

次のように設定します。「名前」は何でも良いです。


Android 12 VPNプロファイル設定画面

VPN接続し、インターネットに接続できる事を確認してください。
また、IPアドレスが PUBLIC IPアドレスと同じになっていることを確認してください。

Windows 11 からのVPN接続

CA証明書のインポート

VPN接続するために、CA証明書のインポートが必要になります。
コンテナ内にある、/etc/ipsec.d/cacerts/ca-cert.pem ファイルをローカルに置き、次のようにファイル名を変更します。

ca-cert.pem ⇒ ca-cert.cer

ファイルをダブルクリックし、次のようにファイルを設置します。


Windows11 CA証明書インストール手順

VPN接続

「設定」⇒「ネットワークとインターネット」⇒「VPN」⇒「VPNを追加」から、次のように設定します。接続名は何でもかまいません。「サーバ名またはアドレス」に関しては、WAN側のアドレスに設定してください。

最後に

以上が、DockerコンテナにVPNサービスを構築し、スマホやWindows PCから接続する手順になります。

Discussion