From ebf94e668bbf17b32fba8f406b5b14302bb9b6ec Mon Sep 17 00:00:00 2001 From: pipistrello Date: Fri, 24 Jul 2026 10:34:52 +0300 Subject: [PATCH] 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 --- tailscale-proxy/3proxy.cfg | 15 ++++++---- tailscale-proxy/docker-compose.yaml | 24 +++++++++++++--- tailscale-proxy/mtproto/config.py.example | 34 +++++++++++++++++++++++ 3 files changed, 63 insertions(+), 10 deletions(-) create mode 100644 tailscale-proxy/mtproto/config.py.example diff --git a/tailscale-proxy/3proxy.cfg b/tailscale-proxy/3proxy.cfg index 825cd71..d38f228 100644 --- a/tailscale-proxy/3proxy.cfg +++ b/tailscale-proxy/3proxy.cfg @@ -1,9 +1,13 @@ -# Unified LAN proxy for the tekhnohim Tailscale exit-node egress. +# HTTP proxy for the tekhnohim Tailscale exit-node egress. # -# One 3proxy instance serves BOTH an HTTP proxy (:3128) and a SOCKS5 proxy -# (:1080), each chained to the Tailscale userspace SOCKS5 (ts-proxy:1055) so -# clients exit the internet as the Hetzner exit-node IP (89.167.72.79). -# TCP only (Tailscale userspace SOCKS5 has no UDP ASSOCIATE -> no QUIC/HTTP3). +# This 3proxy instance serves an HTTP proxy (:3128) chained to the Tailscale +# userspace SOCKS5 (ts-proxy:1055) so clients exit the internet as the Hetzner +# exit-node IP (89.167.72.79). TCP only (no QUIC/HTTP3). +# +# The generic SOCKS5 (:1080) was RETIRED 2026-07-24: raw SOCKS5 is blocked by +# TSPU/DPI for the external Telegram use case. Telegram is now served by the +# `ts-lan-mtproto` container (Fake-TLS MTProto proxy) instead, which reuses the +# :1080 external forward. See the profile / mtproto diagnostic. # # Access model (LAN free, outside password): # * LAN 192.168.0.0/22 -> authorised by source IP, NO password. @@ -44,4 +48,3 @@ parent 1000 socks5 ts-proxy 1055 deny * proxy -p3128 -a -i0.0.0.0 -socks -p1080 -i0.0.0.0 diff --git a/tailscale-proxy/docker-compose.yaml b/tailscale-proxy/docker-compose.yaml index ba5096d..98945cb 100644 --- a/tailscale-proxy/docker-compose.yaml +++ b/tailscale-proxy/docker-compose.yaml @@ -15,9 +15,9 @@ services: volumes: ["/mnt/containers/tailscale-proxy/state:/var/lib/tailscale:z"] networks: [proxynet] - # Unified 3proxy front: HTTP proxy (:3128) + SOCKS5 (:1080), LAN passwordless - # and external password-authenticated. Replaces the former tinyproxy HTTP - # container (tinyproxy cannot do per-source-IP conditional auth). + # 3proxy HTTP front (:3128), LAN passwordless and external password- + # authenticated, egressing via the Tailscale exit node. (The generic SOCKS5 + # :1080 was retired 2026-07-24 — see below.) proxy: image: ghcr.io/3proxy/3proxy:latest container_name: ts-lan-proxy @@ -28,7 +28,6 @@ services: - "/mnt/containers/tailscale-proxy/3proxy.secret:/etc/3proxy/3proxy.secret:ro,z" ports: - "192.168.0.35:3128:3128" - - "192.168.0.35:1080:1080" logging: driver: syslog options: @@ -37,6 +36,23 @@ services: tag: tailscale-proxy networks: [proxynet] + # Telegram-only Fake-TLS MTProto proxy on :1080 (replaces the TSPU-blocked + # generic SOCKS5). Chains its Telegram-DC connections through the Tailscale + # userspace SOCKS5 (SOCKS5_HOST=ts-proxy:1055 in config.py) so egress still + # rides the Hetzner exit node. Client-facing hop is domestic Fake-TLS; the + # foreign leg is the WireGuard tunnel that already carries the HTTP proxy. + # config.py is host-only (0600, uid 10000, NOT in git) - holds the secret. + mtproto: + image: alexbers/mtprotoproxy:latest + container_name: ts-lan-mtproto + restart: unless-stopped + depends_on: [ts-proxy] + volumes: + - "/mnt/containers/tailscale-proxy/mtproto/config.py:/home/tgproxy/config.py:ro,z" + ports: + - "192.168.0.35:1080:1080" + networks: [proxynet] + networks: proxynet: name: tailscale-proxynet diff --git a/tailscale-proxy/mtproto/config.py.example b/tailscale-proxy/mtproto/config.py.example new file mode 100644 index 0000000..aad14c6 --- /dev/null +++ b/tailscale-proxy/mtproto/config.py.example @@ -0,0 +1,34 @@ +# alexbers/mtprotoproxy config for the tekhnohim Telegram Fake-TLS MTProto proxy. +# +# The REAL config.py is host-only at /mnt/containers/tailscale-proxy/mtproto/config.py +# (mode 0600, owned by uid 10000 = the container's `tgproxy` user, NOT in git), +# because USERS holds the proxy secret. This file is the secret-free template. +# +# Egress: SOCKS5_HOST/SOCKS5_PORT point at the Tailscale userspace SOCKS5 +# (ts-proxy:1055), so every Telegram-DC connection exits via the Hetzner exit +# node (89.167.72.79). The client-facing side is Fake-TLS (looks like HTTPS to +# TLS_DOMAIN), which survives TSPU where the retired raw SOCKS5 did not. + +PORT = 1080 + +# username -> 32-hex-char secret (16 bytes). Generate: openssl rand -hex 16 +USERS = { + "tekhnohim": "00000000000000000000000000000000", +} + +# Fake-TLS only (best obfuscation). classic/secure are easier to fingerprint. +MODES = { + "classic": False, + "secure": False, + "tls": True, +} + +# SNI presented in the Fake-TLS handshake. Must be a real, reachable HTTPS host. +# Tunable if a given domain is filtered on the client path. +TLS_DOMAIN = "www.google.com" + +# Upstream SOCKS5 = the Tailscale userspace proxy -> Hetzner exit node. +SOCKS5_HOST = "ts-proxy" +SOCKS5_PORT = 1055 +SOCKS5_USER = None +SOCKS5_PASS = None