2026年10月3日
2026年10月3日
IPsecとstrongSwanでサイト間VPNを構築する方法(swanctl.conf版)
strongSwan は Linux で IPsec(IKEv2)VPN を組むための定番ソフトウェアで、現在の推奨設定方式は swanctl.conf と swanctl コマンドです。この記事では、2台のサーバー(例: Webサーバーと別拠点のDBサーバー)の間をIPsecで結ぶサイト間VPNを、インストールから疎通確認、つまずきやすいファイアウォールとNATの設定まで順に説明します。
この記事で作る構成と前提
例として、次の2拠点を結びます。IPアドレスはドキュメント用の例示アドレスなので、自分の環境に置き換えてください。
- 拠点A: グローバルIP
203.0.113.10、内部ネットワーク10.1.0.0/24 - 拠点B: グローバルIP
198.51.100.20、内部ネットワーク10.2.0.0/24
OSは Ubuntu / Debian 系を想定しています。認証は手順を短くするため事前共有鍵(PSK)を使いますが、拠点が増える場合や外出先の端末をつなぐリモートアクセス用途では、証明書認証のほうが管理しやすく安全です。PSKを使うなら、推測できない長いランダム値にしてください。
なお、2台のサーバー間を暗号化したいだけで、相手側の機器にIPsecが要求されていないなら、WireGuard のほうが設定は簡単です。IPsecを選ぶ理由は「相手がルーターやクラウドのVPNゲートウェイでIPsecしか話せない」「既存の社内規程でIPsec/IKEv2が指定されている」といった場面が中心です。
ipsec.conf ではなく swanctl.conf を使う理由
古い解説記事の多くは /etc/ipsec.conf と ipsec コマンド(stroke方式)を使っています。strongSwan はこの方式を非推奨としており、新しいバージョンでは既定で無効、あるいはパッケージから外れていることがあります(2026年10月現在)。これから構築するなら、/etc/swanctl/swanctl.conf に設定を書き、swanctl で読み込む vici 方式を選ぶほうが長く使えます。
Ubuntu では次のパッケージを入れます。パッケージ名やサービス名はディストリビューションとバージョンで異なることがあるので、インストール後に systemctl list-units | grep -i strongswan で実際のサービス名を確認してください。
sudo apt update
sudo apt install strongswan-swanctl charon-systemd
systemctl list-units | grep -i strongswan
拠点Aの設定
拠点Aの /etc/swanctl/swanctl.conf に、接続(IKE SA)と子SA(実際に暗号化するネットワークの組み合わせ)を書きます。
connections {
site-a-to-b {
version = 2
local_addrs = 203.0.113.10
remote_addrs = 198.51.100.20
proposals = aes256gcm16-prfsha384-ecp384
dpd_delay = 30s
local {
auth = psk
id = site-a
}
remote {
auth = psk
id = site-b
}
children {
net-a-b {
local_ts = 10.1.0.0/24
remote_ts = 10.2.0.0/24
esp_proposals = aes256gcm16-ecp384
start_action = start
dpd_action = restart
}
}
}
}
secrets {
ike-site-ab {
id-a = site-a
id-b = site-b
secret = "your-long-random-psk"
}
}
ポイントは次のとおりです。
proposalsはIKE(鍵交換)の暗号方式、esp_proposalsは実データの暗号方式です。両拠点で一致する組み合わせが一つも無いとNO_PROPOSAL_CHOSENで失敗します。相手がクラウドのVPNゲートウェイや市販ルーターの場合は、相手側が対応する方式の一覧を先に確認してください。local_ts/remote_tsは暗号化の対象にする通信の範囲です。ここが相手側の設定と逆向きで一致していないとTS_UNACCEPTABLEになります。start_action = startは設定の読み込み時に接続を開始します。通信が発生したときだけ張りたい場合はtrapを使います。- PSKは
openssl rand -base64 32などで生成した値を使い、設定ファイルの権限は root だけが読める状態に保ちます。Gitなどにコミットしないでください。
拠点Bの設定
拠点Bは、アドレス・ID・トラフィックセレクタを左右逆にするだけです。
connections {
site-b-to-a {
version = 2
local_addrs = 198.51.100.20
remote_addrs = 203.0.113.10
proposals = aes256gcm16-prfsha384-ecp384
dpd_delay = 30s
local {
auth = psk
id = site-b
}
remote {
auth = psk
id = site-a
}
children {
net-b-a {
local_ts = 10.2.0.0/24
remote_ts = 10.1.0.0/24
esp_proposals = aes256gcm16-ecp384
start_action = start
dpd_action = restart
}
}
}
}
secrets {
ike-site-ab {
id-a = site-a
id-b = site-b
secret = "your-long-random-psk"
}
}
両側を start_action = start にすると、双方が同時に接続を開始して重複したSAができることがあります。片側を start、もう片側を trap(または接続を待つだけの設定)にしておく構成がよく使われます。
ファイアウォール・転送・NATの設定
IPsecがつながらない原因として多いのが、設定ファイルではなくネットワーク側です。次の3点を両拠点で確認します。
IKEとESPの通信を許可する
IKEはUDP 500番、NAT越え(NAT-T)が発生するとUDP 4500番を使い、NATが無い経路では暗号化データはESP(IPプロトコル番号50)で流れます。ufw を使っている場合の例です。
sudo ufw allow from 198.51.100.20 to any port 500,4500 proto udp
# ESP(プロトコル50)は ufw の通常ルールでは指定できないため、
# /etc/ufw/before.rules に「-A ufw-before-input -p esp -s 198.51.100.20 -j ACCEPT」を追記して ufw reload する
クラウドのVPSでは、OSのファイアウォールとは別に、事業者側のセキュリティグループやパケットフィルタでも同じポートを開ける必要があります。AWS EC2 で内部ネットワークへ中継する場合は、インスタンスの送信元/送信先チェックの無効化も必要です。
IPフォワーディングを有効にする
サーバー自身だけでなく、背後の内部ネットワーク同士を通信させる場合はカーネルの転送を有効にします。
echo 'net.ipv4.ip_forward = 1' | sudo tee /etc/sysctl.d/99-ipsec.conf
sudo sysctl --system
NAT(MASQUERADE)から除外する
内部ネットワークからインターネットへ出る通信を MASQUERADE している環境では、VPN宛ての通信まで変換されてしまい、IPsecのポリシーに一致しなくなります。VPN宛てを先にNATの対象外にします。
sudo iptables -t nat -I POSTROUTING -s 10.1.0.0/24 -d 10.2.0.0/24 -j ACCEPT
この iptables ルールは再起動で消えるため、動作を確認したら、使っている仕組み(netfilter-persistent や ufw の before.rules など)に合わせて永続化してください。
設定の読み込みと疎通確認
両拠点で設定を読み込み、接続状態を確認します。
sudo swanctl --load-all
sudo swanctl --list-conns
sudo swanctl --initiate --child net-a-b
sudo swanctl --list-sas
--list-sas で IKE SA が ESTABLISHED、子SAが INSTALLED と表示されれば確立しています。続けて、拠点Aの内部ネットワーク上のホストから拠点Bの内部アドレスへ ping を送り、--list-sas のバイト数カウンタが増えることを確かめます。カウンタが増えないのに通信できている場合は、VPNを通らず別経路で届いている可能性があります。
つながらないときの確認順
ログは journalctl で確認します。サービス名は環境で異なるため、先に確認した名前を使ってください。
sudo journalctl -u strongswan -f
ログに出る内容から、次の順で原因を絞り込みます。
- 応答が無い・再送を繰り返す: UDP 500/4500 が途中で落ちています。両側のOSファイアウォール、クラウドのセキュリティグループ、相手のグローバルIPの指定を確認します。
- AUTHENTICATION_FAILED: PSKの不一致か、
idの不一致です。IDは文字列として比較されるので、両側のlocal.idとremote.idが対応しているかを見ます。 - NO_PROPOSAL_CHOSEN: 暗号方式の組み合わせが合っていません。
proposalsとesp_proposalsを相手と揃えます。 - TS_UNACCEPTABLE:
local_ts/remote_tsが相手と対応していません。サブネットの範囲とマスク長を確認します。 - 確立するのにpingが通らない: IPフォワーディング、NAT除外、内部ホスト側のルーティング(相手ネットワーク宛てがVPNサーバーを向いているか)を順に確認します。大きなパケットだけ通らない場合は、IPsecのヘッダー分でMTUを超えている可能性があり、TCP MSSの調整を検討します。
運用で気をつけること
設定変更は、いきなり本番の拠点間で試さず、検証用のVMを2台立てて同じ構成で確かめるのが安全です。変更前には /etc/swanctl/ 一式とファイアウォール設定をバックアップしておきます。SSHで接続しているサーバーのファイアウォールを触るときは、自分のSSH接続を遮断しないよう、許可ルールを先に追加してから既存ルールを変更してください。
また、strongSwan 自体のセキュリティ更新は定期的に出ています。OSのパッケージ更新に含めて適用し、更新後は swanctl --list-sas でトンネルが復帰しているかを確認する手順を運用に組み込んでおくと安心です。
まとめ
- 新規構築では
ipsec.confではなくswanctl.confとswanctlコマンドを使う - 暗号方式(
proposals/esp_proposals)とトラフィックセレクタ(local_ts/remote_ts)を両拠点で対応させる - UDP 500/4500 とESPの許可、IPフォワーディング、NAT除外の3点がつまずきやすい
- 状態は
swanctl --list-sas、原因はログのエラー名から順に切り分ける - 単純なサーバー間暗号化なら WireGuard も選択肢になる