published on Friday, February 24, 2017
In VPN in a Nutshell I have described a command
prefix vpnbox. This precommand executes applications in a network
namespace but does not take care to check if VPN is already up and
automatically start if it is not.
Unfortunately, I know no good (simple) way to do this. Please tell me if
you've got any better solutions.
First, modify the vpnbox command as follows:
# check if there is a default route in the netns going over tun0:
# NOTE: 'tun0' may not be the correct interface name
sudo ip netns exec vpn sudo -u $user -- ip route \
| grep default | grep tun0
if ! vpn_online; then
# Execute openvpn in daemon mode:
sudo /bin/openvpn --config /etc/vpn/CONFIG.conf --daemon
# Wait for completion. Otherwise routes/DNS information may not be
# setup when the main program starts:
echo "Waiting for route."
while ! vpn_online; do
# Execute the actual command as before:
sudo ip netns exec vpn sudo -u $user -- "$@"
To make this work without passwords, type sudo visudo to add the following
to your sudoers:
# put this near the end of the file:
# this line is unchanged from the previous post:
alice ALL=(ALL:ALL) NOPASSWD: /usr/bin/ip netns exec vpn sudo -u alice -- *
# The following line is new and allows to start the vpn without password:
alice ALL=(ALL:ALL) NOPASSWD: /usr/bin/openvpn --config /etc/openvpn/CONFIG.conf --daemon
WARNING: You must specify the exact line here. You must not use the *
as a lazy shortcut here, otherwise a user can specify as additional parameters
any script and it will be executed as root.
Personally, I'm using another (more complex) solution that does not provide
much benefit over the simpler one given above. But since I've gone through the
development effort and learnt something from it and also it's slightly nicer,
I cannot let go yet.
The difference is that it does print some output of the openvpn command to
standard output and can exit early if an error occurs during the
This is accomplished by exchanging the plain sudo openvpn statement in the
vpnbox script above by the crazier command:
sudo openvpn-daemonize /etc/openvpn/CONFIG.conf || exit 1
Huh? This wasn't so bad, was it?
Yeah, but you will also have to provide the openvpn-daemonize script. This
time I highly recommend to put it actually in /usr/local/bin and not in a
user path. Make it writable by root only (because we are executing it with
# Truncate log file to make sure it doesn't contain remnants
# Start VPN in background, this does not block
/bin/openvpn --config $config --log $log --writepid $writepid --daemon
# Create a temporary pipe that will be used to connect the standard IO of
# the next two processes
# Search for markers in the fifo stream, quit with exit code when found
sed -e '/Initialization Sequence Completed/q0' \
-e '/Connection refused/q1' <$pipe & sed_PID=$!
# Follow the log, write output to pipe, but also exit when 'sed' exits
tail -n +0 -f $log --pid $sed_PID >> $pipe
# Cleanup and exit
Also, convenience demands to add the following additional line in sudoers:
alice ALL=(ALL:ALL) NOPASSWD: /usr/local/bin/openvpn-daemonize /etc/openvpn/CONFIG.conf