Categories
Apple Hardware Linux Misc Networking Software Windows www

Remote desktop and Wake-on-LAN

Shan uses her iPad a lot, but a lot of the more serious (interior design) work needs to happen on AutoCAD or Photoshop. That is just not going to work on an iPad.

When we’re travelling (read: holiday) she’s carrying an old Lenovo ThinkPad 13 (great device!) just “in case” she needs to open AutoCAD and edit something minor or read the drawings/dimensions. But honestly, most of the time that device is turned off and dead weight.

But all the above is just an excuse to “I was bored, and I wanted to test something”: can I use an old Raspberry Pi (zero W) to remotely wake her Intel NUC, and then use Tailscale to use RD on her iPad? Well, yes I can.

I completed this using:

  • Tailscale to remote desktop from anywhere to home
  • Cloudflare Tunnels, Access and DNS to have a web interface to wake the desktop
  • A Linux device that’s always on and in the same LAN, and that’ll run a PHP script.

Prep work: enable WOL

First off: enable Wake-on-LAN (WOL) in the BIOS and in your Windows settings. This article explains it for Intel NUCs, but would be similar enough for most devices. The Device Manager pane looked different on our i5 NUC, but was close enough.

On Mac, you just need to enable it in the Energy preference pane, for Linux I have no clue. 🤷‍♂️

Second step: have a working Raspberry Pi (or any Linux device) in the same LAN. This device needs to be turned on 24/7, so use something that uses very little power.

I do have a more powerful RPi4 I wish I could've reused (running Docker and some other "serious" stuff; however it's currently in a different VLAN, and it's quite crucial the Linux device is in the same LAN as the device(s) you want to wake up), so I went with an old Raspberry Pi Zero W that was collecting dust (it used to run pwnagotchi).

On the Linux device, install etherwake. The command to run is quite simply etherwake aa:bb:cc:11:22:33 (= the ethernet MAC address of your device).

If this doesn’t wake your desktop, something is wrong and there’s no point continuing. Go and troubleshoot.

Install Tailscale and RD

On the (Windows) desktop and your iPad, install Tailscale. Login, and make sure it works by pinging from one to the other.

Then set up Remote Desktop on both (Windows, iPad). You should test and make sure you can properly connect using the LAN IP address and then the Tailscale IP address.

Fun fact: I create a DNS record for all my devices using Cloudflare DNS with the syntax of device-name.ts.yeri.be, so I don't need to ever remember IPs, and can easily ssh or ping devices without having to look up IPs. 
Cloudflare DNS screenshot, filtered on “ts”. I add both A and AAAA records (not shown in the screenshot)
Fun fact side track: I actually have a dynamic script that runs (on Linux) and creates hostname.ts.yeri.be for the Tailscale IP, hostname.wg.yeri.be based on the Wireguard IP, hostname.lan.yeri.be based on the LAN IP. This dyndns script runs every so often and updates IPs if needed. All this is running using Cloudflare DNS and their API. Super convenient.

Nginx, php and etherwake

I'm a 80s kid, so I'll use dirty PHP to run this script. I'm sure I'll go straight to hell for this, but yolo.

Install nginx and PHP (no need for MySQL and other stuff).

etherwake requires root to run (because it needs root access to create a weird magic ethernet packet). Create a file in /etc/sudoers.d/etherwake and add this line:

www-data ALL=(ALL) NOPASSWD: /usr/sbin/etherwake

This will allow www-data (nginx/php) to run /usr/sbin/etherwake using sudo, without password.

In /var/www/html/ create an index.php file with:

<html>
<head><title>Wake on Lan</title></head>
<body>
<p>Wake up <a href="mycooldesktop.php">My Cool Desktop</a>
</body>
</html>

And a mycooldesktop.php (or whatever) file with:

<?php
$output = shell_exec('sudo /usr/sbin/etherwake aa:bb:cc:11:22:33 2>&1');
echo "<pre>$output</pre>";
?>
<p><a href="..">Back</a></p>
It ain't pretty -- but it gets the job done. 

And be sure to edit the MAC address to match your desktop’s ethernet MAC address.

