公衆Wi-Fiを使うときの暗号化と、そもそもVPNが中で何をしているのかを理解したくて、商用VPNを契約する代わりにAWSのEC2にWireGuardを自前で建ててみました。
構築自体は30分ほどで終わります。設定ファイルも15行程度で、OpenVPNを触ったことがある人ほど拍子抜けすると思います。
ただ、そのあとMacとスマホとテレビの3台を繋いで一週間ほど動かしてみたら、手順そのものより「どのクラウドを選ぶか」と「何に課金されているのか」のほうで学ぶことが多かったです。この記事はそのあたりを中心にまとめます。
クラウド選びでいきなり詰まった
最初はOracle Cloud InfrastructureのAlways Free枠を使うつもりでした。永年無料で4 OCPU / 24GBのARMインスタンスが使えるので、VPN用途には過剰なくらいです。
ところが、サインアップのホームリージョン選択に、自分が使いたかったリージョンが出てきませんでした。ASIA-PACIFICのセクションを最後までスクロールしても無い。アルファベット順で並んでいるはずの位置がまるごと抜けています。
容量が逼迫しているリージョンは無料枠の受付自体を止めているようで、これは時期によって変わるようです。
問題は、OCIのAlways Freeインスタンスは原則ホームリージョンにしか作れず、しかもホームリージョンはサインアップ後に変更できないことです。「とりあえず契約してから考える」ができません。
一応、有料プランにアップグレードしてサービスリミット申請を出せばリージョンを追加できますが、申請に数日かかることがあるようで、無料で済ませたかった当初の目的とは噛み合いませんでした。
OCIのAlways Freeを狙うなら、契約前に目的のリージョンが選択肢に出るか確認したほうがいいです。自分はここで方針転換しました。
他の選択肢を調べた結果
代わりの候補を一通り調べました。2026年8月時点の状況です。
AWSは2025年7月から新規アカウントの無料枠がクレジット制に変わっていますが、月100GBのアウトバウンド無料枠は全アカウント共通で残っています。個人利用のVPNならこの枠に収まります。
GCPは300ドル/90日のトライアルが健在で、e2-microが0.0107ドル/時。今回くらいの使い方なら完全にクレジット内に収まります。新規で始めるならこれが一番手軽だと思います。
Azureは200ドル/30日のクレジットがありますが、無料アカウントだとリージョンによってデプロイ制限がかかるという報告が複数あり、狙ったリージョンに立てられない可能性があったので外しました。
Vultrは無料枠がない代わりに時間課金で、一晩使って数円という世界です。使い捨て前提ならこれが一番安いです。
自分は昔作ったAWSアカウントがあったので、AWSにしました。
構築
鍵を作る
ssh-keygen -t ed25519 -f ~/.ssh/vpn_key -C "vpn-server"
EC2を起動する
AMIはUbuntu 24.04か26.04のLTS。WireGuardがカーネルに入っているので追加のビルドが要りません。
インスタンスタイプはt3.microかt4g.microで十分です。VPNはCPUをほとんど使わないので、あとで測ったら1 vCPUで250Mbps出ました。
パブリックIPの自動割り当てを有効にするのを忘れないでください。ここが無効だと外から繋がりません。
セキュリティグループは2つ開けます。
SSH(TCP 22)は自分のIPだけに絞ります。WireGuard(UDP 51820)は0.0.0.0/0で全開放が必要です。スマホがモバイル回線から繋ぐので、送信元を固定できません。
全開放に抵抗があるかもしれませんが、WireGuardは正しい鍵を持たない相手のパケットに一切応答しない設計です。ポートスキャンしても閉じているようにしか見えません。TCPのサービスを晒すのとは意味が違います。
鍵ペアを生成する
sudo -i
umask 077
mkdir -p /etc/wireguard/keys && cd /etc/wireguard/keys
for n in server mac phone tv; do
wg genkey | tee $n.key | wg pubkey > $n.pub
done
umask 077 を先に打つのを忘れないでください。秘密鍵がワールドリーダブルだと wg-quick が起動時に警告を出します。
サーバーとクライアントでそれぞれ鍵ペアを作って、互いの公開鍵だけを交換します。秘密鍵は生成した場所から動かしません。
サーバー設定
/etc/wireguard/wg0.conf です。
[Interface]
Address = 10.8.0.1/24
ListenPort = 51820
PrivateKey = <server.keyの中身>
PostUp = iptables -t nat -A POSTROUTING -o ens5 -j MASQUERADE; iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -j ACCEPT
PostDown = iptables -t nat -D POSTROUTING -o ens5 -j MASQUERADE; iptables -D FORWARD -i wg0 -j ACCEPT; iptables -D FORWARD -o wg0 -j ACCEPT
[Peer]
PublicKey = <mac.pubの中身>
AllowedIPs = 10.8.0.2/32
Address はVPNの内側だけで使うプライベートネットワークです。サーバーが .1、クライアントに .2 以降を配ります。
PostUp のMASQUERADEが、VPN内部のアドレスから来たパケットの送信元をサーバーのグローバルIPに書き換えるNAT設定です。これがないとパケットは外に出ていくものの戻ってこられません。
-o ens5 の部分は環境で変わります。ip route の default via の行に出るデバイス名を見てください。AWSのUbuntuは ens5 ですが、他だと eth0 や enp0s6 のこともあります。ここを間違えると、設定は通るのに通信できないという分かりにくい状態になります。
IPフォワーディングを有効にする
echo "net.ipv4.ip_forward=1" | sudo tee /etc/sysctl.d/99-wireguard.conf
sudo sysctl -p /etc/sysctl.d/99-wireguard.conf
Linuxはデフォルトで「自分宛でないパケットは転送しない」設定になっています。VPNサーバーはまさにその転送をする役なので、明示的に有効にします。
ハンドシェイクは成功しているのに通信できない、というトラブルの原因はだいたいこれかNATのインターフェース名です。
起動
sudo systemctl enable --now wg-quick@wg0
sudo wg show
enable を付けておけばインスタンス再起動後も自動で上がります。
クライアント側の設定
[Interface]
PrivateKey = <クライアントの秘密鍵>
Address = 10.8.0.2/32
DNS = 1.1.1.1
MTU = 1420
[Peer]
PublicKey = <server.pubの中身>
Endpoint = <サーバーのグローバルIP>:51820
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25
4行だけ補足します。
AllowedIPs はサーバー側とクライアント側で意味が変わるので、ここが一番混乱しました。サーバー側は「このpeerから来ることを許可する送信元」ですが、クライアント側は「どの宛先の通信をトンネルに流すか」です。0.0.0.0/0 は全部流す設定になります。
DNS を書かないと、通信はVPN経由なのに名前解決だけ手元のISPのDNSに行きます。VPNを使う意味が半分なくなるので必ず指定します。
MTU は、WireGuardがカプセル化でヘッダを足すぶん1500から下げます。1420で不調なら1380まで下げます。「繋がるけど特定のサイトだけ開かない」はだいたいこれです。
PersistentKeepalive は、NATの裏にいるクライアントが25秒ごとに空パケットを送ってNATテーブルのエントリを維持するためのものです。スマホやルーター配下では実質必須です。
スマホはQRコードで渡す
sudo qrencode -t ansiutf8 < /etc/wireguard/clients/phone.conf
-t ansiutf8 を使うとターミナルにQRが直接描画されるので、ファイルを転送せずにその場でスキャンできます。
当然ですが、このQRコードには秘密鍵がそのまま入っています。画面共有やSlackへの貼り付けは、鍵をそのまま渡すのと同じです。
テレビにはカメラがない
Android TV(自分の場合はSony BRAVIA)にもWireGuardの公式アプリが入ります。ただしテレビにカメラは付いていないので、QRコードが使えません。
USBメモリ経由が確実でした。
- USBメモリ(FAT32かexFAT)に
.confをコピーする - テレビのUSBポートに挿す
- WireGuardアプリ →「+」→「ファイル、アーカイブからインポート」→ USB内の
.confを選ぶ
ファイル選択画面にUSBが出てこない場合は、プリインストールされているファイルマネージャ(File Commanderなど)を一度開いてUSBを認識させてから戻ると見えるようになります。
ちなみに、MacからテレビにミラーリングしてもDRMのかかった動画は映像が真っ黒になります。最初これをVPNのせいかと思って調べましたが、HDCPの仕様で、VPNとは何の関係もありませんでした。テレビ側に直接VPNを入れればミラーリング自体が不要になります。
peerの追加はサーバー再起動なしでできる
あとからクライアントを足すとき、wg0.conf に [Peer] を追記してから次を実行します。
sudo wg syncconf wg0 <(wg-quick strip wg0)
systemctl restart と違って、既存の接続を切らずに反映できます。wg-quick strip は設定ファイルから PostUp など wg コマンドが解釈できない行を落としてくれるユーティリティです。
踏んだ落とし穴
VPNをオンにするとSSHできなくなる
これが一番間抜けでした。
セキュリティグループでSSHを自宅IPだけに絞っていたのですが、VPNをオンにすると自分の通信もトンネルを通るので、SSHの送信元がVPN内部のアドレスになります。当然、自宅IPの許可には引っかかりません。
VPN接続中はサーバーのVPN内部アドレス宛にSSHすれば通ります。
ssh -i ~/.ssh/vpn_key ubuntu@10.8.0.1
言われてみれば当たり前なのですが、「さっきまで繋がっていたSSHがタイムアウトする」と一瞬焦ります。
OSのファイアウォールが別にいる場合がある
AWSのUbuntu公式AMIは素の状態なので不要でしたが、OCIの提供イメージなどはOS側のiptablesに最初からREJECTルールが入っています。クラウド側のセキュリティグループを開けただけでは通りません。
繋がらないときは sudo iptables -L -n も見る価値があります。
コストの話
一番勉強になったのは、ネットワークではなく課金体系のほうでした。
AWSの料金は独立した2つのメーターで動いています。
1つはインスタンスの稼働費です。t3.microとパブリックIPv4で約0.018ドル/時。通信量がゼロでも、起動している限り課金されます。24時間つけっぱなしだと月13ドル、日本円で2,000円くらいです。
もう1つがデータ転送量で、こちらは月100GBまで無料、超過分が約0.09〜0.13ドル/GBです。
つまり自前VPNのコストは「どれだけ使ったか」ではなく「どれだけ置いてあるか」で決まります。個人利用なら通信量は無料枠に収まるので、実質的に稼働時間だけが効きます。
なので、使うときだけ起動して終わったら停止するのが正解です。停止中はEBSの0.9ドル/月程度まで落ちます。ただしパブリックIPが変わるので、全クライアントの Endpoint を書き換えることになります。固定したいならElastic IPで月3.6ドルです。
自分は3台繋いでいるので毎回3箇所書き換えることになり、正直これが一番面倒でした。頻繁に使うならElastic IPを付けたほうが精神衛生上いいと思います。
商用VPNに勝てない理由が数字で分かった
このegress単価が、自前VPNを人に提供する形にできない理由でもあります。
AWSのegressは従量課金で約0.1ドル/GB。一方、商用VPN事業者が使っているのは帯域無制限の専用サーバーで、1Gbpsの回線が月150ドル程度です。ざっくり0.005ドル/GBを下回ります。
20倍から40倍の差があります。
商用VPNの実売価格は月3〜4ドルですが、AWSで同じ使い方をすると1ユーザーあたりの通信費だけで月10ドルかかります。原価が売値を超えるので、ハイパースケーラーの上で消費者向けVPNを成立させるのは構造的に無理です。
「自分ひとりが無料枠の中で使う」がこの構成のスイートスポットで、そこから一歩でも外に出た瞬間に成立しなくなる、というのが分かったのが個人的には一番の収穫でした。
まとめ
- 構築自体は30分。詰まるのはIPフォワーディング、NATのインターフェース名、MTU、DNSのどれか
- クラウドの無料枠は条件が頻繁に変わる。OCIはリージョンが選択肢に出るかを契約前に確認する
- コストは通信量より起動時間で決まる。使うときだけ起動する運用が前提
- VPNオンの状態だとSSHの送信元が変わる。内部アドレス宛に繋ぐ
- egress単価の差が大きすぎて、自前VPNは自分用に閉じているうちが一番コスパがいい
なお、VPNを自分で使うぶんには何の問題もありませんが、他人に提供すると電気通信事業法の届出が必要になります(有償なら特に)。届出自体は無料で即日ですが、通信の秘密の遵守義務や発信者情報開示請求への対応義務が付いてくるので、収益化を考えるなら先に調べたほうがいいです。
VPNが中で何をしているのかを理解する題材としては、かなり良かったです。普段アプリを書いているときには完全に隠れているNATやルーティングやMTUを、動かないという形で全部踏むことになります。