将strongswan从旧版迁移到swanctl的新版
需求
之前写过一篇关于strongswan配置的《StrongSwan配置笔记》,因为当时用的系统比较旧,strongswan还是5.7,用的是旧版的starter配置方式,这回是需要在一台新的Debian13上配置,用的是strongswan 6.0.1,要使用新的swanctl方式配置,所以需要迁移一下。
新版的配置方式变化其实只是表面现象,本质上的变化更大。比如后端协议由传统的Stroke协议改为使用现代的VICI协议。更关键的是官方对于旧版的支持已处于维护模式,不再添加新特性,所以还是要切换到更强大且配置灵活的新版。
迁移内容
首先是安装上的区别:
# 首先是移除旧版(如果已经安装了的话)
sudo systemctl disable --now strongswan-starter
sudo systemctl mask strongswan-starter.service
# 然后开始安装新版(注意排除掉旧版)
sudo apt-get update
sudo env DEBIAN_FRONTEND=noninteractive apt-get install -y \
charon-systemd strongswan-swanctl libcharon-extra-plugins certbot \
strongswan-starter- strongswan-
需要注意的是,不要同时安装两个版本,更不要同时启动两个版本,否则会有冲突。
其次就是配置文件上的区别:
旧版的配置文件是/etc/ipsec.conf和ipsec.secrets,新版改为/etc/swanctl/swanctl.conf,格式也完全不同。
配置变更
一个可供参考新版配置如下:
connections {
ikev2-eap {
version = 2
local_addrs = %any
remote_addrs = %any
proposals = aes256gcm16-prfsha384-ecp384,aes256gcm16-prfsha256-modp2048,aes256-sha256-modp2048,aes256-sha256-ecp256,aes256-sha1-modp2048,aes128-sha1-modp2048
fragmentation = yes
mobike = yes
send_cert = always
unique = never
pools = vpn-ipv4
dpd_delay = 30s
rekey_time = 0s
reauth_time = 0s
local {
auth = pubkey
certs = server.pem
id = <your_domain_name>
}
remote {
auth = eap-mschapv2
eap_id = %any
}
children {
internet {
local_ts = 0.0.0.0/0
remote_ts = dynamic
esp_proposals = aes256gcm16,aes128gcm16,aes256-sha256,aes128-sha256,aes256-sha1,aes128-sha1
rekey_time = 1h
life_time = 90m
dpd_action = clear
start_action = none
}
}
}
}
pools {
vpn-ipv4 {
addrs = 10.12.0.0/24
dns = 1.1.1.1, 8.8.8.8
}
}
include conf.d/*.conf
其中<your_domain_name>要换成你的服务器域名,并且提供相应的TLS证书。
这里的配置中保留 AES/SHA1 + MODP2048 作为部分原生客户端的兼容选项,优先协商 AES-GCM 或 SHA256。Windows 下文提供显式 SHA256 设置。unique = never 允许同一账号在多个设备连接。
域名证书
首先配置好域名解析。这里以Let’s encrypt签署的证书为例。如果现有 Nginx/Apache 的域名匹配及 HTTP challenge 路径可用,不需要停用 Web 服务。
sudo /usr/bin/certbot certonly --webroot \
-w /path_to/www/challenge \
--cert-name <your_domain_name> -d <your_domain_name> \
--key-type rsa --rsa-key-size 3072 --non-interactive
证书目录:/etc/letsencrypt/live/<your_domain_name>/,私钥只存放在服务器。
证书通过 /usr/local/sbin/refresh-swanctl-certs 同步:
cert.pem→/etc/swanctl/x509/server.pem,权限 644。privkey.pem→/etc/swanctl/private/server.pem,权限 600。chain.pem拆分到/etc/swanctl/x509ca/letsencrypt-chain-*.pem。- 服务运行时调用
swanctl --load-creds热加载,无需重启 VPN。
本次证书链为服务器证书 → Let’s Encrypt YR2 → Root YR → ISRG Root X1。应下发完整的中间证书链,不能只复制叶子证书,也不能假定 chain.pem 永远只有一张证书。
证书自动更新需要启用 Debian 的 certbot.timer,续期命令统一使用绝对路径 /usr/bin/certbot。创建证书续期脚本 /etc/letsencrypt/renewal-hooks/deploy/50-swanctl :
#!/bin/sh
set -eu
DOMAIN=<your_domain_name>
if [ "${RENEWED_LINEAGE:-}" = /etc/letsencrypt/live/${DOMAIN} ]; then
/usr/local/sbin/refresh-swanctl-certs
fi
/usr/sbin/nginx -t && /usr/bin/systemctl reload nginx
然后用下面的命令启用:
sudo systemctl enable --now certbot.timer strongswan.service
sudo /usr/bin/certbot renew --cert-name <your_domain_name> \
--dry-run --run-deploy-hooks --no-random-sleep-on-renew
HTTP-01 续期需要继续保留域名解析、TCP 80 和现有 webroot challenge 路径。
账号配置
原来的账号配置文件 /etc/ipsec.secrets 已经没用了,新文件是 /etc/swanctl/conf.d/90-eap-secrets.conf,root:root、600。密码使用 swanctl 的 0s Base64 格式存储;Base64 不是加密。
参考配置如下:
secrets {
eap-migrated-1 {
id = "用户名"
secret = 0s<密码的Base64>
}
}
修改账号应编辑新文件,再运行:
sudo swanctl --load-creds
charon-systemd的配置
文件在: /etc/strongswan.d/zz-vpn-systemd.conf
charon-systemd {
load = random nonce x509 revocation constraints pubkey pkcs1 pkcs7 pem openssl gcm drbg kernel-netlink socket-default vici eap-identity eap-mschapv2
load_modular = no
plugins {
openssl {
load_legacy = yes
}
}
}
swanctl {
load = random nonce x509 revocation constraints pubkey pkcs1 pkcs7 pem openssl gcm drbg
}
OpenSSL legacy provider 提供 EAP-MSCHAPv2 所需的 MD4/DES 算法;它不代表 IKE/ESP 允许使用 DES,实际隧道套件由上面的 proposals 限定。显式插件列表也避免加载旧 stroke/XAUTH/DHCP/attr 功能,以及 swanctl 对未安装插件的告警。DNS 只由新地址池下发。
网络及防火墙配置
在 /etc/sysctl.conf 里加上:
net.ipv4.ip_forward = 1
然后启用:
sudo sysctl -p
在已有 iptables-nft 规则中现有 INPUT 部分,在 DROP 前放行 UDP 500/4500 和 ESP。FORWARD 调整为同时匹配地址池及 IPsec policy,不需要绑定入站/出站网卡名:
-A FORWARD -s 10.12.0.0/24 -m policy --dir in --pol ipsec -j ACCEPT
-A FORWARD -d 10.12.0.0/24 -m policy --dir out --pol ipsec -j ACCEPT
配置如下 NAT 规则:
-A POSTROUTING -s 10.12.0.0/24 -o eth0 -m policy --dir out --pol ipsec -j ACCEPT
-A POSTROUTING -s 10.12.0.0/24 -o eth0 -j MASQUERADE
以上为规则内容,添加到 iptables.save 后使用 iptables-restore 命令加载,不能直接作为 shell 命令运行。
客户端配置
iOS / iPadOS
设置 → 通用 → VPN 与设备管理 → VPN → 添加 VPN 配置:
- 类型:IKEv2。
- 服务器、远程 ID:
<your_domain_name>。 - 本地 ID:留空。
- 用户鉴定:用户名,填写账号和密码。
- 代理:关闭。
使用系统信任的 CA 验证服务器证书;无需导入服务器私钥或客户端证书,不要选择共享密钥认证。
macOS
系统设置 → VPN → 添加 VPN 配置 → IKEv2。服务器地址、远程 ID 都填写 <your_domain_name>,本地 ID 留空,认证选择用户名和密码。不同 macOS 版本的菜单位置可能略有不同。
Android
使用 strongSwan VPN Client:
- Server:
<your_domain_name>。 - VPN Type:
IKEv2 EAP (Username/Password)。 - Username / Password:账号和密码。
- CA certificate:自动选择。
- 若填写 Server identity,设为
<your_domain_name>。
不要选择 Certificate + EAP,也无需安装用户证书。可按需求打开始终开启 VPN、阻止非 VPN 流量。手机厂商内置 IKEv2 配置界面差异较大,此文以 strongSwan App 为准。
Windows 10 / 11
创建 Windows 内置 VPN,服务器 <your_domain_name>,类型 IKEv2,登录信息为用户名和密码。连接名可设为 xxx-IKEv2。
在适用的用户上下文运行 PowerShell(涉及权限时以管理员运行):
Add-VpnConnection -Name "xxx-IKEv2" `
-ServerAddress "<your_domain_name>" `
-TunnelType Ikev2 -AuthenticationMethod Eap `
-EncryptionLevel Required -SplitTunneling $false
Set-VpnConnectionIPsecConfiguration -ConnectionName "xxx-IKEv2" `
-EncryptionMethod AES256 -IntegrityCheckMethod SHA256 `
-DHGroup Group14 -CipherTransformConstants AES256 `
-AuthenticationTransformConstants SHA256128 -PfsGroup None -Force
如果连接已在界面创建,跳过 Add-VpnConnection。打开 ncpa.cpl → 此 VPN 的属性 → 安全,确认 EAP 方法为 Microsoft: Secured password (EAP-MSCHAP v2);不要选择智能卡/证书或 PEAP,不要自动使用 Windows 登录账号。连接时输入 VPN 原账号密码。
根证书需受 Windows 信任;正常更新的系统通常已有 ISRG Root X1。若证书验证失败,应检查系统时间、根证书及远程域名,不要禁用服务器证书校验。
Linux 桌面
Debian/Ubuntu 可安装 NetworkManager 的 strongSwan 插件:
sudo apt-get install network-manager-strongswan
在网络设置中新增 IPsec/IKEv2(strongSwan)连接,网关填 <your_domain_name>,认证为 EAP 用户名/密码。指定系统可信根 /etc/ssl/certs/ISRG_Root_X1.pem(其他发行版路径可能不同),如有服务器身份栏填写新域名。要求 IPv4 全隧道时不要勾选“仅用于此网络上的资源”。
Linux 无桌面也可使用 charon-systemd + swanctl 作为客户端。
对比其它平台,再次证明了一个真理:Windows善于制造其它平台上不存在的问题……