Using Tailscale on Windows to network more easily with WSL2 and Visual Studio Code
Tailscale is a zero config mesh "VPN" that runs atop other networks and effectively "flattens" networks and allows users/services to more easily (and securely) communicate with each other.
For example, I've written extensively on how to SSH into WSL2 on Windows 10 from another machine and you'll note that there is not only a ton of steps but there's more than one way to do it!
I have talked about this for SSH, but if you're an active developer and want to share the services and sites you're working on with your coworkers and collaborators, there's a non-trivial amount of setup, management, and maintenance to deal with.
Phrased differently, "wouldn't it be easier if we were all just on the same network and subnet?"
WSL1 shares its networking stack with Windows 10, so the "machine" is the same. Whatever YourMachineName is, running a service on 5000 is the same if it's a Windows service or an app running in Linux under WSL1. However, in WSL2, your Linux environment is "behind" your Windows host. While WSL2 makes it easy to hit http://localhost:5000 by transparent port-forwarding, your WSL2 Linux machine isn't really a peer on the same network as your other devices.
Using a zero-configuration networking system like Tailscale (and similar services) levels the playing field - and the network. Due to some characteristics of WSL2 there are a few gotchas. Here's how I got it working for me.
Tailscale on WSL2
- Install WSL2 - follow the instructions here
- Install a Linux distro - I used Ubuntu 20.04
- go through the process, make a user, etc.
- Install the Windows Terminal - It's just so much better, and really makes your command line experience better
- I can't get Tailscale today to startup on WSL2 with ipv6 install, so I disable it.
sudo sysctl -w net.ipv6.conf.all.disable_ipv6=1
sudo sysctl -w net.ipv6.conf.default.disable_ipv6=1
Here you startup the daemon. There's no systemd (yet) on WSL2, but if you're on a version over Windows 10 build 21286, there are ways run commands on startup in the Windows Subsystem for Linux. Personally, I just do this in a bash script.
WSL doesn't have a way to do an interactive login process, so you wan tot create a pre-authentication key to authenticate a single machine. Then use that key, as I do here, to bring up Tailscale within WSL:
tailscale up --authkey=tskey-9e85d94f237c54253cf0
I like to keep this open in another Terminal Tab or Window Pane so I can watch the logs. It's interesting and verbose!
Within the Tailscale machines admin panel, you can see all the machines living on your new Tailscale network. Note that I have scottha-proto listed as Windows, and scottha-proto-1 listed as Linux. The first is my Host machine and the second (the -1) is my Linux WSL2 instance! They are now on a flat network!
I was also able to invite a user from outside my network with the new (coming soon) Tailscale node sharing feature. My friend Glenn is NOT in my organization, but just like I use OneDrive or DropBox to create a link to access ONE entity but not the WHOLE system, I can do the same here.
Now I can have Glenn hit a service running in WSL2 from his house.
Make a Service and Bind it to the Tailscale Network
I've installed .NET 5 in my WSL2 Ubuntu system, made a folder, and run
dotnet new web to make a Hello World microservice.
When I run the service - .NET or Node, or whatever - it essential that the service listen on the Tailscale network. Your Linux system in WSL2 is 'multi-homed' and is connected to multiple networks. By default my developer systems listen only on localhost.
For .NET there's several ways to listen on all networks (including Tailscale) but I used this one:
dotnet run --urls http://*:5100;https://*:5101
So here I've got myself connecting to the Tailscale IP that's associated with my WSL2 instance and hitting my Linux service running within:
How far can we take this? Well, since I'm on the Tailscale network and Glenn has connected to it, the whole network is flat, so hitting my service is trivial! Here I am on Teams with my desktop on the bottom and Glenn's desktop on the top.
Cool. How far can we go?
Add Visual Studio Code and the Remote Development SSH Extension
Ok, so flat secure network, no limits! Can I make my WSL2 instance be treated as a remote development system for Glenn? Sure, why not?
To be clear - this is just me talking and experimenting, but there's something here. This can also be cross platform, Mac to Windows to WSL2, etc. You can also certainly use this section to create a VM in any cloud host or hoster, install Tailscale, stop worrying about port forwarding, and use it as a development box. Yes, you can just use WSL local, but this is fun and can be exploited in other cool ways.
On my WSL2 machine, I'll start up the ssh service. I could share public keys and do proper key-based login, but for this I'll do it by username.
/etc/ssh/sshd_config and set the port, ListenAddress, and PasswordAuthentication to Yes. Here's an example:
I made glenn a local super user just in my WSL2 instance:
sudo adduser glenn
usermoid -aG sudo glenn
Glenn then installs the VS Code Remote Development pack and connects using Remote via SSH to my Tailscale IP. Here you can see VS Code from Glenn's machine is actually installing the VS Code Server and remote developers, and Glenn and code with VS Code architecturally split in half with the client on his Windows machine and the server on my WSL2 instance.
Note in the lower left corner, you can see his VS Code is connected to my WSL2 Linux instance's Tailscale IP!
What do you think?
You may compare Tailscale to things like NGrok which offers a developer-oriented localhost tunneller, but there are some important differences. Do your research! I have no relationship with this company other than I'm a fan.
Sponsor: This week's sponsor is...me! This blog and my podcast has been a labor of love for 19 years. Your sponsorship pays my hosting bills for both AND allows me to buy gadgets to review AND the occasional taco. Join me!