Mullvad VPN setup guide

It is not that simplistic like you make it out to be either. I am making a new guide on how to set up Lokinet on Qubes right now and I just ran into a perfect example of why using the /rw/config/rc.local file is not proper.

For context:

  • Lokinet wants DNS to be managed by resolvconf.
  • resolvconf works by symlinking /run/resolvconf/resolv.conf /etc/resolv.conf
  • qubes-network-uplink overrides this by adding its own /etc/resolv.conf.

So what is the solution to this? We need to run the following after qubes-network-uplink.service finishes starting up:

rm -rf /etc/resolv.conf
ln -s /run/resolvconf/resolv.conf /etc/resolv.conf

With a systemd service, this is very simple to do: Just use After=qubes-network-uplink.service as a start condition for the service that will run those commands. Nice, simple, easy and with guarantees that it will only be started AFTER qubes-network-uplink.service has started successfully.

What about the rc.local file?

It is started by qubes-post-misc.service, which has the following conditions:
After=network-pre.target
After=qubes-mount-dirs.service
After=qubes-network.service
After=qubes-firewall.service

These start conditions do not guarantee that the commands will be executed qubes-network-uplink.service has started. In fact, if you were to make a systemd service with these conditions, it will run before qubes-network-uplink.service, and have its resolv.conf overwritten by qubes-network-uplink.service.

The only reason this suggestion with rc.local even works is that qubes-post-misc.service also invokes:

. /usr/lib/qubes/functions

/usr/lib/qubes/update-proxy-configs

These happen to take long enough to run that the commands in rc.local get executed after qubes-network-uplink.service. It’s just pure luck.

This is not how proper dependency resolution works on any system that’s supposed to be reliable. You should not be engineering something that relies on luck like this to run. Stuff like this are why rc.local is deprecated almost everywhere.