A python project to help find the optimal MTU values that maximizes the upload or download speeds between a peer and server. It also helps find bandwidth dead zones caused due to a poor choice of MTUs.
I built the project to help myself find the right MTU values for my WG server and peer. I inadvertently found that the default MTU values for the server and peer in my case put my WG connection in a bandwidth dead zone. Related reddit post.
You can have a look at the real-world heatmaps which are posted by users in the issue Post your MTU heatmaps here! If you happen to successfully use nr-wg-mtu-finder
and are able to generate a heatmap, please post your heatmap in the issue if possible.
Lastly, please read the following documentation carefully!
python 3.8
and python 3.9
. While it may work on python 3.7
and python 3.10
, you may have to resolve some issues with building dependencies, yourself.0.2.1
WARNING: This project contains scripts that run shell commands using root access. DO NOT USE IN PRODUCTION.
WARNING: This project tears down and spins up the Wireguard interface in the order of a thousand times. DO NOT USE IN PRODUCTION.
That being said, if you're an experienced python developer, please go through the code to verify that it meets your security standards.
The project has been built and tested on Ubuntu 20.04 & Python 3.9.
Install the following on both the WG server and WG peer
ping
# Ubuntu
sudo apt install iputils-ping
iperf3
# Source: https://iperf.fr/iperf-download.php
sed
# Ubuntu
sudo apt install sed
wg-quick
# Should come installed when you install Wireguard
# Use your environment manager of choice like virtualenv or conda or poetry to pre-create an environment
pip install nr-wg-mtu-finder==0.2.1 --upgrade
wg0
./etc/wireguard/wg0.conf
. Take a backup of these files.wg-quick up INTERFACE
on both the WG server and WG peer to activate the connection.# Replace 10.2.0.0/24 with your interface's IP range
ufw allow proto tcp from 10.2.0.0/24 to any port 5201
# Replace 10.2.0.0/24 with your interface's IP range
ufw allow proto tcp from 10.2.0.0/24 to any port 5000
Add the MTU setting to the WG conf file i.e. /etc/wireguard/wg0.conf
. Choose any random MTU, it will be replaced by the script anyway:
[Interface]
...
MTU = 1420 # <----- ADD THIS LINE IF NOT ALREADY EXISTS
[Peer]
...
# Example: The script loops through server MTUs from 1280 to 1290 in steps of 2
nr-wg-mtu-finder --mode server --mtu-min 1280 --mtu-max 1290 --mtu-step 2 --server-ip 10.2.0.1
Add the MTU setting to the WG conf file i.e. /etc/wireguard/wg0.conf
. Choose any random MTU, it will be replaced by the script anyway:
[Interface]
...
MTU = 1420 # <----- ADD THIS LINE IF NOT ALREADY EXISTS
[Peer]
...
# Example: The script cycles through peer MTUs from 1280 to 1290 in steps of 2
nr-wg-mtu-finder --mode peer --mtu-min 1280 --mtu-max 1290 --mtu-step 2 --server-ip 10.2.0.1
subprocess.Popen
to run shell commands. The following commands are used and expected to be pre-installed if not already available:
ping
iperf3
wg-quick
sed
flask
server and the peer script uses requests
to communicate with the flask server.MTUFinder.run_server_mode()
.sync_server
is run is the background on a separate process.
sync_server
listens for requests and commands from the peer script so that they can synchronize with each other.sync_server
to be available before running any upload or download tests.sync_server
.sync_server
that it is done with its looping through all of its MTUs and is ready for the server script to change its MTU so that it can start a fresh cycle.sync_server
informs the peer script that the server script is finished with looping through all MTUs and that it is going to shut itself down. The peer script uses this signal to shut itself down as well.INITIALIZE
signal, it runs the following shell commands
iperf3
server process if it is already running.wg-quick down wg0
# 1421 is the new MTU
sed -i s/MTU.*/MTU = 1421/ /etc/wireguard/wg0.conf
wg-quick up wg0
iperf3 -s
SHUTDOWN
signal to the peer script via the sync_server
.sync_server
is reachable. Once it is reachable, it sends a peer/ready
request to the server script.iperf3
server to start on the server side. Once it recognizes that the iperf3 server has started, and then the peer script starts cycling through each of its MTUs.
# Upload test
iperf3 -c 10.2.0.1 -J -t 5 -i 5
# Download test
iperf3 -c 10.2.0.1 -J -t 5 -i 5 -R
peer/ready
request to the server script and restarts the whole process again with the next server MTU.SHUTDOWN
response to the peer script as a reply to the peer/ready
request. The server shuts down after a short delay as does the peer script.wg_mtu_finder_peer_20220101T000000.csv
and is generated in the same directory where the peer script was run.wg_mtu_finder_peer_20220101T000000.png
and is generated in the same directory where the peer script was run.So if you successfully ran the server and peer script, you should find two new files (one csv and one png) generated in the same directory where you ran the peer script on the WG-peer server.
$ nr-wg-mtu-finder --help
usage: nr-wg-mtu-finder [-h] --mode MODE --mtu-min MTU_MIN --mtu-max MTU_MAX --mtu-step
MTU_STEP --server-ip SERVER_IP [--server-port SERVER_PORT]
[--interface INTERFACE] [--conf-file CONF_FILE]
[--peer-skip-errors PEER_SKIP_ERRORS]
nr-wg-mtu-finder - Helps find the optimal Wireguard MTU between a WG Server and a WG Peer.
optional arguments:
-h, --help show this help message and exit
--mode MODE Mode should be 'server' if you are running this script on the WG
Server. Mode should be 'peer' if you are running this script on
the WG Peer.
--mtu-min MTU_MIN Min MTU. Must be in the range [1280, 1500].
--mtu-max MTU_MAX Max MTU. Must be in the range [1280, 1500].
--mtu-step MTU_STEP By how much to increment the MTU between loops.
--server-ip SERVER_IP
The IP address of the WG server and flask server.
--server-port SERVER_PORT
The port for the flask server.
--interface INTERFACE
The WG interface name. Default: 'wg0'
--conf-file CONF_FILE
The path to the interface config file. Default:
'/etc/wireguard/wg0.conf'
--peer-skip-errors PEER_SKIP_ERRORS
Skip errors when known errors occur in 'peer' mode during the MTU
loop. The known errors are logged and the loop continues without
crashing. Default: 'True'. Example usage: --peer-skip-errors False
$ nr-wg-mtu-finder-heatmap --help
usage: nr-wg-mtu-finder-heatmap [-h] --log-filepath LOG_FILEPATH --heatmap-filepath
HEATMAP_FILEPATH
nr-wg-mtu-finder-heatmap - Generate a heatmap file (png) from a log file (csv) that was
created by the `nr-wg-mtu-finder` script. This is useful in case the original script file
crashed midway.
optional arguments:
-h, --help show this help message and exit
--log-filepath LOG_FILEPATH
Absolute path to the log file (csv) that was created by the `nr-wg-
mtu-finder` script.
--heatmap-filepath HEATMAP_FILEPATH
Absolute path to the heatmap file (png) which will be created from
the log file (csv).
pip install poetry==1.1.15
poetry build
poetry publish --dry-run
MIT