Using Tailscale MagicDNS to access VM network for development purposes

I was thinking it would be really cool if I could use Tailscale to access my VM network so that I don’t need to make any changes to my host machine, like forwarding ports and using additional reverse proxy, just to route traffic to it.

Let me explain my setup and what I am trying to achieve. I am coming from a macOS Docker Compose-based development environment and not knowing exactly where to start with Nix the first thing I did was turning my application (.NET API, React, Postgres, Nginx) into a Nix module with a lot of defaults, so all I need to do is myApp.enable = true to make it available. That’s how I configured my production environment as well.

production = nixpkgs.lib.nixosSystem {
  inherit system;
  modules = awsModule ++ sharedModule;
};

I can then deploy it with nixos-rebuild switch --flake .#production --target-host root@<ip> . I haven’t had time to look into other deployment tools, but this method works so well that I’m probably going to stick with it.

I then read that I could run the configuration locally in a VM using nix run .#nixosConfigurations.production.config.system.build.vm and virtualisation = ... . I tried it not expecting much, and it just worked! It’s hard to explain what possibilities it unlocks for me. I can tinker, try, and break anything I want, and if it runs locally, I have a high level of certainty it’s going to work the same in production!

I promptly uninstalled Docker and started to create a development VM that only slightly differs from production, which is a good thing because the closer, the better. However, I got a bit stuck on how to access it from my browser. The only thing I could think of was to create a Caddy reverse proxy on my local machine to route myapp.localhost into the VM, where I opened ports with virtualisation.forwardPorts . It works, and I even got React HMR working, which needs WebSockets (I used Caddy instead of Nginx to have local dev HTTPS).

So, the current setup is as follows: My local machine has Caddy, which routes myapp.localhost along with some other routes into the running VM, which has Nginx that then routes the traffic to appropriate services.

What I would want to achieve is to take advantage of Tailscale, which is running as part of my VM anyway, to route traffic into the VM not from localhost but from the internet using MagicDNS with the fully qualified domain name name like https://myapp.yak-bebop.ts.net .
Is it possible to achieve this along with HTTPS, which browsers trust? It seems like an ideal setup and dangerously close to what production is like. Basically, I want to fake the internet with Tailscale. I could then:

  • share the link with users from my tailnet or maybe even with people without tailscale at all?
  • use regular url address instead localhost
  • VM is isolated from rest of the system and I can have multiple of them each with its own adress
  • browser have no way of telling its not just regular website I rely on both HttpOnly and Secure for my auth and when developing locally I need to relax those rules
  • no need to have caddy running on my local

I tried it a few times, but I am new to Nix, and I only know the basics of Nginx. Additionally, I am also getting a bit lost in all of the Tailscale features.

3 Likes

This just dropped https://tailscale.com/blog/tailscale-funnel-beta I’ll give it another try.

1 Like