将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善于制造其它平台上不存在的问题……