Cloudflare tunnels

Install Cloudflare Tunnel (via Zero Trust dashboard).

When creating a new tunnel, the dashboard will give you all needed commands to install the tunnel on your RPi — but be sure to select the right OS/architecture (arm64? arm? armhf?).

Easy.

And then point the tunnel to http://localhost. No need to mess around with SSL certs.

Lastly, set up Cloudflare Access (via the same Zero Trust dashboard): create a new application, and make sure only approved users can sign in (i.e.: using a pin code emailed to only approved emails).

I only allow access to my own emails, and my family, by using groups.

You can try it yourself via wol.superuser.one. You won’t get in. 🙂

Optionally, but recommended: lock down Nginx to only allow connections from localhost (127.0.0.0/8 and ::1) if using Cloudflare Tunnels, or Cloudflare IPs if using port forwarding with Cloudflare Access in front. 
Love my design skills… But it gets the job done: click that link, and it’ll execute etherwake.

To recap

  • We used Tailscale to create a VPN network between the desktop and the iPad. The big benefit is that Tailscale works effortlessly across NAT networks without having to open ports,
  • We used Cloudflare DNS so we don’t need to remember hostnames :),
  • We used Cloudflare Tunnels to make sure the RPi web interface is accessible across NAT (without port forwarding) and from anywhere,
  • We used Cloudflare Acces and locked down access to the right people using ACLs,
  • We used etherwake running on a RPi to wake up devices that are hibernating or turned off.

And that’s it really.

PS: technically WoL works with WiFi, but when I enabled WoL on the WiFi adapter, the NUC refused to hibernate/sleep for more than a minute, and kept waking itself up. So, there seems to be some kind of trigger in my network that keeps waking it up. Also, not sure if WoL via WiFi would work if the device is turned off (as opposed to sleep or hibernate). I just ended up using ethernet. 

PPS: both Cloudflare Tunnels and Tailscale use Wireguard tech in the background, so that's really cool. 
Categories
Linux Networking Software

WireGuard

This is the first post of several. Next posts will focus on running WireGuard inside a Docker container on amd64 Linux and a Raspberry Pi.

I’ve been running WireGuard for a few months now and I’ve been loving it.

I first started using it about a year ago when in China — OpenVPN was once again being actively blocked and it was driving me nuts. Overnight I set up a DigitalOcean server in Singapore and ran WireGuard from it — both my phone and laptop were able to actively bypass the GFW and (at that time) surf the internet freely once more. As WireGuard gains popularity, I am sure the GFW will start detecting it — it’s a quiet but not a stealthy protocol.

Since then I’ve dug quite a bit deeper in WireGuard and am really looking forward to what it’s going to bring.

WireGuard differentiates itself to be an extremely simple VPN server (which can make getting started and debugging a bit more challenging) — but it wants to seamlessly work together with existing tools. One of the main features still missing is for example running a DHCP server on the server and dynamically assigning IPs (like oVPN does).

WireGuard network
Simplified diagram of my network. Using static routing my clients can access the WireGuard network even without running WireGuard directly. (Some of) my containers are also able to access the network, this allows me to run Resilio Sync over WireGuard. It’s using one big subnet to create one big LAN.

It’s also pretty cool because any node can both be a server and a client at the same time. In my setup I am running two servers: one running at home in Singapore on a RPi4 (1Gbit fiber connection) and one on a virtual machine in Amsterdam (1Gbit as well). The RPis at my parents are connected to the server in Amsterdam, my iPad and phones are connected to the server in Singapore. If I am in Europe I might switch over and let my iDevices connect to the AMS server instead.

WireGuard and traffic shaping
Click to enlarge.
Bandwidth stats from Resilio Sync, transferring several big files. We can clearly see a speed increase (from 2-5mb/s to 11mb/s) when routing the exact same traffic over WireGuard. Traffic shaping at its best.

The example above clearly shows speed gains by cloaking the traffic in UDP packets. The shared folder has only two nodes (sender and receiver) and shows several big files being transferred from Amsterdam to Singapore. Resilio Sync uses the Bittorrent protocol, something ISPs generally hate and tend to slow down as much as they can — thanks Starhub.

