Retire the tinyproxy HTTP container (tinyproxy has no per-source-IP conditional auth) and serve both the HTTP proxy (:3128) and SOCKS5 (:1080) from a single 3proxy instance. LAN (192.168.0.0/22) stays passwordless; any non-LAN source (i.e. external clients via the router port-forward) must authenticate. Credentials live in a host-only /etc/3proxy/3proxy.secret (0600, not in git), included by 3proxy.cfg. A deny rule on the gateway IP makes the proxy fail closed if the port-forward ever SNATs to 192.168.0.1. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.