Requires a Go environment with GOPROXY set:
# Go >= 1.13
go env -w GOPROXY=https://goproxy.cn,direct
git clone https://github.com/keminar/anyproxy.git
cd anyproxy
make allFor cross-compilation for various platforms/architectures (including router MIPS, ARM, and Windows WinDivert copying), see build.md.
# foreground
./anyproxy
# background daemon (forks a child process; parent exits)
./anyproxy -daemon
# start as a dedicated user (paired with iptables owner rules)
sudo -u anyproxy ./anyproxy -daemonSend SIGHUP; the program forks a new process to take over the listening fd, and the old process exits after draining:
kill -HUP <pid>
listen: off(pure websocket penetration, no main listening fd to hand over) also supportsSIGHUP, but goes through "start new process first, old process exits later": the websocket service has built-in bind retry, so after the old process exits and releases the port the new process takes over, and subscribers auto-reconnect (there is a very brief connection interruption, not a zero-downtime handover).
- Normal mode:
SIGINT(Ctrl+C) /SIGTERMcloses the listener, drains connections, then exits. - TUN mode:
SIGINT/SIGTERMfirst cancels the context, closes the virtual network interface, reclaims the0.0.0.0/1+128.0.0.0/1routes, then exits. Force kill (kill -9/taskkill /F) skips cleanup, leaving residual routes and the interface that must be deleted manually.
# create a non-login user, use it to start anyproxy, avoiding its own traffic being re-forwarded into a loop
sudo useradd -M -s /sbin/nologin anyproxy
sudo iptables -t nat -A OUTPUT -p tcp -m owner --uid-owner anyproxy -j RETURN
sudo -u anyproxy ./anyproxy -daemon
# root account local subnets don't go through proxy
sudo iptables -t nat -A OUTPUT -p tcp -d 192.168.0.0/16 -m owner --uid-owner 0 -j RETURN
sudo iptables -t nat -A OUTPUT -p tcp -d 172.17.0.0/16 -m owner --uid-owner 0 -j RETURN
# root account http/https go through proxy
sudo iptables -t nat -A OUTPUT -p tcp -m multiport --dport 80,443 -m owner --uid-owner 0 -j REDIRECT --to-port 3000Removing rules:
sudo iptables -t nat -L -n --line-number # view line numbers
sudo iptables -t nat -D OUTPUT 2 # delete the 2nd OUTPUT ruleLinux iptables transparent proxy is Linux-only; the Windows/macOS builds drop this part and use TUN for the global proxy instead.
docker build -t anyproxy:latest .
docker run anyproxy:latest
docker run -p 3000:3000 anyproxy:latest -p '127.0.0.1:3001'mode: tunrequires administrator privileges. Windows does not create a virtual network interface, but uses WinDivert to intercept packets at the network layer (replacing the old wintun). You must placeWinDivert.dll+WinDivert64.sys(32-bit systems also needWinDivert32.sys) in the same directory asanyproxy.exe(a path containing spaces/Chinese may cause driver load failure). See windows-winDivert.md.ensureEagerRSS()is a no-op on Windows and does not re-exec.- Process management must watch the real PID: under
-daemonthe parent forks a child and exits immediately; the one actually running is the child (new PID). When using an external program (e.g. a tray UI) to start/stop anyproxy, killing by the parent PID obtained at startup or "scanning by exe name" may kill the wrong target and result in "can't kill". It's recommended to use the PID of the actual listening process, or omit-daemon(let the external program handle background hiding). - Stop: Windows's WinDivert model doesn't modify the route table or create an interface; on exit it closes the WinDivert handle to stop redirection, leaving no residual routes/interface (unlike the TUN route cleanup on Linux/macOS).
Before starting, it's recommended to raise the available file descriptor limit to at least 65535:
ulimit -n 65535Related to
loopGuard.minActive: the loop is cut once the global in-flight connection count just exceedsminActive; each connection takes about 2 fds, sominActive×2must be far smaller thanulimit -n, otherwise it hitstoo many open filesfirst. See multi-instance-loop.md.
Other kernel parameters: append to /etc/sysctl.conf then run sysctl -p (full list in ./anyproxy -h). Includes enabling BBR congestion control (needs kernel ≥ 4.9):
cat >> /etc/sysctl.conf << EOF
# TCP BBR congestion control
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
# TCP/IP tuning
fs.file-max = 1000000
net.core.rmem_max = 67108864
net.core.wmem_max = 67108864
net.core.netdev_max_backlog = 250000
net.core.somaxconn = 4096
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_keepalive_time = 1200
net.ipv4.ip_local_port_range = 10000 65000
net.ipv4.tcp_max_syn_backlog = 8192
net.ipv4.tcp_max_tw_buckets = 524288
net.ipv4.tcp_fastopen = 3
net.ipv4.tcp_window_scaling = 1
net.ipv4.tcp_rmem = 4096 131072 67108864
net.ipv4.tcp_wmem = 4096 65536 67108864
net.ipv4.tcp_mtu_probing = 1
EOF
sysctl -pVerify BBR:
sysctl net.ipv4.tcp_congestion_control # => net.ipv4.tcp_congestion_control = bbr
lsmod | grep bbr # => contains tcp_bbrYou can also use the built-in commands to auto-check/apply (Linux only):
./anyproxy -check # report whether sysctl/ulimit/BBR meet recommended values (read-only)
sudo ./anyproxy -check-fix # one-click write to /etc/sysctl.d/99-anyproxy.conf and apply with sysctl -p
-check-fixonly handles sysctl; file descriptors (ulimit -n) vary by environment and must be configured separately: for interactive login edit/etc/security/limits.conf, for systemd services setLimitNOFILE=65535in the unit.
./anyproxy -debug 2 # debug level 0~3
./anyproxy -pprof :5001 # access http://:5001/debug/pprof/ in browser