Wireguard also allows the client to decide what to route through the server: only the VPN LAN traffic, or a whole subnet, or 0.0.0.0/0? So for my iPhone I for example route all traffic through VPN to avoid hotel/airport/… WiFi’s to mine/log/scan my data. For my laptop I have two configs, one to only connect to the LAN, but another that routes all my traffic through the VPN if I want to avoid exposure or circumvent censoring.

Note that I am not running WireGuard to remain anonymous and I’ll definitely leak some information — just trying to minimise and remain in control of what I leak. This is not a Tor replacement.

Categories
Apple Linux Networking Software Virtualisation

Box — Docker shell server

A couple of months ago I had the great idea to set up a shell server in Docker. Simply because my docker skillz were quite rusty and a shell server was something I actually genuinely needed.

Shell servers… so 2005. I remember in the good old IRC days people asking for (free) shell servers to run their eggdrop and stuff. OMG am I getting old? Anyhow…

I ssh quite often. I manage quite a few servers (~15?) and routers that require me to login and do some random stuff. I also work on a laptop quite often and that means closing the lid and moving around.

First of all, mosh is amazing and allows you to stay connected via ssh, even with crappy (airport/hotel) internet as well as moving around networks — that solves half the problem. If you are not using it, start using it now!

Second, during my datacenter technician days at Google we used to have a “jump server” — a shell server that allowed us to bridge the corporate network and ssh into prod machines. Doubt that’s still used nowadays, but the idea stuck. I wanted something similar to ssh from, wherever I was, and easily connect to my servers. And as the network the shell server is running on is stable, I only need to use mosh to the shell server. Thereafter, the connection very rarely dies.

And I guess, third, I recently purchased an iPad Pro and I really need to have my local “dev” environment with my git repo that I edit quite frequently but iPadOS isn’t really your average computer, and doesn’t even have a proper terminal. This is my experiment to make iPadOS work as a main computer when on the move.

Enter box — Docker shell server

I’ve copied over the files I use to this example repo, and added some comments. Mind you that this repo acts as a proof of concept and isn’t kept up to date, as I have my own private repo — but this should give you a good idea on how to set up your own shell server with Docker.

start.sh — this is a simple script that I execute when I first run or need to update the container. I execute the same file on two different servers: Liana, my Raspberry Pi at home and Ocean, my server in Amsterdam.

zsh.sh — this installs what I care about for zsh. This could be part of the Dockerfile but for some reason I separated it. ¯\_(ツ)_/¯

git.sh — this clones my Git repos so I can edit and commit stuff from the shell server.

run.sh — this file is launched by Dockerfile at the end and executes what matters: the ssh daemon. It also adds a Wireguard route and executes the scripts above.

Dockerfile — this installs everything I need and configures the whole thing. I’ve added tons of comments that should get you going.

I am also cloning misc and homefiles as submodules in files/ — but you should change this to something that works for you. See the Dockerfile for more info.

Categories
Hardware Linux Networking

Edgerouter IPsec tunnel to Fritzbox

So, I have an EdgeRouter Lite in Singapore (Starhub) and a FritzBox in Belgium (EDPnet).

This is mostly stuff that I have found from several articles, mostly from here.

ERL: eth0 is WAN, eth1 (10.60.111.0/24) and eth2 (unused, not VPN’ed) are LAN
FritzBoz: 192.168.1.0/24

This is the FritzBox config (go to VPN and them Import a config) fritzvpn.cfg:

