Two Wireguard clients at same time?

Hi to all, I would like to run my RUT200 (fw_ver RUT2M_R_00.07.11.1) with two wireguard clients due I need a backup access if main server fails.

Here part of my /etc/config/network:

config interface 'wg_CATT'
	option proto 'wireguard'
	option listen_port '51820'
	option private_key 'oJPHxpUo='
	list addresses '10.252.2.7/32'
	option mtu '1450'
	option disabled '0'

config wireguard_wg_CATT 'p_wg_CATT'
	option public_key 'CB8d4kc='
	option preshared_key '1PSyjpsCV6ESdI='
	list allowed_ips '10.252.2.0/24'
	option persistent_keepalive '15'
	option endpoint_host '4.4.4.4'
	option route '1'
	option force_tunlink '0'
	option tunlink 'any'
	option route_allowed_ips '1'

config interface 'wg_CATT_b'
	option proto 'wireguard'
	option listen_port '51820'
	option private_key 'gMHay8oqvt/2uyac0g='
	option mtu '1450'
	list addresses '10.10.10.10/32'
	option disabled '0'

config wireguard_wg_CATT_b 'p_wg_CATT_b'
	option public_key 'bdWaCDw='
	option preshared_key 'Orugoro='
	list allowed_ips '10.10.10.0/24'
	option persistent_keepalive '15'
	option endpoint_host '8.8.8.8'
	option route '1'
	option force_tunlink '0'
	option tunlink 'any'
	option route_allowed_ips '1'

I can only get one wireguard interface running at time, not both together.

I supposed to get both wg_CATT and wg_CATT_b interfaces in my routing table, but in command “route” I can only see one between wg_CATT or wg_CATT_b interfaces.
What’s wrong on my configuration?
Is it supposed to use more than une wg client at time?
Thanks.

Hello,

Having more than one simultaneous wg responder configurations is possible:

  • You need to choose different option listen_port values for the interfaces 51820 and 51821 will do,
  • Your list addresses ‘10.252.2.7/32’ and ‘10.10.10.10/32’ are wrong use a /24 netmask instead else routing will fail,
  • Your MTU is too high set it to 1420 max IMO it is not worth the hassle to try values above 1280.
  • There is no need to specify an endpoint_host option for a responder.
  • And don’t set persistent_keepalive on the responder use this option on the initiator only.

Regards,

Mmh… ok, I thought it was the listening port on the server.
Thanks, now it works.

Ok, here my script to add wireguard clients starting from xxx.conf client configuration file made using WireguardUI:

#!/bin/ash


#set -x


# Check for configuration file
if [ "$#" -ne 1 ]; then
 echo "Usage: $0 wireguard_configuration_file.conf"
 exit 1
fi


ConfigFile="$1"
Interface=$(basename "$ConfigFile" .conf)

