Recently, I implemented an interesting scenario involving Linux networking and VPN. These were the requirements:
- Unprivileged LXC container running on Debian 13 host:
- All internet-bound traffic from the container is routed via remote VPN.
- Container must not be able to communicate with any other networks the host might be directly connected to.
- The container itself has no knowledge about the VPN.
- If the VPN does not work, the container can’t communicate with internet services.
- Debian 13 host:
- strongSwan handles IPSec IKEv2 connections with the remote VPN service.
- Network traffic originating from the host system is not routed via the VPN service.
- Remote IPSec IKEv2 VPN service:
- Not under our control.
- Assigns a single virtual IPv4 address.

IPv4 ranges (RFC1918) used in the example
192.168.99.0/24– network the host is connected to192.168.222.0/24– host-only network for the container(s)10.9.8.7/32– VPN virtual IP
Let’s take a brief look at a base VPN configuration. It is very easy to configure a policy-based IKEv2 VPN for the host. Example swanctl.conf:
policy-based-vpn {
version = 2
local_addrs = 192.168.99.98
remote_addrs = remote-vpn-gateway.macadmin.cz
vips = 0.0.0.0
local {
auth = pubkey
id = vpn-client.macadmin.cz
}
remote {
auth = pubkey
id = remote-vpn-gateway.macadmin.cz
}
children {
netvpn {
remote_ts = 0.0.0.0/0
start_action = trap
}
}
}
The challenge is how to make it work for the traffic originating from the container
and exclude all traffic originating from the host system. The host only network 192.168.222.0/24, the container is connected to, will have to be NATed behind a single IPv4 address to match the 1:1 expectation of the VPN service. First I tried to come up with a solution using policy-based VPN configuration, but after some thinking I figured a route-based VPN might be a better fit for this situation.
The plan:
- Create XFRM interface
ipsec0and assign IPSec policy with match-all-traffic selector0.0.0.0/0. - Create source routing table which will apply to all traffic originating from the host-only network and use it to route the traffic to
ipsec0interface. - Use
nftablesto configure Source NAT onipsec0. - Make sure virtual IPv4 address assigned by the VPN server gets assigned to
ipsec0and not any another interface.