tsdproxy
| created | 2022-12-31 16:11 |
| modified | 2026-05-27 08:49 |
| tags | self-hosting |
| status | stub |
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.
Setup with NixOS
==TODO these are notes from my claude session trying to set it up; should clean it up.==
- 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
- 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”
- Added ../../../modules/selfhosted/dawarich to imports in configuration.nix
tsdproxy
- 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”
- 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
- Added ../../../modules/selfhosted/tsdproxy to imports in configuration.nix
Workflow for future changes
- Edit docker-compose.yml
- Run compose2nix -project=
to regenerate docker-compose.nix - 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.yamlis annotated with the next expiry date. - Mullvad VPN exit nodes don’t work with
tsdproxy, unfortunately.