Files
docker-infrastructure/tailscale-proxy/docker-compose.yaml
T
pipistrello e41b55ca4f tailscale-proxy: pin Telemt's nofile limit and abort dead pre-auth sockets
Mirrors what is now running on the client-02 docker host, so a "pull and
redeploy" from this repo can no longer silently revert it.

On 2026-09-09 a connection flood against the public :1080 (peak 4,301
connections/minute, ~100% failing the Fake-TLS handshake) exhausted the Telemt
container's file-descriptor table, which sat at Docker's default soft limit of
1024. accept() then failed for every caller — real Telegram clients and the
monitoring collector alike — until the burst drained. Steady state needs only
45-73 descriptors, so the ceiling was ~7% used in normal operation.

  ulimits: nofile 65536/524288 on the telemt service

The host was mitigated at runtime with prlimit on the day, but that is lost on
any recreate, and this compose is exactly what a redeploy would restore. The
proxy (3proxy) service deliberately does NOT get the block in this commit — it
is still on the runtime limit only and is scheduled for its own window, so
adding it here would make the repo claim something that is not yet true.

  rst_on_close = "errors" in telemt.toml.example

Scanners and DPI probes that never complete the handshake leave orphaned sockets
in FIN-WAIT-1. "errors" sets SO_LINGER(0) at accept() and clears it once a client
authenticates, so real sessions still close gracefully with FIN and only pre-auth
closes are aborted. Verified on the wire on the host: a failed handshake now ends
FIN then RST, while authenticated sessions in the same capture closed FIN-only.

Applied on the host at 22:17 MSK via telemt-safe-restart: healthy in 10s,
container IP unchanged, bad-handshake delta 0 over a 5-minute recheck, no EMFILE
since.

NOTE for whoever deploys this stack from this repo: it is still missing the
ts-vpn + ts-lan-ikev2 services that have been running on the client-02 host since
2026-09-05. Deploying this file as-is would take the IKEv2 VPN front down. That
drift is untouched here and needs its own commit.
2026-09-09 22:33:30 +03:00

74 lines
2.9 KiB
YAML

services:
ts-proxy:
image: tailscale/tailscale:v1.98.9
container_name: ts-proxy
hostname: technohim-lan-proxy
restart: unless-stopped
env_file: ["/mnt/containers/tailscale-proxy/ts.env"]
environment:
TS_HOSTNAME: technohim-lan-proxy
TS_STATE_DIR: /var/lib/tailscale
TS_USERSPACE: "true"
TS_ACCEPT_DNS: "false"
TS_EXTRA_ARGS: "--exit-node=100.121.234.85 --reset"
TS_TAILSCALED_EXTRA_ARGS: "--socks5-server=0.0.0.0:1055 --outbound-http-proxy-listen=0.0.0.0:1056"
volumes: ["/mnt/containers/tailscale-proxy/state:/var/lib/tailscale:z"]
networks: [proxynet]
# 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
restart: unless-stopped
depends_on: [ts-proxy]
volumes:
- "/mnt/containers/tailscale-proxy/3proxy.cfg:/etc/3proxy/3proxy.cfg:ro,z"
- "/mnt/containers/tailscale-proxy/3proxy.secret:/etc/3proxy/3proxy.secret:ro,z"
ports:
- "192.168.0.35:3128:3128"
logging:
driver: syslog
options:
syslog-address: "udp://192.168.0.35:514"
syslog-format: rfc3164
tag: tailscale-proxy
networks: [proxynet]
# Telegram Fake-TLS MTProto proxy on :1080. Uses Telemt (the same proven
# implementation as the Hetzner endpoint) after alexbers/mtprotoproxy's
# Fake-TLS handshake was rejected by real clients (see the mtproto diagnostic).
# Only DC-bound traffic is chained out through the Tailscale userspace SOCKS5
# ([[upstreams]] socks5 ts-proxy:1055 in telemt.toml), so egress rides the
# Hetzner exit node; the client-facing hop is direct Fake-TLS.
# telemt.toml is host-only (0600, uid 65532/nonroot, NOT in git) - holds the secret.
telemt:
image: ghcr.io/telemt/telemt:3.4.25
container_name: ts-lan-telemt
restart: unless-stopped
# Docker default soft nofile is 1024. A connection flood on the public :1080
# exhausted it on 2026-09-09 and accept() then failed for EVERY caller, for
# ~8 minutes. Steady state needs only ~45-73 descriptors.
ulimits:
nofile:
soft: 65536
hard: 524288
depends_on: [ts-proxy]
environment:
NO_COLOR: "1" # cleaner `docker logs` (no ANSI escapes)
volumes:
- "/mnt/containers/tailscale-proxy/telemt/telemt.toml:/app/config.toml:ro,z"
ports:
- "192.168.0.35:1080:1080"
# Host :9090 belongs to Cockpit; expose Telemt metrics on :9092 instead.
- "192.168.0.35:9092:9090"
# Stays on json-file: telemt's tracing logs don't ship cleanly over the
# syslog driver, and `docker logs ts-lan-telemt` is worth keeping for this
# critical service. Prometheus metrics are scraped by Zabbix on :9092.
networks: [proxynet]
networks:
proxynet:
name: tailscale-proxynet