2026年6月5日
2026年6月5日
L2TP/IPsec の VPN サーバーを構築する方法|strongSwan と xl2tpd の設定・ファイアウォールのポート・Windows / macOS / iOS からの接続
L2TP/IPsec の VPN サーバーは、strongSwan で IPsec(事前共有鍵、トランスポートモード)を張り、その中で xl2tpd が L2TP トンネルを受け、PPP でクライアントに IP アドレスを配る、という 3 層の組み合わせで動きます。設定ファイルは ipsec.conf / ipsec.secrets、xl2tpd.conf、options.xl2tpd、chap-secrets の 5 つで、迷いやすいのはファイアウォールと NAT です。
結論を先にまとめます。
- L2TP/IPsec の利点は、Windows・macOS・iOS・Android の標準機能で追加ソフトなしに接続できることです。会社の WordPress 管理画面や SSH を「VPN 経由だけ許可」にする入口として今も使われています。
- 必要なポートは UDP 500(IKE)、UDP 4500(NAT-T)、ESP(プロトコル 50)です。L2TP の UDP 1701 は IPsec の中を通るので、外部に直接開ける必要はありません。
- 新しく作るなら、IKEv2(strongSwan 単体)や WireGuard の方が構成が簡単で速いです。L2TP/IPsec を選ぶ理由が「古い機器や標準クライアントで事前共有鍵だけで入りたい」である場合に限ります。
- つながらないときの切り分け(エラー 789 / 809、NAT 越えのレジストリ)は別記事 L2TP/IPsec の VPN がつながらないときの切り分け にまとめています。
L2TP/IPsec の仕組み
| 層 | 担当 | 役割 | 設定ファイル |
|---|---|---|---|
| IPsec | strongSwan | 事前共有鍵(PSK)で IKEv1 の交渉をし、ESP で暗号化する。L2TP の UDP 1701 だけをトランスポートモードで守る | /etc/ipsec.conf、/etc/ipsec.secrets |
| L2TP | xl2tpd | IPsec の中で L2TP トンネルを受け、PPP セッションを起こす | /etc/xl2tpd/xl2tpd.conf |
| PPP | pppd | ユーザー名・パスワード(MS-CHAPv2)の認証、クライアントへの IP アドレスと DNS の配布 | /etc/ppp/options.xl2tpd、/etc/ppp/chap-secrets |
クライアントは「IPsec の事前共有鍵」と「PPP のユーザー名・パスワード」の 2 段で認証されます。事前共有鍵は全員で共通、ユーザー名・パスワードは人ごとに分ける、という運用になります。
手順 1: パッケージを入れる
Ubuntu 22.04 / 24.04、Debian 12 を前提にします。
sudo apt update
sudo apt install strongswan xl2tpd ppp
Ubuntu の strongswan パッケージは ipsec コマンドと /etc/ipsec.conf を使う構成(starter)で動きます。サービス名は strongswan-starter です(環境によっては strongswan)。
手順 2: IPsec(strongSwan)を設定する
/etc/ipsec.conf を次のように書きます。既定の内容は退避しておきます。
config setup
uniqueids=no
conn L2TP-PSK
keyexchange=ikev1
authby=secret
type=transport
left=%defaultroute
leftprotoport=17/1701
right=%any
rightprotoport=17/%any
ike=aes256-sha1-modp2048,aes256-sha256-modp2048,aes128-sha1-modp1024!
esp=aes256-sha1,aes256-sha256,aes128-sha1!
rekey=no
forceencaps=yes
dpdaction=clear
dpddelay=30s
auto=add
type=transport: L2TP/IPsec はトンネルモードではなくトランスポートモードで、UDP 1701 のパケットだけを守ります。uniqueids=no: 同じ事前共有鍵で複数台が同時に接続するために必要です。forceencaps=yes: NAT の内側のクライアント(家庭やモバイル回線はほぼ該当)のため、常に UDP 4500 でカプセル化します。ike=/esp=の候補は、Windows・macOS・iOS の標準クライアントが提案する組み合わせを含めています。modp1024は古い方式ですが、古い端末との互換性のために残しています。不要なら外してください。
事前共有鍵は /etc/ipsec.secrets に書きます。長いランダムな文字列を使います。
%any %any : PSK "ここに長いランダムな事前共有鍵"
sudo chmod 600 /etc/ipsec.secrets
sudo systemctl enable --now strongswan-starter
sudo ipsec statusall
手順 3: L2TP(xl2tpd)と PPP を設定する
/etc/xl2tpd/xl2tpd.conf を次のようにします。ip range はクライアントに配る私的なアドレス、local ip はサーバー側のアドレスで、サーバーの LAN と重ならない範囲にします。
[global]
port = 1701
ipsec saref = no
[lns default]
ip range = 10.99.0.10-10.99.0.200
local ip = 10.99.0.1
require chap = yes
refuse pap = yes
require authentication = yes
name = l2tpd
ppp debug = no
pppoptfile = /etc/ppp/options.xl2tpd
length bit = yes
/etc/ppp/options.xl2tpd に PPP の設定を書きます。DNS は社内の DNS か、公開の DNS を指定します。
ipcp-accept-local
ipcp-accept-remote
ms-dns 10.99.0.1
noccp
auth
mtu 1280
mru 1280
proxyarp
lcp-echo-failure 4
lcp-echo-interval 30
connect-delay 5000
refuse-pap
refuse-chap
refuse-mschap
require-mschap-v2
ms-dns にサーバー自身を書く場合は、サーバーで DNS(unbound など)を動かしている必要があります。動かしていなければ、社内の DNS や公開 DNS の IP にします。
ユーザーは /etc/ppp/chap-secrets に 1 行ずつ書きます。形式は「ユーザー名 サーバー名 パスワード 割り当て IP」で、IP は * で自動割り当てです。
# client server secret IP addresses
taro l2tpd "ユーザーごとの長いパスワード" *
sudo chmod 600 /etc/ppp/chap-secrets
sudo systemctl enable --now xl2tpd
手順 4: IP 転送・NAT・ファイアウォール
VPN 経由で社内やインターネットに出るには、カーネルの IP 転送と NAT(マスカレード)が必要です。
# IP 転送を有効にする
echo "net.ipv4.ip_forward = 1" | sudo tee /etc/sysctl.d/99-vpn.conf
sudo sysctl --system
ufw を使っている場合の例です。外向きのインターフェース名(eth0 等)は環境に合わせます。
# 受け入れるポート
sudo ufw allow 500/udp
sudo ufw allow 4500/udp
# ESP(プロトコル 50)
sudo ufw allow proto esp from any to any
/etc/ufw/before.rules の先頭(*filter より前)に NAT の節を足します。
*nat
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -s 10.99.0.0/24 -o eth0 -j MASQUERADE
COMMIT
/etc/default/ufw の DEFAULT_FORWARD_POLICY を ACCEPT にしてから sudo ufw reload します。firewalld の環境では --add-service=ipsec(UDP 500 / 4500 と ESP)と --add-masquerade で同等の設定になります。
クラウド(AWS のセキュリティグループ、Azure の NSG など)では、OS のファイアウォールとは別に、クラウド側でも UDP 500 / 4500 を許可します。ESP は NAT 越え(UDP 4500 でのカプセル化)が使われる限り不要なことが多いですが、サーバーがパブリック IP を直接持つ構成では ESP も通します。
手順 5: クライアントから接続する
OS 標準のクライアントで入力する項目は次のとおりです。
| 項目 | Windows 11 | macOS | iOS / iPadOS |
|---|---|---|---|
| 設定の場所 | 設定 → ネットワークとインターネット → VPN → VPN 接続を追加 | システム設定 → VPN → VPN 構成を追加 → L2TP over IPSec | 設定 → 一般 → VPN とデバイス管理 → VPN 構成を追加 → L2TP |
| サーバー | サーバーのホスト名または IP | 同左 | 同左 |
| VPN の種類 | 「事前共有キーを使った L2TP/IPsec」 | (L2TP over IPSec を選択) | (L2TP を選択) |
| 事前共有鍵 | 「事前共有キー」欄 | 認証設定 → 共有シークレット | シークレット |
| ユーザー名・パスワード | サインイン情報 | アカウント名・パスワード | アカウント・パスワード |
Windows で、サーバーが NAT の内側(クラウドの多くはこの構成)にあるときは、クライアント側のレジストリ AssumeUDPEncapsulationContextOnSendRule を 2 にして再起動しないと接続できません。この点と、エラー番号ごとの切り分けは L2TP/IPsec の VPN がつながらないときの切り分け に書いています。
接続できたら、サーバー側で確認します。
sudo ipsec statusall # ESTABLISHED と INSTALLED が出る
sudo journalctl -u xl2tpd -n 30
ip addr show ppp0 # PPP のインターフェースができている
WordPress の観点: 管理画面と SSH を VPN 経由だけにする
VPN を作る目的の多くは、「WordPress の管理画面と SSH を VPN からだけ開けたい」です。VPN が動いたら、Nginx で wp-login.php と /wp-admin/ を VPN のアドレス範囲だけに許可します。
location ~ ^/(wp-login\.php|wp-admin/) {
allow 10.99.0.0/24; # VPN クライアント
allow 203.0.113.10; # 事務所の固定 IP
deny all;
# 以下は通常の PHP の処理
}
location = /wp-admin/admin-ajax.php {
allow all; # 訪問者向けの機能が使う
}
SSH も sshd_config の AllowUsers や ufw で VPN の範囲に絞ります。国別の制限と組み合わせる方法は Nginx の GeoIP2 で国別にアクセスを制限する方法 に、パスワード認証を追加で掛ける方法は Nginx でベーシック認証を設定する方法 にまとめています。
なお、Cloudflare などの CDN を前に置いているサイトでは、オリジンへの直接アクセスを CDN の IP だけに絞っているはずです。その場合は、VPN からも CDN 経由でアクセスすることになるので、Cloudflare 側の WAF ルールで VPN の出口 IP を許可します。
よくある質問
今から L2TP/IPsec を選ぶ理由はありますか
標準クライアントだけで、事前共有鍵とユーザー名・パスワードで入れることが理由になります。ただし IKEv2(strongSwan で証明書または EAP-MSCHAPv2)も Windows 7 以降・macOS・iOS の標準クライアントで使え、NAT 越えやモバイルでの再接続(MOBIKE)が L2TP/IPsec より素直です。WireGuard は専用アプリが要りますが、設定が短く速度も出ます。新規に作るなら、まず IKEv2 か WireGuard を検討し、古い機器の都合があるときだけ L2TP/IPsec にする、という順番を勧めます。
事前共有鍵は全員同じでよいのですか
L2TP/IPsec の仕組み上、事前共有鍵はサーバーに 1 つ(%any %any)で全員共通になります。人ごとに分けるのは PPP のユーザー名・パスワードです。退職者が出たら chap-secrets の行を消し、事前共有鍵も定期的に変えます。
Android からは接続できますか
Android は 12 以降で標準の VPN クライアントから L2TP/IPsec の選択肢が外されました。Android の端末が多い場合は、IKEv2 か WireGuard の方を用意する方が現実的です。
クライアントは IP を配られたのにインターネットに出られません
IP 転送(net.ipv4.ip_forward)、NAT のマスカレード、ufw の DEFAULT_FORWARD_POLICY のいずれかが抜けている典型例です。sudo sysctl net.ipv4.ip_forward、sudo iptables -t nat -L POSTROUTING -n、/etc/default/ufw の順に確かめます。
まとめ
- L2TP/IPsec の VPN サーバーは strongSwan(IPsec、PSK、トランスポートモード)+ xl2tpd(L2TP)+ PPP(MS-CHAPv2 認証と IP 配布)の 3 層で、設定ファイルは 5 つです。
- 外部に開けるのは UDP 500 / 4500 と ESP で、IP 転送と NAT を忘れると「つながるが出られない」状態になります。
- 新規なら IKEv2 か WireGuard を先に検討し、L2TP/IPsec は標準クライアントと事前共有鍵が条件のときに選びます。
関連記事
- L2TP/IPsec の VPN がつながらないときの切り分け|エラー 789 / 809、NAT 越え、PSK 不一致、ログの見方
- Nginx でベーシック認証を設定する方法
- Nginx の GeoIP2 で国別にアクセスを制限する方法
参考: strongSwan Documentation、strongSwan – Windows Clients、xl2tpd(GitHub)、Microsoft Learn – Configure L2TP/IPsec server behind NAT-T device
更新履歴: 2026-11-09 全面改訂(定型文の記事を、strongSwan と xl2tpd の設定ファイル・ファイアウォール・クライアント設定・WordPress 管理画面の VPN 限定の手順に置き換え。切り分けは別記事に分離)。この記事はワードプレス博士(ライトセンド株式会社)が運営しています。