jik<p><strong>Sysadmin journal: setting up wireguard on all of my Linux desktops</strong></p> <p>I have several mostly interchangeable Linux computers for personal use. All but one are laptops; the mini-tower which isn’t is used as both a desktop and my home network server, e.g., for DNS and for SSHing into the home network from the outside when I’m traveling with one of the laptops.</p><p>A pro-democracy activist group that I’m part of has asked everyone in the group to use a VPN whenever accessing group stuff online (including Signal, Matrix, Proton, etc.) and has recommended using a VPN all the time. I am not convinced this is worth the effort, but it probably can’t hurt, and I don’t want to be the Guy Who Wasn’t Following The Rules if something does end up going down, so today I set out to make this happen.</p><p>I signed up for a VPN service that uses wireguard (no, I’m not going to tell you which one, that would be giving away information unnecessarily) and set out to figure out how to set up this VPN to be active all the time on my phone and all of my Linux computers. Below are my notes about the bumps in the road I hit while figuring this out and how I got over them.</p><p>The VPN service I signed up with has a bespoke Android client so setting it up for Android was trivial.</p><p>The service allowed me to add other devices to my account and download a standard-format wireguard configuration file for each, to be imported into wireguard, which I was able to do easily in NetworkManager on Debian after installing the wireguard package (I’m actually not 100% certain that it was necessary to import the wireguard package, I think it may have worked even if I hadn’t done that):</p><ul><li>Open Settings app</li><li>Click on Network</li><li>Click the + symbol next to VPN</li><li>Click Import from file…</li><li>Select the wireguard configuration file I downloaded from the VPN service</li></ul><p>I wanted to configure the VPN to connect automatically. You can’t do that from the Settings app but you can do it from <code>nm-connection-editor</code> or <code>nmcli</code>. In the connection editor:</p><ul><li>Open <code>nm-connection-editor</code>, a.k.a., the “Advanced Network Configuration” desktop app</li><li>Double-click on the imported VPN</li><li>Click on the General tab</li><li>Check the “Connect automatically with priority” checkbox</li><li>Save and exit</li></ul><p>In <code>nmcli</code>, you can do “<code>nmcli connection modify <em>[connection-name]</em> connection.autoconnect yes</code>“.</p><p>I configure all my Linux machines via Ansible, so I wanted to figure out how to do the wireguard VPN configuration automatically using the <code>nmcli</code> Ansible module, i.e., I wanted to do the import as described above manually the first time and then figure out how to replicate in Ansible code what the manual import did so I wouldn’t have to do it manually in the future. Unfortunately, though the documentation claims this should be possible, for some reason I don’t have the ability to specify <code>wireguard.peers</code> to the module, so I can’t do the configuration automatically. Therefore, I set up an Ansible rule that checks if the VPN is configured and fails if it isn’t, so that I am reminded to configure it manually if/when I’m setting up a new computer:</p> <pre> - name: make sure wireguard VPN is configured and autoconnect is on nmcli: conn_name: "{{wireguard['vpn_name']}}" autoconnect: yes state: present register: nmcli check_mode: true failed_when: nmcli.changed or 'Exists' not in nmcli</pre> <p>Next, I had to deal with the fact that when I enabled the VPN on my desktop, my <code>ddclient</code> configuration stopped getting my correct public IP address and instead started putting the egress IP of my VPN into my dynamic DNS entry. The reason for this is obvious. I told <code>ddclient</code> to <code>use=web, web=http://checkip.dyndns.com/</code>, and that is obviously going to go through the VPN and get the VPN’s IP rather than mine. I don’t know if the fix I came up with is the best one, but it works: <code>use=cmd, cmd='curl --silent --interface enp2s0 http://checkip.dyndns.com/ | perl -ne \'chomp; if (s/.<em>\b([1-9][0-9]</em>\.[1-9][0-9]<em>\.[1-9][0-9]</em>\.[1-9][0-9]<em>)\b.</em>/$1/){print;exit}\''</code></p><p> Next problem: I need to be able to log into my home desktop from outside the house. Solution: add routing policy rules on my home desktop so that traffic to/from our family server in the cloud bypasses the VPN, so that I can SSH into the cloud server from anywhere and then SSH into the home desktop from the cloud server. I deployed a script to <code>/etc/NetworkManager/dispatcher.d</code> to add the routing rules when the VPN comes up and remove them when it comes down. The commands the script runs look like this:</p> <pre>ip -4 rule add from [server IP] table mainip -4 rule add to [server IP] table main</pre> <p>It specifies “del” instead of “add” to remove the rules. I figured this out with the help of <a href="https://www.reddit.com/r/WireGuard/comments/o6lgnm/how_do_i_use_wireguard_for_outgoing_connections/" rel="nofollow noopener" target="_blank">this Reddit posting</a>. Note that this needs to be a dispatcher script because NetworkManager ignores <code>PostUp</code> and <code>PreDown</code> lines in wireguard configuration files when importing them, and as far as I can tell there is no way to configure directly in NetworkManager commands to be run when an interface goes up or down.</p><p>Final challenge: when I am working on one of my laptops and I need to SSH into my desktop, I want to do so directly via the private IP address on the home network when I’m at home, or indirectly through my cloud server when I’m out of the house, and I want this to happen automatically. Fortunately, I already had a NetworkManager dispatcher script which automatically generates ah SSH configuration file that’s included by my main SSH configuration. The old purpose of this script was so that when I’m out of the house with laptop A and I want to SSH into laptop B, which is on my home network but not accessible from the outside, that SSH automatically gets proxied through my desktop, which <em>is</em> accessible from the outside. I was able to augment this script to add the new functionality. Now whenever one of my laptops connects to my home network, the script adds to my SSH config a <code>Host</code> section for the desktop with a <code>HostName</code> line in it specifying the internal domain host name which resolves to its internal IP address, whereas when the laptop connects to a network outside my home, instead of the <code>HostName</code> line it adds a <code>ProxyJump</code> line specifying the host name of my cloud server.</p><p>If you’re one of the two people in the world who read this blog posting all the way to the end, drop a comment and let me know. 😉</p> <a class="" href="https://www.addtoany.com/add_to/mastodon?linkurl=https%3A%2F%2Fblog.kamens.us%2F2025%2F05%2F10%2Fsysadmin-journal-setting-up-wireguard-on-all-of-my-linux-desktops%2F&linkname=Sysadmin%20journal%3A%20setting%20up%20wireguard%20on%20all%20of%20my%20Linux%20desktops" rel="nofollow noopener" target="_blank"></a><a class="" href="https://www.addtoany.com/share" rel="nofollow noopener" target="_blank"></a> <p><a rel="nofollow noopener" class="hashtag u-tag u-category" href="https://blog.kamens.us/tag/ansible/" target="_blank">#Ansible</a> <a rel="nofollow noopener" class="hashtag u-tag u-category" href="https://blog.kamens.us/tag/ddclient/" target="_blank">#ddclient</a> <a rel="nofollow noopener" class="hashtag u-tag u-category" href="https://blog.kamens.us/tag/linux/" target="_blank">#Linux</a> <a rel="nofollow noopener" class="hashtag u-tag u-category" href="https://blog.kamens.us/tag/networkmanager/" target="_blank">#NetworkManager</a> <a rel="nofollow noopener" class="hashtag u-tag u-category" href="https://blog.kamens.us/tag/sysadmin/" target="_blank">#sysadmin</a> <a rel="nofollow noopener" class="hashtag u-tag u-category" href="https://blog.kamens.us/tag/vpn/" target="_blank">#VPN</a> <a rel="nofollow noopener" class="hashtag u-tag u-category" href="https://blog.kamens.us/tag/wireguard/" target="_blank">#wireguard</a></p>