Files
docker-infrastructure/tailscale-proxy
pipistrelloandClaude Opus 4.8 ebf94e668b tailscale-proxy: replace TSPU-blocked SOCKS5 with Fake-TLS MTProto (Telegram)
Retire the generic SOCKS5 :1080 (raw SOCKS5 is blocked by TSPU/DPI for the
external Telegram use case) and add ts-lan-mtproto (alexbers/mtprotoproxy) on
:1080 instead: a Fake-TLS MTProto proxy whose Telegram-DC connections chain
through the Tailscale userspace SOCKS5 (SOCKS5_HOST=ts-proxy:1055), so egress
still rides the Hetzner exit node. Client-facing hop is domestic Fake-TLS to
test the hypothesis that TSPU bites hardest at the border. 3proxy keeps only
the HTTP front (:3128). The proxy secret lives in a host-only config.py
(0600, uid 10000, not in git); config.py.example is the secret-free template.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 10:34:52 +03:00
..

Tailscale exit-node LAN proxy

LAN HTTP and SOCKS5 proxies that egress through the dedicated Hetzner Tailscale exit node, so proxied clients appear on the internet as 89.167.72.79 without routing the docker host itself through the tunnel.

  • HTTP endpoint: 192.168.0.35:3128/tcp (tinyproxy, HTTP/HTTPS forward proxy);
  • SOCKS5 endpoint: 192.168.0.35:1080/tcp (3proxy, LAN-only);
  • both fronts accept LAN clients (192.168.0.0/22) and forward upstream over SOCKS5 to the Tailscale container (tinyproxy upstream socks5, 3proxy parent socks5);
  • ts-proxy runs Tailscale in userspace mode and sends outbound traffic through the exit node fedora-technohim (100.121.234.85);
  • userspace mode adds no host route/firewall changes — the docker host's own services (NPM, KMS, IPsec) keep egressing via the normal gateway;
  • both fronts carry TCP only — QUIC/HTTP3 (UDP) is not proxied, so clients must disable browser QUIC for e.g. YouTube video, or run the Tailscale client directly and use the exit node for a full (UDP-capable) tunnel;
  • proxy access logs ship to the logging stack (Alloy → Loki) via the syslog log-driver (tag: tailscale-proxy for HTTP, tag: tailscale-socks5 for SOCKS5); the Grafana dashboard logging/grafana-dashboards/tailscale-proxy.json visualises the HTTP proxy.

The stack deliberately keeps credential-bearing / stateful files outside Git:

Host path Purpose Required mode
/mnt/containers/tailscale-proxy/ts.env TS_AUTHKEY=<tailscale auth key> 0600, owner root:root
/mnt/containers/tailscale-proxy/state/ Tailscale node state (persists identity across restarts) dir, owner root:root
/mnt/containers/tailscale-proxy/tinyproxy.conf tinyproxy config (also tracked in this directory as the source of truth) 0644
/mnt/containers/tailscale-proxy/3proxy.cfg 3proxy SOCKS5 config (also tracked in this directory as the source of truth) 0644

Before deploying: create ts.env on the host with a Tailscale auth key, and in the Tailscale admin console approve the exit node and allow this node to use it. Deploy this directory as a Portainer Git stack named tailscale-proxy, or run it with Docker Compose using project name tailscale-proxy. The absolute configuration files must already exist on the host before deployment.

Full build record and rationale (userspace vs TUN dead-ends, SOCKS5-vs-HTTP, monitoring) is in ops-knowledge: diagnostics/2026-07-23-02-tekhnohim-docker-tailscale-exit-proxy-stack.md.