Configure a Multi-Site IPsec VPN on Debian 13 with strongSwan 6
- Last updated: Sep 12, 2025

With each major release, Debian introduces updated software packages. Debian 13 “Trixie” now ships with strongSwan 6, which brings significant changes to the configuration format compared to previous versions. As a result, configuration files from earlier releases such as Debian 12 are no longer compatible, since the syntax has been completely redesigned.
In this guide, I will demonstrate how to configure strongSwan 6 for a multi-site IPsec VPN architecture using three Debian 13 routers. This setup builds upon my previous tutorial for Debian 12 “Bookworm”, which you can find here: Setting Up a Multi-Site IPsec VPN with strongSwan on Debian 12.
- The architecture presented in this tutorial includes three routers running Debian and strongSwan:
- Headquarters: the central hub of the network, hosting four segments for users, IP phones, WiFi, and application servers. It also acts as the VPN gateway for inter-site traffic between Branch Office 1 and Branch Office 2.
- Branch Office 1: includes three networks for users, IP phones, and WiFi.
- Branch Office 2: includes three networks for users, IP phones, and WiFi.
Network Architecture Diagram

Site 1 – Headquarters (VPN Gateway)
Let's start with the configuration of the main site. This site centralizes all VPN connections for the other locations, and it also serves as the authority that allows specific traffic—in this case, the VoIP network—between Branch Office 1 and Branch Office 2.
Headquarters - Prerequisites
- Install the strongSwan package:
root@HQ:~# apt update && apt install strongswan
- Enable
nftables
autostart:
root@HQ:~# systemctl enable nftables.service
Headquarters - nftables Configuration
The configuration of nftables
is simplified here, allowing networks to access the Internet and communicate with each other. In a production environment, you may want to configure filtering rules between VLANs.
- Edit the
/etc/nftables.conf
file:
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
chain input {
type filter hook input priority 0; policy accept;
}
chain forward {
type filter hook forward priority 0; policy accept ;
}
chain output {
type filter hook output priority 0; policy accept;
}
}
#NAT for outgoing traffic.
table ip my_nat {
chain my_masquerade {
type nat hook postrouting priority 100;
ip daddr != { 10.1.0.1, 192.168.0.0/16 } oifname wan masquerade comment "output nat"
}
}
- Reload the
nftables
configuration:
root@HQ:~# nft -f /etc/nftables.conf
Headquarters - Network Configuration
Configure Headquarters Network Interfaces
Here, we configure our two network interfaces: lan
and wan
. For details on how to rename network interfaces in Debian, see this guide: Renaming Network Interfaces on Debian. We will configure the system to run the script /usr/local/sbin/ipconf.sh
(which we will create later) automatically when the lan
interface comes up.
- Edit the
/etc/network/interfaces
file:
# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).
source /etc/network/interfaces.d/*
# The loopback network interface
auto lo
iface lo inet loopback
# The primary network interface
# This is an autoconfigured IPv6 interface
allow-hotplug wan
iface wan inet static
address 10.1.0.1
netmask 255.255.255.0
gateway 10.1.0.254
allow-hotplug lan
iface lan inet static
address 192.168.1.254
netmask 255.255.255.0
up /usr/local/sbin/ipconf.sh
- Reboot the system or restart the networking service:
root@HQ:~# systemctl restart networking
Enable IP Forwarding for Gateway Mode
Since our Debian server will act as a router, we need to enable IP forwarding.
- Create a
/etc/sysctl.d/99-ipforward.conf
file and add the following line:
net.ipv4.ip_forward=1
- Apply the change immediately with the following command:
root@HQ:~# sysctl -p /etc/sysctl.d/99-ipforward.conf
Network Script
The /usr/local/sbin/ipconf.sh
script will be executed at startup. It is used to configure the VLAN interfaces automatically.
- Create a
/usr/local/sbin/ipconf.sh
file:
#!/bin/sh
# VLAN configuration script for the lan interface
# This script creates VLAN interfaces and assigns IP addresses
# Run at startup to ensure VLANs are ready before services start
# --- SETTING UP VLANs ON THE lan INTERFACE ---
modprobe 8021q
ip link add link lan name users type vlan id 2
ip link add link lan name voip type vlan id 3
ip link add link lan name wifi type vlan id 4
ip link add link lan name servers type vlan id 5
# Bring VLAN interfaces up
ip link set users up
ip link set voip up
ip link set wifi up
ip link set servers up
# --- VLAN INTERFACE IP ADDRESS SETTINGS ---
ip addr add 192.168.2.254/24 dev users
ip addr add 192.168.3.254/24 dev voip
ip addr add 192.168.4.254/22 dev wifi
ip addr add 192.168.5.254/24 dev servers
- Modify the permissions so that the
/usr/local/sbin/ipconf.sh
script is executable:
root@host:~# chmod +x /usr/local/sbin/ipconf.sh
Headquarters - strongSwan Configuration
strongSwan Main Configuration File: /etc/swanctl/swanctl.conf
- Edit the
/etc/swanctl/swanctl.conf
file to configure the site-to-site connections. The goal is to allow VoIP networks at all sites to communicate with each other, and to enable users at Branch Office 1 and Branch Office 2 to access the Headquarters server network:
connections {
#############################################################
# Tunnel between Headquarters (HQ) and Branch Office 1 (B1) #
#############################################################
hq-b1 {
version = 2 # Use IKEv2
mobike = no # Disable MOBIKE (static IPs, no mobility expected)
local_addrs = 10.1.0.1 # Public IP (or WAN IP) of HQ
remote_addrs = 10.10.0.1 # Public IP of Branch Office 1
proposals = aes128-sha256-x25519 # IKE proposals
reauth_time = 0 # Disable reauth, rely on rekey instead
dpd_delay = 20s # Send Dead Peer Detection probes every 20s
dpd_timeout = 60s # Consider peer dead after 60s
local {
auth = psk # Pre-shared key authentication
id = 10.1.0.1 # Local identifier (HQ)
}
remote {
auth = psk
id = 10.10.0.1 # Remote identifier (B1)
}
children {
net-net {
# Traffic Selectors (subnets allowed through this tunnel)
# HQ subnets + VoIP VLAN of B2 (for inter-branch VoIP via HQ)
local_ts = 192.168.1.0/24, 192.168.3.0/24, 192.168.5.0/24, 192.168.20.0/24, 192.168.23.0/24
# Subnets from Branch Office 1
remote_ts = 192.168.10.0/24, 192.168.12.0/24, 192.168.13.0/24
start_action = start # Bring up tunnel automatically at startup
rekey_time = 3600 # Rekey every 60 minutes
dpd_action = restart # Restart connection if peer is dead
esp_proposals = aes128gcm128-x25519
}
}
}
#############################################################
# Tunnel between Headquarters (HQ) and Branch Office 2 (B2) #
#############################################################
hq-b2 {
version = 2 # Use IKEv2
mobike = no # Disable MOBIKE (static IPs, no mobility expected)
local_addrs = 10.1.0.1 # Public IP (or WAN IP) of HQ
remote_addrs = 10.20.0.1
proposals = aes128-sha256-x25519 # IKE proposals
reauth_time = 0 # Disable reauth, rely on rekey instead
dpd_delay = 20s # Send Dead Peer Detection probes every 20s
dpd_timeout = 60s # Consider peer dead after 60s
local {
auth = psk # Pre-shared key authentication
id = 10.1.0.1 # Local identifier (HQ)
}
remote {
auth = psk
id = 10.20.0.1 # Remote identifier (B2)
}
children {
net-net {
# Traffic Selectors (subnets allowed through this tunnel)
# HQ subnets + VoIP VLAN of B1 (for inter-branch VoIP via HQ)
local_ts = 192.168.1.0/24, 192.168.3.0/24, 192.168.5.0/24, 192.168.10.0/24, 192.168.13.0/24
# Subnets from Branch Office 2
remote_ts = 192.168.20.0/24, 192.168.22.0/24, 192.168.23.0/24
start_action = start # Bring up tunnel automatically at startup
rekey_time = 3600 # Rekey every 60 minutes
dpd_action = restart # Restart connection if peer is dead
esp_proposals = aes128gcm128-x25519
}
}
}
}
####################################
# Shared Secrets (Pre-Shared Keys) #
####################################
secrets {
ike-hq-b1 {
id = 10.1.0.1
peer_id = 10.10.0.1
secret = "JohnWeakPasswd:)"
}
ike-hq-b2 {
id = 10.1.0.1
peer_id = 10.20.0.1
secret = "JohnWeakPasswd:)"
}
}
- Restart the
strongswan
service to apply the changes:
root@HQ:~# systemctl restart strongswan
Site 2 – Branch Office 1 VPN Configuration
Let's move on to configuring the first branch office. The setup is similar to that of the headquarters, as it also requires configuring the network interfaces and the strongSwan service.
Branch Office 1 – Prerequisites
- Install the strongSwan package:
root@B1:~# apt update && apt install strongswan
- Enable
nftables
autostart:
root@B1:~# systemctl enable nftables.service
Branch Office 1 – nftables Configuration
As with the headquarters, the nftables
configuration here is simplified. No filtering rules are applied in this example.
- Edit the
/etc/nftables.conf
file:
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
chain input {
type filter hook input priority 0; policy accept;
}
chain forward {
type filter hook forward priority 0; policy accept ;
}
chain output {
type filter hook output priority 0; policy accept;
}
}
#NAT for outgoing traffic.
table ip my_nat {
chain my_masquerade {
type nat hook postrouting priority 100;
ip daddr != { 10.10.0.1, 192.168.0.0/16 } oifname wan masquerade comment "output nat"
}
}
- Reload the
nftables
configuration:
root@host:~# nft -f /etc/nftables.conf
Branch Office 1 - Network Configuration
Configure Branch Office 1 Network Interfaces
Here, we configure our two network interfaces: lan
and wan
.
- Edit the
/etc/network/interfaces
file:
# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).
source /etc/network/interfaces.d/*
# The loopback network interface
auto lo
iface lo inet loopback
# The primary network interface
# This is an autoconfigured IPv6 interface
allow-hotplug wan
iface wan inet static
address 10.10.0.1
netmask 255.255.255.0
gateway 10.10.0.254
allow-hotplug lan
iface lan inet static
address 192.168.10.254
netmask 255.255.255.0
up /usr/local/sbin/ipconf.sh
Enable IP Forwarding for Gateway Mode
- Create a
/etc/sysctl.d/99-ipforward.conf
file and add the following line:
net.ipv4.ip_forward=1
- Apply the change immediately with the following command:
root@B1:~# sysctl -p /etc/sysctl.d/99-ipforward.conf
Network Script
The /usr/local/sbin/ipconf.sh
script will be executed at startup to configure the VLAN interfaces automatically.
- Create a
/usr/local/sbin/ipconf.sh
file:
#!/bin/sh
# VLAN configuration script for the lan interface
# This script creates VLAN interfaces and assigns IP addresses
# Run at startup to ensure VLANs are ready before services start
# --- SETTING UP VLANs ON THE lan INTERFACE ---
modprobe 8021q
ip link add link lan name users type vlan id 2
ip link add link lan name voip type vlan id 3
ip link add link lan name wifi type vlan id 4
# Bring VLAN interfaces up
ip link set users up
ip link set voip up
ip link set wifi up
# --- VLAN INTERFACE IP ADDRESS SETTINGS ---
ip addr add 192.168.12.254/24 dev users
ip addr add 192.168.13.254/24 dev voip
ip addr add 192.168.14.254/22 dev wifi
- Modify the permissions so that the
/usr/local/sbin/ipconf.sh
script is executable:
root@B1:~# chmod +x /usr/local/sbin/ipconf.sh
Branch Office 1 - strongSwan Configuration
strongSwan Main Configuration File: /etc/swanctl/swanctl.conf
- Edit the
/etc/swanctl/swanctl.conf
file:
connections {
#############################################################
# Tunnel between Branch Office 1 (B1) and Headquarters (HQ) #
#############################################################
b1-hq {
version = 2 # Use IKEv2
mobike = no # Disable MOBIKE (static IPs, no mobility expected)
local_addrs = 10.10.0.1 # Public IP of Branch Office 1
remote_addrs = 10.1.0.1 # Public IP (or WAN IP) of HQ
proposals = aes128-sha256-x25519 # IKE proposals
reauth_time = 0 # Disable reauth, rely on rekey instead
dpd_delay = 20s # Send Dead Peer Detection probes every 20s
dpd_timeout = 60s # Consider peer dead after 60s
local {
auth = psk # Pre-shared key authentication
id = 10.10.0.1 # Remote identifier (B1)
}
remote {
auth = psk # Pre-shared key authentication
id = 10.1.0.1 # Local identifier (HQ)
}
children {
net-net {
# Traffic Selectors (subnets allowed through this tunnel)
# B1 subnets
local_ts = 192.168.10.0/24, 192.168.12.0/24, 192.168.13.0/24
# HQ subnets + VoIP VLAN of B2 (for inter-branch VoIP via HQ)
remote_ts = 192.168.1.0/24, 192.168.3.0/24, 192.168.5.0/24, 192.168.20.0/24, 192.168.23.0/24
start_action = start # Bring up tunnel automatically at startup
rekey_time = 3600 # Rekey every 60 minutes
dpd_action = restart # Restart connection if peer is dead
esp_proposals = aes128gcm128-x25519
}
}
}
}
secrets {
ike-b1-hq {
id = 10.10.0.1
peer_id = 10.1.0.1
secret = "JohnWeakPasswd:)"
}
}
- Restart the
strongswan
service to apply the changes:
root@B1:~# systemctl restart strongswan
Site 3 – Branch Office 2 VPN Configuration
Branch Office 2 – Prerequisites
- Install the strongSwan package:
root@B2:~# apt update && apt install strongswan
- Enable
nftables
autostart:
root@B2:~# systemctl enable nftables.service
Branch Office 2 – nftables Configuration
As with the headquarters, the nftables
configuration here is simplified. No filtering rules are applied in this example.
- Edit the
/etc/nftables.conf
file:
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
chain input {
type filter hook input priority 0; policy accept;
}
chain forward {
type filter hook forward priority 0; policy accept ;
}
chain output {
type filter hook output priority 0; policy accept;
}
}
#NAT for outgoing traffic.
table ip my_nat {
chain my_masquerade {
type nat hook postrouting priority 100;
ip daddr != { 10.20.0.1, 192.168.0.0/16 } oifname wan masquerade comment "output nat"
}
}
- Reload the
nftables
configuration:
root@B2:~# nft -f /etc/nftables.conf
Branch Office 2 - Network Configuration
Configure Branch Office 2 Network Interfaces
Here, we configure our two network interfaces: lan
and wan
.
- Edit the
/etc/network/interfaces
file:
# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).
source /etc/network/interfaces.d/*
# The loopback network interface
auto lo
iface lo inet loopback
# The primary network interface
allow-hotplug wan
iface wan inet static
address 10.20.0.1
netmask 255.255.255.0
allow-hotplug lan
iface lan inet static
address 192.168.21.254
netmask 255.255.255.0
up /usr/local/sbin/ipconf.sh
Enable IP Forwarding for Gateway Mode
- Create a
/etc/sysctl.d/99-ipforward.conf
file and add the following line:
net.ipv4.ip_forward=1
- Apply the change immediately with the following command:
root@B2:~# sysctl -p /etc/sysctl.d/99-ipforward.conf
Network Script
The /usr/local/sbin/ipconf.sh
script will be executed at startup to configure the VLAN interfaces automatically.
- Create a
/usr/local/sbin/ipconf.sh
file:
#!/bin/sh
# VLAN configuration script for the lan interface
# This script creates VLAN interfaces and assigns IP addresses
# Run at startup to ensure VLANs are ready before services start
# --- SETTING UP VLANs ON THE lan INTERFACE ---
modprobe 8021q
ip link add link lan name users type vlan id 2
ip link add link lan name voip type vlan id 3
ip link add link lan name wifi type vlan id 4
# Bring VLAN interfaces up
ip link set users up
ip link set voip up
ip link set wifi up
# --- VLAN INTERFACE IP ADDRESS SETTINGS ---
ip addr add 192.168.22.254/24 dev users
ip addr add 192.168.23.254/24 dev voip
ip addr add 192.168.24.254/22 dev wifi
- Modify the permissions so that the
/usr/local/sbin/ipconf.sh
script is executable:
root@host:~# chmod +x /usr/local/sbin/ipconf.sh
Branch Office 2 - strongSwan Configuration
strongSwan Main Configuration File: /etc/swanctl/swanctl.conf
- Edit the
/etc/swanctl/swanctl.conf
file:
connections {
#############################################################
# Tunnel between Branch Office 2 (B2) and Headquarters (HQ) #
#############################################################
b2-hq {
version = 2 # Use IKEv2
mobike = no # Disable MOBIKE (static IPs, no mobility expected)
local_addrs = 10.20.0.1 # Public IP of Branch Office 2
remote_addrs = 10.1.0.1 # Public IP (or WAN IP) of HQ
proposals = aes128-sha256-x25519 # IKE proposals
reauth_time = 0 # Disable reauth, rely on rekey instead
dpd_delay = 20s # Send Dead Peer Detection probes every 20s
dpd_timeout = 60s # Consider peer dead after 60s
local {
auth = psk # Pre-shared key authentication
id = 10.20.0.1 # Remote identifier (B2)
}
remote {
auth = psk # Pre-shared key authentication
id = 10.1.0.1 # Local identifier (HQ)
}
children {
net-net {
# Traffic Selectors (subnets allowed through this tunnel)
# B2 subnets
local_ts = 192.168.20.0/24, 192.168.22.0/24, 192.168.23.0/24
# HQ subnets + VoIP VLAN of B2 (for inter-branch VoIP via HQ)
remote_ts = 192.168.1.0/24, 192.168.3.0/24, 192.168.5.0/24, 192.168.10.0/24, 192.168.13.0/24
start_action = start # Bring up tunnel automatically at startup
rekey_time = 3600 # Rekey every 60 minutes
dpd_action = restart # Restart connection if peer is dead
esp_proposals = aes128gcm128-x25519
}
}
}
}
secrets {
ike-b2-hq {
id = 10.20.0.1
peer_id = 10.1.0.1
secret = "JohnWeakPasswd:)"
}
}
- Restart the
strongswan
service to apply the changes:
root@B2:~# systemctl restart strongswan
Troubleshooting
- Ping from Headquarters:
root@HQ:~# ping 192.168.20.254 -I 192.168.1.254
- Ping from Branch Office 1:
root@B1:~# ping 192.168.5.254 -I 192.168.12.254
- Ping from Branch Office 2:
root@B2:~# ping 192.168.13.254 -I 192.168.23.254
- Check logs:
root@HQ:~# journalctl -u strongswan
- List strongSwan loaded configurations:
root@HQ:~# swanctl --list-conns
hq-b1: IKEv2, no reauthentication, no rekeying, dpd delay 20s
local: 10.1.0.1
remote: 10.10.0.1
local pre-shared key authentication:
id: 10.1.0.1
remote pre-shared key authentication:
id: 10.10.0.1
net-net: TUNNEL, rekeying every 3600s, dpd action is start
local: 192.168.1.0/24 192.168.3.0/24 192.168.5.0/24 192.168.20.0/24 192.168.23.0/24
remote: 192.168.10.0/24 192.168.12.0/24 192.168.13.0/24
hq-b2: IKEv2, no reauthentication, no rekeying, dpd delay 20s
local: 10.1.0.1
remote: 10.20.0.1
local pre-shared key authentication:
id: 10.1.0.1
remote pre-shared key authentication:
id: 10.20.0.1
net-net: TUNNEL, rekeying every 3600s, dpd action is none
local: 192.168.1.0/24 192.168.3.0/24 192.168.5.0/24 192.168.10.0/24 192.168.13.0/24
remote: 192.168.20.0/24 192.168.22.0/24 192.168.23.0/24
- List strongSwan currently active IKE_SAs:
root@HQ:~# swanctl --list-sas
hq-b2: #6, ESTABLISHED, IKEv2, d0f895ea384c5d55_i 3b76bf7604c051fd_r*
local '10.1.0.1' @ 10.1.0.1[500]
remote '10.20.0.1' @ 10.20.0.1[500]
AES_CBC-128/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/CURVE_25519
established 433s ago
net-net: #7, reqid 2, INSTALLED, TUNNEL, ESP:AES_GCM_16-128
installed 433s ago, rekeying in 2974s, expires in 3527s
in c19f2fff, 672 bytes, 8 packets, 231s ago
out ca67ea94, 672 bytes, 8 packets, 231s ago
local 192.168.1.0/24 192.168.3.0/24 192.168.5.0/24 192.168.10.0/24 192.168.13.0/24
remote 192.168.20.0/24 192.168.22.0/24 192.168.23.0/24
hq-b1: #5, ESTABLISHED, IKEv2, 7c785e920c3a199a_i fddac3562b3129fe_r*
local '10.1.0.1' @ 10.1.0.1[500]
remote '10.10.0.1' @ 10.10.0.1[500]
AES_CBC-128/HMAC_SHA2_256_128/PRF_HMAC_SHA2_256/CURVE_25519
established 1274s ago
net-net: #5, reqid 1, INSTALLED, TUNNEL, ESP:AES_GCM_16-128
installed 1274s ago, rekeying in 2179s, expires in 2686s
in c8d03828, 56952 bytes, 678 packets, 236s ago
out cc5e72e5, 56952 bytes, 678 packets, 236s ago
local 192.168.1.0/24 192.168.3.0/24 192.168.5.0/24 192.168.20.0/24 192.168.23.0/24
remote 192.168.10.0/24 192.168.12.0/24 192.168.13.0/24