Wgjail-quick gives you the ability to create a "Wireguard jail," i.e., a network namespace where a program running inside that namespace can only see and use the one WireGuard connection you have given it. There are two main reasons you would want to do this:
- For split tunneling, which means that only some of the programs on your PC shall use the WireGuard VPN, while the rest use your normal network connection.
- To prevent a program from using your normal internet connection in case the WireGuard VPN connection is shut down or crashes (a killswitch).
Wgjail-quick is based on the ideas of wgjailr (https://github.com/moismailzai/wgjailr). Many thanks to Mo Ismailzai for writing wgjailr.
So, why wgjail-quick then? Because I wanted something that:
- Has a similar syntax to wg-quick, because people already use wg-quick and are used to that syntax.
- Can be packaged for a Linux distribution (wgjailr can't really, because it needs some variables to be set in the script file itself).
TLDR:
socat wireguard-tools bubblewrap
- You need wireguard-tools.
- If you want to forward a port into the namespace, you also need socat.
- If you want to use the exec command, you also need bubblewrap (bwrap), which is necessary to map the resolv.conf file with the IP of your WireGuard VPN's DNS server to the correct location where programs expect it (/etc/resolv.conf). Bubblewrap is not needed for a cmd-service, as systemd itself can map the resolv.conf file to the correct location. Why this added complexity? Well, I doubt you would want a DNS leak. This is why. I got your back.
- Everything else should already be on your system.
Just copy the "wgjail-quick" file to /usr/bin and make sure it is executable.
To uninstall, just: rm /usr/bin/wgjail-quick
I wrote wgjail-quick with packaging for Linux distributions in mind, so please feel free to do so for whatever distribution you would like.
I have now made a Copr repository:
https://copr.fedorainfracloud.org/coprs/best-heygman/wgjail-quick/
In the future, I would like to maintain the package directly in the Fedora / EPEL repositories. No timeframe for that yet.
wgjail-quick [ up | down ] [ CONFIG_FILE | INTERFACE ]
wgjail-quick exec [ CONFIG_FILE | INTERFACE ] USERNAME CMD_LINE
wgjail-quick portforward [ CONFIG_FILE | INTERFACE ] LISTEN_ADDRESS FORWARDED_PORT [ DESTINATION_PORT ]
wgjail-quick generate-jail-service [ CONFIG_FILE | INTERFACE ]
wgjail-quick generate-cmd-service [ CONFIG_FILE | INTERFACE ] CMD_LINE
wgjail-quick generate-portforward-service [ CONFIG_FILE | INTERFACE ] LISTEN_ADDRESS FORWARDED_PORT [ DESTINATION_PORT ]
CONFIG_FILE is a path to a WireGuard configuration file. Using an absolute path is a good idea.
INTERFACE is a WireGuard config file that is in /etc/wireguard, which means you only have to write, for example, "p2p" to use the WireGuard config file /etc/wireguard/p2p.conf.
The portion of the config file's basename before the .conf is the name that will be given to:
- the network namespace (the "WireGuard jail") and
- the WireGuard interface inside the network namespace.
CMD_LINE is a command with command-line arguments that you want to execute in the namespace.
Creates a new network namespace with a WireGuard interface defined in the given config file.
Removes the given network namespace.
Executes a command in the given network namespace.
USERNAME is the username or UID of the user that shall execute the given command.
Forwards a port into the network namespace. You have to specify which address to listen on and which port to forward. Use 0.0.0.0 to listen everywhere.
Optionally, you can also define a destination port inside the network namespace that is different from the port on which the host system listens. If not given, the same port is used.
Generates a systemd service that creates a network namespace, like with the up command. Result will be saved to the current directory (./wgjail-NAMESPACE.service).
This service will expect to find the configuration file at the same absolute path on every start. Make sure you generate the service either with the absolute path to where the config file will be permanently, or, if you plan to put the config file into '/etc/wireguard/CONFIG_FILE.conf', it is enough to give the filename before the '.conf' without any path.
Generates a systemd template service that starts the given command inside the given network namespace, like the exec keyword.
When you start this service, make sure you append the username that shall run the command after the '@' symbol, e.g. 'systemctl start wgjail-NAMESPACE-CMD@myuser.service'. Result will be saved to the current directory (./wgjail-NAMESPACE-CMD@.service).
CMD will be substituted by the name of the command. The parameters will not be inserted into the filename. If you want to create multiple services for the same command, you have to rename them manually.
The network namespace this service references must also be started via a systemd service (e.g., with a service generated by the "generate-jail-service" command), so systemd can make sure the jail already exists before it tries to execute this command inside the jail. This cmd service will bind to the jail service and will automatically be stopped if the jail service is stopped.
Generates a systemd template service that forwards a port into the network namespace (the WireGuard jail).
Result will be saved to the current directory ('wgjail-NAMESPACE-portforward-LISTEN_ADDRESS-FORWARDED_PORT.service').
Optionally, you can also define a destination port inside the network namespace that is different from the port on which the host system listens. If not given, the same port is used.
The network namespace this service references must also be started via a systemd service (e.g., with a service generated by the "generate-jail-service" command), so systemd can make sure the jail already exists before it tries to execute this command inside the jail. This cmd service will bind to the jail service and will automatically be stopped if the jail service is stopped.
If you want to, for example, just quickly torrent an ISO of Hannah Montana Linux, which is not a metaphor for something else, and you want to make sure your torrent client only uses a VPN connection and under no circumstances your normal internet connection, while the rest of your system continues as normal, you can do it this way:
sudo wgjail-quick up /path/to/<wireguard_config>.conf
sudo wgjail-quick exec /path/to/<wireguard_config>.conf <your_username> qbittorrent
When you're done, close the qbittorrent window, then:
sudo wgjail-quick down /path/to/<wireguard_config>.conf
Done. Very easy.
If you want to start a container inside the network namespace, you can do it (with podman) like this:
sudo podman run --network ns:/var/run/netns/<NAMESPACE> ...
This will also automatically use the correct resolv.conf for the namespace.
If you write a Quadlet, then adding this option is enough:
Network=ns:/var/run/netns/<NAMESPACE>
This also uses the correct resolv.conf automatically.
If you now, for example, have set up a dedicated server to seed your Hannah Montana Linux ISO image, you can, with wgjail-quick, create systemd files that automatically, on boot:
- create the WireGuard jail, then
- start qbittorrent-nox (nox means webUI, so you can connect to your server via a web browser and use qbittorrent that way), then
- forward a port into the WireGuard jail so you can access the web interface of qbittorrent:
wgjail-quick generate-jail-service /path/to/<wireguard_config>.conf
wgjail-quick generate-cmd-service /path/to/<wireguard_config>.conf /usr/bin/qbittorrent-nox -d --webui-port=6969
wgjail-quick generate-portforward-service /path/to/<wireguard_config>.conf 0.0.0.0 6969
Now you can copy these systemd files to /etc/systemd/system and enable them. The filenames are different depending on how you named your WireGuard conf file (just like wg-quick sets the name of the interface it creates according to the filename of the .conf file). If, for example, your WireGuard config file was named "my-wg.conf" and the username with which you want to start the qbittorrent server is "myuser", then you can copy and start the services, for example, like this:
sudo cp wgjail-my-wg.service wgjail-my-wg-qbittorrent-nox@.service wgjail-my-wg-portforward-0.0.0.0-6969.service /etc/systemd/system
sudo systemctl enable --now wgjail-my-wg.service wgjail-my-wg-qbittorrent-nox@myuser.service wgjail-my-wg-portforward-0.0.0.0-6969.service
- Maybe make an "exec-gui" command
- Some GUI applications will not work or will not work properly when started with the exec command inside a wgjail. The problems for GUI programs are:
- No connection to D-Bus
- Audio does not work
- Some applications are OK with that, like qbittorrent. Others, like Firefox, won't even start.
- So, I would like to keep the "exec" command the way it works right now and not pile a lot of magic on top, but adding an "exec-gui" command that does that magic would probably be a nice thing to have for many users.
- Some GUI applications will not work or will not work properly when started with the exec command inside a wgjail. The problems for GUI programs are:
- More info on containers and network namespaces, in addition to rootful podman.
- Does this also work with Docker?
- Is there a way to make it work with a rootless podman container?
This is actually pretty neat. Now I don't have to update both. First, copy the "Usage," "Commands," and "Usage Examples" parts to a new markdown file (e.g., tmp.md). Then use pandoc:
pandoc tmp.md -s -o wgjail-quick.8 -t man
SPDX-License-Identifier: CC0-1.0+
© 2024-2025 Stephan Hegemann