vpncfg {
        connections {
                enabled = yes;
                conn_type = conntype_lan;
                name = "VPN Yeri";
                always_renew = yes;
                reject_not_encrypted = no;
                dont_filter_netbios = yes;
                localip = 0.0.0.0;
                local_virtualip = 0.0.0.0;
                remoteip = 0.0.0.0;
                remote_virtualip = 0.0.0.0;
                remotehostname = "erl.yeri.be";
                localid {
                        fqdn = "fritz.yeri.be";
                }
                remoteid {
                        fqdn = "erl.yeri.be";
                }
                mode = phase1_mode_idp;
                phase1ss = "all/all/all";
                keytype = connkeytype_pre_shared;
                key = "SOMEPASSWORD";
                cert_do_server_auth = no;
                use_nat_t = yes;
                use_xauth = no;
                use_cfgmode = no;
                phase2localid {
                        ipnet {
                                ipaddr = 192.168.1.0;
                                mask = 255.255.255.0;
                        }
                }
                phase2remoteid {
                        ipnet {
                                ipaddr = 10.60.111.0;
                                mask = 255.255.255.0;
                        }
                }
                phase2ss = "esp-all-all/ah-none/comp-all/pfs";
                accesslist = "permit ip any 10.60.111.0 255.255.255.0";
        }
        ike_forward_rules = "udp 0.0.0.0:500 0.0.0.0:500", 
                            "udp 0.0.0.0:4500 0.0.0.0:4500";
}

Be sure to modify the password, local (Fritz) and remote (ERL) LAN and edit the local and remote fqdn.

This is the ERL config (via ssh, you’ll need to set this:

[email protected]# show vpn ipsec 
 auto-update 60
 auto-firewall-nat-exclude enable
 esp-group FOO0 {
     proposal 1 {
         encryption aes256
         hash sha1
     }
 }
 ike-group FOO0 {
     dead-peer-detection {
         action restart
         interval 60
         timeout 60
     }
     lifetime 3600
     proposal 1 {
         dh-group 2
         encryption aes256
         hash sha1
     }
 }
 ipsec-interfaces {
     interface eth0
 }
 nat-networks {
     allowed-network 0.0.0.0/0 {
     }
 }
 nat-traversal enable
 site-to-site {
     peer fritz.yeri.be {
         authentication {
             mode pre-shared-secret
             pre-shared-secret SOMEPASSWORD
         }
         connection-type initiate
         description "VPN to fritz.yeri.be"
         ike-group FOO0
         local-address erl.yeri.be
         tunnel 1 {
             esp-group FOO0
             local {
                 prefix 10.60.111.0/24
             }
             remote {
                 prefix 192.168.1.0/24
             }
         }
     }
 }

Status:

[email protected]:~$ show vpn ipsec status
IPSec Process Running PID: 20140

1 Active IPsec Tunnels

IPsec Interfaces :
        eth0    (no IP on interface statically configured as local-address for any VPN peer)
[email protected]:~$ show vpn ipsec sa
peer-be.yeri.be-tunnel-1: #9, ESTABLISHED, IKEv1, 85a2d010ada73113:ca439c40ac3bca06
  local  'erl.yeri.be' @ 116.87.x.y
  remote 'fritz.yeri.be' @ 109.236.x.y
  AES_CBC-256/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_1024
  established 1592s ago, reauth in 1333s
  peer-fritz.yeri.be-tunnel-1: #1, INSTALLED, TUNNEL, ESP:AES_CBC-256/HMAC_SHA1_96/MODP_1024
    installed 1592 ago, rekeying in 1200s, expires in 2009s
    in  c0bb652e, 1038032 bytes, 10726 packets,     0s ago
    out 8d5df3f5, 532685 bytes,  6062 packets,     0s ago
    local  10.60.111.0/24
    remote 192.168.1.0/24

I haven’t really figured out what no IP on interface statically configured as local-address for any VPN peer means yet though.

Next up: VLANs

Categories
Errors Linux Networking Software

OpenVPN packet drops

I recently started to notice following error messages on my openVPN server.

ovpn-server[6306]: vpn.rootspirit.com/85.234.x.y:62068 MULTI: packet dropped due to output saturation (multi_process_incoming_tun)

This basically means that the TUN or TAP interface is making more packets than the real (TCP) interface can handle.

As I need to run OpenVPN using the TCP protocol (instead of the faster UDP protocol; as UDP is often blocked in networks I use my VPN in) I experimented by increasing the tcp-queue-limit. The default is 64, and I’ve set it to 256. So far, everything still seems to be working fine (but more packets will be queued before being dropped by OpenVPN, requiring less retransmissions).

Add this to the OpenVPN server config:

tcp-queue-limit 256

And restart the daemon.