RecentlyOdds & Ends
now playing

tsdproxy

tsdproxy is a tool to serve multiple services with HTTPS from a single machine on a tailnet. This is particularly useful because Tailscale only natively supports serving one service (using tailscale serve) per host. These services can be accessed through MagicDNS as https://<servicename>.magicdns.ts.net.

How it works

For each service, tsdproxy sets up a Docker container acting as a distinct Tailscale device. Each container sets up its own Tailscale connection and its own tailscale serve. In other words, it sets up a reverse proxy via tailscale serve for each service.

tsdproxy-diagram
A side effect is that each service registers as a new machine in Tailscale - note that there *is* a limit to the number of tailnet machines on the free tier, though it is pretty large (100).

Setup with NixOS

==TODO these are notes from my claude session trying to set it up; should clean it up.==

  1. Created modules/selfhosted/dawarich/ with: - docker-compose.yml — source compose file (edit this) - docker-compose.nix — auto-generated by compose2nix -project=dawarich - default.nix — imports the nix file, opens port 2999 in firewall
  2. Config changes to docker-compose.yml - Port: 2999:3000 - TIME_ZONE: America/Los_Angeles - APPLICATION_HOSTS: added gethsemane, gethsemane.dinosaur-frog.ts.net:2999, dawarich.gethsemane.dinosaur-frog.ts.net - Labels for tsdproxy: tsdproxy.enable: “true” and tsdproxy.name: “dawarich”
  3. Added ../../../modules/selfhosted/dawarich to imports in configuration.nix

tsdproxy

  1. Created modules/selfhosted/tsdproxy/ with: - docker-compose.yml - docker-compose.nix — auto-generated by compose2nix -project=tsdproxy - tsdproxy.yaml — config file, placed at /etc/tsdproxy/ via environment.etc - default.nix — imports nix file, opens port 8080, enables podman.dockerSocket, copies config via environment.etc.“tsdproxy/config.yaml”
  2. Key fixes: - Socket path: /run/podman/podman.sock:/var/run/docker.sock (not /var/run/docker.sock) - Added /run/secrets/tailscale_key volume mount for sops secret - HOME: /data env var to fix Tailscale log state panic
  3. Added ../../../modules/selfhosted/tsdproxy to imports in configuration.nix

Workflow for future changes

  1. Edit docker-compose.yml
  2. Run compose2nix -project= to regenerate docker-compose.nix
  3. nixos-rebuild switch

captain’s log for debugging container stuck in “starting” state

ISSUE: services aren’t up; logs report this bs

1:23AM INF Authkey is set; but state is NoState. Ignoring authkey. Re-run with TSNET_FORCE_LOGIN=1 to force use of authkey. Hostname=qbittorrent module=proxymanager tailscale=default

Seemingly relevant issue https://github.com/almeidapaulopt/tsdproxy/issues/343

The solution for me was to down the tsd proxy container, delete the data directories, remove the nodes from the tailnet (headscale in my case) and then bring tsd proxy back up

# Remove stale data directories
sudo rm -rf /var/lib/tsdproxy/data/default/*

# Remove nodes from tailnet

# Start the service
sudo systemctl start podman-tsdproxy-tsdproxy.service

# Check logs; shouldn't see it anymore
sudo podman logs -f tsdproxy-tsdproxy

well that didn’t fuckin work

Help, it stopped working (AGAIN)

  • Is the auth key expired? They expire after 90 days. secrets.yaml is annotated with the next expiry date.
  • Mullvad VPN exit nodes don’t work with tsdproxy, unfortunately.