ProxyChains (the maintained fork is proxychains-ng, run as proxychains4) makes a Linux program open its TCP connections through the proxies listed in proxychains4.conf, even when the program has no proxy setting. Put your proxy under [ProxyList] as socks5 IP PORT USERNAME PASSWORD, then prefix the command: proxychains4 curl https://api.ipify.org. It works by preloading a library into the program, which is also why some programs slip past it.
We ran every config and error below with proxychains-ng 4.16, the Debian 12 package, against a local SOCKS5 and HTTP proxy with username and password authentication.
Install and find the config
sudo apt install proxychains4
proxychains4 reads the first config it finds in this order:
- the file named by
-for thePROXYCHAINS_CONF_FILEenvironment variable, ./proxychains.confin the current directory,~/.proxychains/proxychains.conf,/etc/proxychains4.conf(the Debian and Ubuntu path).
A per-project file passed with -f keeps experiments out of the system config.
proxychains4.conf for one authenticated proxy
Copy the host, port, username and password from your order. The first proxy must be written as an IPv4 address, so resolve the host once:
getent hosts HOST
Then write the config:
strict_chain
proxy_dns
remote_dns_subnet 224
tcp_read_time_out 15000
tcp_connect_time_out 8000
[ProxyList]
socks5 IP PORT USERNAME PASSWORD
For the HTTP port use http as the type instead; ProxyChains talks to it with CONNECT and sends Basic credentials. Run a command through it:
proxychains4 -f ./proxychains.conf curl -s "https://api.ipify.org?format=json"
On success the library prints its route before the output, ... Strict chain ... IP:PORT ... api.ipify.org:443 ... OK, and the JSON shows the proxy's address. Add -q to hide those lines once you trust the setup.
Give it a hostname as the first entry and it refuses to start: proxy HOST has invalid value or is not numeric.
strict_chain, dynamic_chain and the rest
Exactly one chain type should be uncommented; if several are, the last one wins.
| Option | With a dead proxy in the list | Use it for |
|---|---|---|
strict_chain | The connection fails | One proxy, or a fixed route you want to fail loudly |
dynamic_chain | Skipped; the rest are used in order | A primary IP with a fallback |
round_robin_chain | Skipped; each connection starts after the last one used | Spreading connections, with chain_len |
random_chain | Picks proxies at random, chain_len of them | Testing, not production |
In our test a strict chain whose first hop was unreachable printed timeout and curl exited with code 7. The same list as a dynamic chain timed out on the dead hop, then went through the second proxy. Every extra hop adds latency, and two paid hops bill the same bytes twice; the proxy chain entry covers when chaining is worth it.
proxy_dns: who resolves the hostname
With proxy_dns on, ProxyChains answers the program's lookup with a placeholder address from remote_dns_subnet (224.x.x.x by default) and sends the real hostname to the proxy, which resolves it. We gave the proxy a name only it could resolve: with proxy_dns the request succeeded, without it curl failed with Could not resolve host. Leave it on so lookups happen at the exit, the same idea as socks5h.
One side effect: localnet exclusions only match plain IP addresses while proxy_dns is on, because a hostname never resolves to a real address inside the program.
What ProxyChains cannot proxy
- UDP.
proxychains4 dig @1.1.1.1 example.comanswered from our own network; the proxy logged nothing. The same query withdig +tcpwent through the proxy as aCONNECTto port 53. - Statically linked binaries.
busybox wgetfrom busybox-static and a Go binary (Chisel 1.12) both connected directly. The tell: proxychains printsconfig file foundandpreloading, but never theDLL initor chain lines. - Anything that bypasses the C library's socket calls, for the same reason.
For those, redirect at the kernel instead with Redsocks, which catches every TCP connection the machine makes, static or not.
Troubleshooting
<--deniedafter the proxy address. The proxy refused: wrong username or password, or the port does not speak the type you wrote.timeouton a hop. Address or port unreachable from this machine.preloadingand then no chain line. The program never loaded the library; it is static, see above.- Works in curl, fails in the real tool. Run the tool with
-fpointing at the same file, then compare against a plain curl request through the proxy.
With ProxyHive
A command-line job usually wants one fixed exit with SOCKS5, which is what a datacenter IP is: static, sold one at a time, with HTTP, HTTPS and SOCKS5 listed in its specs and username and password authentication. Each IP is its own endpoint, so one [ProxyList] line is one address; give each project its own config file and its own IP.