※記事内に商品プロモーションを含む場合があります
8月に、Ubuntuに移行が完了しましたが
VPNで問題が発生しています。
【関連】VPSのサーバOSをCentOS8からUbuntuに移行
L2TP/IPsecで構築し、NAT traversalを設定しましたが
PCとiPhoneで同時接続してしばらくすると、接続が切れてしまいます。
ログを見ると、
xl2tpd[81723]: Can not find tunnel 81723 (refhim=0)
xl2tpd[81723]: network_thread: unable to find call or tunnel to handle packet.
と出て、トンネルが見つからなくなっています。
本当は、VPSと自宅サーバをVPNで繋げたいのですが、
VPNが不安定ではそれも実現しません。
iPhoneでL2TP/IPsec接続すると、スリープさせたり、1時間ぐらい経過すると
接続は途切れてしまうのが、難点でした。
紆余曲折の後、Wireguardを導入しましたが、
PC+iPhone+自宅サーバが同一のグローバルIPからアクセスしても
全然途切れません。
WireguardでVPNを構築
WireguardはP2Pで本来はサーバとクライアントとは言いませんが
便宜上、接続を受ける方をサーバ
iPhoneやPCなど、接続する方をクライアントとします。
Wireguardでは秘密鍵と対となる公開鍵で認証するので秘密鍵が漏れると
簡単に第三者がVPNにアクセス出来てしまいます。
公開鍵は秘密鍵から作れます。
鍵の管理には、十分に注意してください。
手順としては、
- 鍵の生成
- 設定ファイルを作成
- サービスの起動
で行います。
鍵の生成
rootでログインするか、sudoでsu -を実行しrootユーザーに切り替えます。
/etc/wireguard/にカレントディレクトリを変更します。
/etc/wireguard/はrootでないと表示されず
sudo cd /etc/wireguard/をroot以外で実行してもエラーになります。
sudo su -
cd /etc/wireguard/
このコマンドで、サーバの秘密鍵とサーバの公開鍵を生成します。
wg genkey | tee server_private.key | wg pubkey > server_public.key
このコマンドで、秘密鍵と公開鍵を一気に作成出来ます。
このコマンドは実行するたびに、ランダムな鍵が生成されます。
この場合、
サーバの秘密鍵が、 /etc/wireguard/server_private.key
サーバの公開鍵が、 /etc/wireguard/server_public.key
に保存されます。
鍵はこの様なランダムな文字列となっています。
6MibeBkof3hzPZF1WkxJ/Z/bNDWbmsS4Q9NFdoi0bm4=
クライアントの鍵もサーバと同じコマンドで生成できます。
wg genkey | tee peer1_private.key | wg pubkey > peer1_public.key
wg genkey | tee peer2_private.key | wg pubkey > peer2_public.key
こんな感じに、一部変更してください。
セキュリティ強度を上げるため、今回は事前共有鍵も設定するので
事前共有鍵も生成します。
wg genpsk | tee peer1_psk.key
生成した鍵は、そのまま置いておく場合は、パーミッションを
600にしておきます。
chmod 600 *.key
生成した鍵は、catコマンドで確認できますし、
各設定が完了したら、消しても動作には支障しません。
サーバ側の設定ファイルを作成
今回の設定ファイルは、wg0.conf(/etc/wireguard/wg0.conf)とします。
このwg0がそのまま、インターフェイス名になります。
[Interface]
PrivateKey = 【サーバの秘密鍵】
Address = 10.0.0.1
ListenPort = 51820
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o ens3 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o ens3 -j MASQUERADE
[Peer]
## Peer1 クライアント用設定
PublicKey = 【Peer1の公開鍵】
PresharedKey = 【Peer1の事前共有鍵】
AllowedIPs = 10.0.0.2/32
[Peer]
## Peer2 クライアント用設定
PublicKey = 【Peer2の公開鍵】
PresharedKey = 【Peer2の事前共有鍵】
AllowedIPs = 10.0.0.3/32
項目ごとに説明します。
Address はVPNのIPアドレスを指定します。
10.0.0.1以外にも、192.168.2.1なども使えますが
自宅のLANとかぶらない様に設定します。
ListenPort は接続を待ち受けるポートを指定します。
Wireguardでは、51820が多く使われています。
PostUp VPNからインターネットへ行くパケットを
転送する設定を行っています、Wireguard起動時に適用されます。
その中に、ens3とありますが、サーバによって異なるので
書き換えてください(CentOSではeth0が多い)。
ip a
で確認できます。
PostDown Wireguard終了時に、PostUpで設定を
削除しています。
PresharedKeyは事前共有鍵を使わない場合は不要です。
AllowedIPsは各クライアントのIPアドレスです。
クライアント側の設定と一致しないと動作しません。
IPフォワーディングの設定
Linuxのデフォルト設定では異なるネットワーク間の転送を
行わない設定になっています。
/etc/sysctl.confにある
net.ipv4.ip_forward=0
↓
net.ipv4.ip_forward=1
sudo vi /etc/sysctl.confなどで変更し、
sudo sysctl -p で設定を反映させます。
この設定を行わないと、VPNからインターネットへの
接続ができません。
サービスの起動
今回作った、wg0を起動するには、このコマンドを実行します。
wg-quick up wg0
終了する場合は、このコマンドを実行します。
wg-quick down wg0
調べた所、再読み込みの機能は無さそうなので
クライアントを追加したなど、設定ファイルを変更した場合は
wg0を終了させてから、起動させる必要があります。
システム起動時から、自動起動する場合はこのコマンドを実行します。
systemctl enable wg-quick@wg0
これで、接続待ちの状態ですが、ufwなどのファイアウォールで
ポート開放しておく必要があります。
サービスの起動前に、接続に使用するポート開放を行います。
ufwの場合以下のコマンドでポート開放できます。
ufw allow 51820
クライアント側の設定ファイルを作る
サーバ側に、鍵があるので接続に必要な設定ファイルを作ります。
基本的にはこの様になっています。
[Interface]
PrivateKey = 【Peer1の秘密鍵】
Address = 10.0.0.3/32
[Peer]
PublicKey = 【サーバ公開鍵】
PresharedKey =【Peer1の事前共有鍵】
AllowedIPs = 10.0.0.0/24, 【サーバのグローバルIP】/32
Endpoint = サーバ:51820
PersistentKeepalive = 25
項目ごとに説明します。
Address はサーバで設定したIPアドレスを設定します。
Endpoint はサーバとポート(ListenPort)を指定します。
PresharedKeyは事前共有鍵を使わない場合は不要です。
PersistentKeepalive はこの場合25秒に1回適当な通信をサーバと行う事で
接続を維持します。
NAT下から接続する場合は、この設定が無いと接続が切れる様です。
Windows,iOS両方ともデフォルトではWireguardに対応していないので
アプリをインストールしてVPNを使用します。
WindowsならSSHからコピペで設定を移行しました。
AllowedIPs
AllowedIPsはサーバ側と、働きが異なります。
クライアント側で設定するAllowedIPsが
どのIPアドレス範囲を、VPNで通信するかを設定します。
パソコンや、自宅サーバなど
VPNのアドレス以外VPNを使いたくない場合は上と同じ様に設定します。
私の場合は、サーバと通信する場合は、VPNを使いたいので、サーバIPも入れています。
iPhoneなどで、すべての通信をVPN経由でしたい場合は
この様に設定します。
AllowedIPs = 0.0.0.0/0
DNS = 8.8.8.8
すべての通信をVPN経由で流しているのでプロバイダやキャリアの
DNSサーバが使えなくなります。
AllowedIPs = 0.0.0.0/0にする場合は、DNSでDNSサーバの設定
が必要です。
8.8.8.8はGoogle Public DNSのIPアドレスです。
QRコードで設定を転送する
パソコンだったら、SSH経由でも良いですが、問題はiPhoneなどスマホです。
上の設定を適当なテキストファイルに保存して以下のコマンドで
QRコードを表示させます。
qrencode -t ansi -r /etc/wireguard/tekitou.txt
設定ファイルのサイズによっては、全体を表示しきれないので
Teratermでは設定⇢フォントでフォントサイズを小さくして
QRコード全体を表示しました。
表示したQRコードはスマホのWireGuardアプリから
右上の+をタップして、QRコードから作成で、設定を読み込むことができます。
QRコード作成で使用したテキストファイルは使用予定がなければ
削除しておきます。
VPNでアクセスできているかの確認
Wireguardの接続ができているかは、
設定ソフトや、sudo wgコマンドで確認出来ます。
実際にインターネットへの接続がVPNサーバを経由しているかは
分かりません。
VPN経由でアクセス出来ているかは、アクセス情報確認ツールなどに
アクセスしてIPアドレスがサーバのIPアドレスなら
VPNでアクセスできています。
443番ポートをApacheと共存させる
一部の公衆Wifiではメジャーなポート(53/80/443)以外のポートへの
接続ができない場合があり、Apacheの443ポートと共存させるが良いと思います。
SSHとSSLを分けるsslhでもWireguard対応可能でしたが
アクセス元が全て127.0.0.1となり使えませんでした。
いろいろ調べたiptablesでWireguardのパケットを振り分けて
ApacheとWireguardを共存できる方法が見つかりました。
【参考】クラウドから撤退して自前サーバに自分でwebアプリを建てるおはなし
Wireguardのパケットは識別できるので、
443ポートに届いたパケットの内Wireguardのパケットのみを
51820ポートに転送します。
iptables -t nat -I PREROUTING -p udp -m udp --dport 443 -m string --algo kmp --from 28 --to 31 --hex-string '|01000000|' -j DNAT --to-destination 127.0.0.1:51820
参考元のコマンドではiptables -t nat -A となっていますが、
このままでは動作しませんでした。
ufwは、バックエンドではiptablesで動いているので
iptables -t nat -Iで設定を上書きする様にしたら動作しました。
このままだと、システム終了時に設定が消えてしまうので
wg0.confに設定を追加します。
PostUp = iptables -t nat -I PREROUTING -p udp -m udp --dport 443 -m string --algo kmp --from 28 --to 31 --hex-string '|01000000|' -j DNAT --to-destination 127.0.0.1:51820
PostDown = iptables -t nat -D PREROUTING -p udp -m udp --dport 443 -m string --algo kmp --from 28 --to 31 --hex-string '|01000000|' -j DNAT --to-destination 127.0.0.1:51820
この設定を追加することで、Wireguard起動時に転送設定が反映され
Wireguard終了時には転送設定が削除されます。