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.
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-proxyruns Tailscale in userspace mode and sends outbound traffic through the exit nodefedora-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-proxyfor HTTP,tag: tailscale-socks5for SOCKS5); the Grafana dashboardlogging/grafana-dashboards/tailscale-proxy.jsonvisualises 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.
Telemt monitoring
Telemt exports Prometheus metrics on container port 9090, published as
http://192.168.0.35:9092/metrics because host port 9090 is reserved by
Cockpit. The Telemt application whitelist permits only the client-02 Zabbix
server (192.168.0.34/32). In Zabbix, import Telemt's upstream
tools/zbx_telemt_template.yaml, link it to the Docker host, and set
{$TELEMT_URL} to the URL above.
Prometheus deliberately exposes only active-IP counts. The files in
zabbix/ add the text key telemt.active_ips.list without publishing
Telemt's control API. A root timer enters only the container's network
namespace, reads /v1/users, discards links/secrets in memory, and writes a
sanitized username/IP list readable by the Zabbix agent:
install -o root -g root -m 0755 zabbix/zabbix-telemt-active-ips \
/usr/local/libexec/zabbix-telemt-active-ips
install -o root -g root -m 0644 zabbix/zabbix-telemt-active-ips.service \
zabbix/zabbix-telemt-active-ips.timer /etc/systemd/system/
install -o root -g root -m 0644 zabbix/telemt-active-ips.conf \
/etc/zabbix/zabbix_agent2.d/telemt-active-ips.conf
systemctl daemon-reload
systemctl enable --now zabbix-telemt-active-ips.timer
systemctl start zabbix-telemt-active-ips.service
systemctl restart zabbix-agent2
Create a Zabbix agent item on Fedora Kirochnaya with key
telemt.active_ips.list, information type Text, a 30-second update
interval, and one-day history. IP addresses are operationally sensitive; do
not retain this item longer or expose it on unrestricted dashboards.