# Validate interface name length
if [ ${#Interface} -gt 5 ]; then
 echo "Error: Interface name '$Interface' exceeds 5 characters."
 exit 1
fi


# Extract CLIENT parameters from [Interface]
Address=$(awk '/^\[Interface\]/ { intf=1 } /^Address/ && intf { print $3 }' "$ConfigFile")
PrivateKey=$(awk '/^\[Interface\]/ { intf=1 } /^PrivateKey/ && intf { print $3 }' "$ConfigFile")
ListenPort=$(awk '/^\[Interface\]/ { intf=1 } /^ListenPort/ && intf { print $3 }' "$ConfigFile")

# Extract SERVER (Peer) parameters from [Peer]
PublicKey=$(awk '/^\[Peer\]/ { peer=1 } /^PublicKey/ && peer { print $3 }' "$ConfigFile")
PresharedKey=$(awk '/^\[Peer\]/ { peer=1 } /^PresharedKey/ && peer { print $3 }' "$ConfigFile")
Endpoint=$(awk '/^\[Peer\]/ { peer=1 } /^Endpoint/ && peer { print $3 }' "$ConfigFile")
AllowedIPs=$(awk '/^\[Peer\]/ { peer=1 } /^AllowedIPs/ && peer { print $3 }' "$ConfigFile")
Keepalive=$(awk '/^\[Peer\]/ { peer=1 } /^PersistentKeepalive/ && peer { print $3 }' "$ConfigFile")
MTU=$(awk '/^\[Interface\]/ { intf=1 } /^MTU/ && intf { print $3 }' "$ConfigFile")

echo "MTU forced to 1420"
# di default 1450
MTU=1420
MTU=1280 # standard compatibile con molti servizi


# Validate required fields
[ -z "$Address" ] && { echo "Missing Address"; exit 1; }
[ -z "$PrivateKey" ] && { echo "Missing PrivateKey"; exit 1; }
[ -z "$PublicKey" ] && { echo "Missing PublicKey"; exit 1; }
[ -z "$Endpoint" ] && { echo "Missing Endpoint"; exit 1; }

# Split Endpoint into host and port
EndpointHost="${Endpoint%:*}"
EndpointPort="${Endpoint##*:}"





Interface="wg_$Interface"        # modificato io per avere un tunnel corrispondente all'interfaccia, altrimenti mi confingo





# Check for existing interface


echo "Interface = $Interface"
echo "PrivateKey = '$PrivateKey'"

interface_exists() {
 grep -q "config interface '$Interface'" /etc/config/network
}

if interface_exists; then
 echo "Interface '$Interface' exists. Exiting."
 exit 0
fi



# Check for existing interface parameters
# ma questa ricerca viene effettuata su tutto il file.....
parameters_exist() {
 grep -q "option private_key '$PrivateKey'" /etc/config/network && \
 grep -q "option public_key '$PublicKey'" /etc/config/network && \
 grep -q "option endpoint_host '$EndpointHost'" /etc/config/network
}


if parameters_exist; then
 echo "Interface with same parameters exists. Exiting."
 exit 0
fi





# check for listen port on client side
ClientListenPort=51820

listenport_exist() {
 grep -q "option listen_port '$ClientListenPort'" /etc/config/network
}

if listenport_exist; then
 #echo "listen_port $listenport_exist already present."
 
 while listenport_exist; do
   ClientListenPort=$((ClientListenPort+1))
 done
 #echo "listen_port set to $ClientListenPort"
fi


# Generate UCI configuration

config_interface="
config interface '$InterfaceName'
 option proto 'wireguard'
 option private_key '$PrivateKey'
 list addresses '$Address'
 $( [ -n "$MTU" ] && echo "option mtu '$MTU'" )
 option disabled '1'
"



config_peer="
config wireguard_$InterfaceName
 option public_key '$PublicKey'
 option preshared_key '$PresharedKey'
 list allowed_ips '$AllowedIPs'
 option endpoint_host '$EndpointHost'
 option endpoint_port '$EndpointPort'
 $( [ -n "$Keepalive" ] && echo "option persistent_keepalive '$Keepalive'" )
 option route '1'
"


# creo il backup del vecchio file di rete

timestamp=$(date +"%Y%m%d_%H%M%S")
#echo "$timestamp"

# Genera il nome del file
filename="network_${timestamp}.bak"

# Stampa il nome generato
#echo "$filename"


# Backup network config
cp /etc/config/network "/etc/config/$filename" || exit 1


echo "$config_interface"  /etc/config/network
echo "$config_peer"  /etc/config/network

# Reload network
/etc/init.d/network reload && echo "Success" || echo "Failed"```

Interesting. I’ll try it.

Ok, script updated and tested on RUT200 RUT2M_R_00.07.13.2

Loading wireguard configuration file created by WireguardUI (let’s say FERR.conf for main and FERR_b.conf for server backup).

Usage:
./myscript.sh FERR.conf

Creating on /etc/config/network following wireguard interface and wireguard peer:

config interface ‘wg_ferr’

config wireguard_wg_ferr ‘pferr’

Created backup of network file with timestamp (date and time):

network_20250305_104138.bak

Wireguard interfaces disabled by default, to be manually enabled.

#!/bin/ash


#set -x


# Check for configuration file
if [ "$#" -ne 1 ]; then
echo "Usage: $0 wireguard_configuration_file.conf"
exit 1
fi


ConfigFile="$1"
Interface=$(basename "$ConfigFile" .conf)

MaxLen=7

# Validate interface name length
if [ ${#Interface} -gt $MaxLen ]; then
 echo "Error: Interface name '$Interface' exceeds $MaxLen characters."
 exit 1
fi


# Extract CLIENT parameters from [Interface]
Address=$(awk '/^\[Interface\]/ { intf=1 } /^Address/ && intf { print $3 }' "$ConfigFile")
PrivateKey=$(awk '/^\[Interface\]/ { intf=1 } /^PrivateKey/ && intf { print $3 }' "$ConfigFile")
ListenPort=$(awk '/^\[Interface\]/ { intf=1 } /^ListenPort/ && intf { print $3 }' "$ConfigFile")

# Extract SERVER (Peer) parameters from [Peer]
PublicKey=$(awk '/^\[Peer\]/ { peer=1 } /^PublicKey/ && peer { print $3 }' "$ConfigFile")
PresharedKey=$(awk '/^\[Peer\]/ { peer=1 } /^PresharedKey/ && peer { print $3 }' "$ConfigFile")
Endpoint=$(awk '/^\[Peer\]/ { peer=1 } /^Endpoint/ && peer { print $3 }' "$ConfigFile")
AllowedIPs=$(awk '/^\[Peer\]/ { peer=1 } /^AllowedIPs/ && peer { print $3 }' "$ConfigFile")
Keepalive=$(awk '/^\[Peer\]/ { peer=1 } /^PersistentKeepalive/ && peer { print $3 }' "$ConfigFile")
MTU=$(awk '/^\[Interface\]/ { intf=1 } /^MTU/ && intf { print $3 }' "$ConfigFile")

echo "MTU forced to 1420"
# di default 1450
MTU=1420
MTU=1280 # standard compatibile con molti servizi


# Validate required fields
[ -z "$Address" ] && { echo "Missing Address"; exit 1; }
[ -z "$PrivateKey" ] && { echo "Missing PrivateKey"; exit 1; }
[ -z "$PublicKey" ] && { echo "Missing PublicKey"; exit 1; }
[ -z "$Endpoint" ] && { echo "Missing Endpoint"; exit 1; }

# Split Endpoint into host and port
EndpointHost="${Endpoint%:*}"
EndpointPort="${Endpoint##*:}"







# Funzione per lowercase
to_lowercase() {
    echo "$1" | tr 'A-Z' 'a-z'  # Sintassi alternativa per BusyBox
}


# Convert to lowercase to be compatible with OpenWrt uci code
Interface=$(to_lowercase "$Interface")
InterfaceName="wg_$Interface"


# Check for existing interface

echo "Interface = $Interface"
echo "InterfaceNAme = $InterfaceName"





interface_exists() {
grep -q "config interface '$InterfaceName'" /etc/config/network
}

if interface_exists; then
echo "Interface '$InterfaceName' exists. Exiting."
exit 0
fi



# Check for existing interface parameters
# ma questa ricerca viene effettuata su tutto il file.....
parameters_exist() {
grep -q "option private_key '$PrivateKey'" /etc/config/network && \
grep -q "option public_key '$PublicKey'" /etc/config/network && \
grep -q "option endpoint_host '$EndpointHost'" /etc/config/network
}


if parameters_exist; then
echo "Interface with same parameters exists. Exiting."
exit 0
fi





# check for listen port on client side
ClientListenPort=51820

listenport_exist() {
grep -q "option listen_port '$ClientListenPort'" /etc/config/network
}

if listenport_exist; then
#echo "listen_port $listenport_exist already present."

while listenport_exist; do
  ClientListenPort=$((ClientListenPort+1))
done
#echo "listen_port set to $ClientListenPort"
fi


# Generate UCI configuration

config_interface="
config interface '$InterfaceName'
option proto 'wireguard'
option listen_port '$ClientListenPort'
option private_key '$PrivateKey'
list addresses '$Address'
$( [ -n "$MTU" ] && echo "option mtu '$MTU'" )
option disabled '1'
"



config_peer="
config wireguard_$InterfaceName 'p$Interface'
option public_key '$PublicKey'
option preshared_key '$PresharedKey'
list allowed_ips '$AllowedIPs'
option endpoint_host '$EndpointHost'
option endpoint_port '$EndpointPort'
$( [ -n "$Keepalive" ] && echo "option persistent_keepalive '$Keepalive'" )
#option route '1'
option route_allowed_ips '1' # aggiunta io dopo
"


# creo il backup del vecchio file di rete
timestamp=$(date +"%Y%m%d_%H%M%S")
#echo "$timestamp"

# Genera il nome del file
filename="network_${timestamp}.bak"

# Stampa il nome generato
#echo "$filename"


# Backup network config
cp /etc/config/network "/etc/config/$filename" || exit 1


echo "$config_interface"
echo "$config_peer"



echo "$config_interface" >> /etc/config/network
echo "$config_peer" >> /etc/config/network

# Reload network
#/etc/init.d/network restart && echo "Success" || echo "Failed"

Ok, some updates: due to OpenWrt compatibility I need to avoid uppercase in interfaces names.
Due I am using underscore in interface names, I need /etc/init.d/network restart instead of /etc/init.d/network reload.

You can change code to create instead wg0, wg1, wg2, … interface names, so you’ll simply need /etc/init.d/network reload to correctly update router.

Just a few remarks about your script:

  • for a responder (server) set persistent_keepalive to 0
  • for an initiator (client) don’t set listen_port at all a random value will be assigned by the bind() call
  • list addresses and list allowed_ips can occur multiple times for the same interface and peer respectively.

Mmh… after further testing, I discovered I can’t access to my RUT200 from outside, more precisely I can access only from “wg0” (let’s say main wireguard) but “wg0” (backup) is unreachable.
On firewall zones I find a “wireguard” zone with wg0 interface.
I need to manually add wg0 to “wireguard” zone, while this is automatically made using OpenVpn.
I don’t know why…

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.