Guide

How to Use ProxyChains to Force Any Tool Through a Proxy

How to use ProxyChains-ng to route any TCP program through a proxy it has no support for: install, the config file and ProxyList, dynamic vs strict vs random chains, proxy_dns, chaining multiple hops, and the LD_PRELOAD limits that matter.

HProxy Team · ·Updated July 17, 2026 ·8 min read
HProxy. Guide

Free proxies won't hold up here.

Shared datacenter IPs get flagged and dropped fast. When it has to hold, gaming, streaming, accounts, you need mobile and residential IPs that read as a real device, from $0.65/GB, pay as you go.

See plans & pricing

Some programs simply have no proxy option. An old CLI tool, a binary you did not write, a scanner that only knows how to open raw sockets. ProxyChains solves this a layer below the application: instead of asking the program to use a proxy, it rewrites the program's network calls from underneath and forces every TCP connection through a proxy whether the program knows about proxies or not. That is a genuine superpower, and every one of its limitations falls straight out of how it does it. This guide covers installing ProxyChains-ng, the config file, the chain modes that are the whole point, keeping DNS from leaking, chaining multiple hops, and the constraints that trip people up.

We route a lot of traffic through a lot of proxies, and ProxyChains is the tool we reach for when something has no --proxy flag of its own. Every command below is copy-paste runnable. Where one needs a live proxy, pull a fresh one from our free proxy API, which returns real, recently checked endpoints without a key.

How do you use ProxyChains?

Prefix any command with proxychains4: proxychains4 curl https://example.com forces that curl through the proxy chain. ProxyChains reads a config file, most often /etc/proxychains.conf or a local ./proxychains.conf, that lists your proxies under a [ProxyList] section and picks a chain mode. Point it at a specific config with -f. The program itself needs no proxy support at all.

Install

Use ProxyChains-ng, the maintained "new generation" fork. Its binary is called proxychains4. On Debian or Ubuntu:

sudo apt install proxychains-ng

Or build the current version from source, which is worth doing if your distro packages an old one:

git clone https://github.com/rofl0r/proxychains-ng
cd proxychains-ng
./configure --prefix=/usr --sysconfdir=/etc
make && sudo make install && sudo make install-config

make install-config writes a default /etc/proxychains.conf you will edit next.

How it works, and why that dictates everything

ProxyChains sets LD_PRELOAD (the dynamic linker's "load this library first" hook) to inject its own version of the C library's connect() function into the target program. When the program tries to open a TCP connection, ProxyChains' connect() runs instead, dials your proxy, negotiates the tunnel, and hands the socket back as if the connection had gone direct. The program is none the wiser.

Hold onto that mechanism, because it explains every limit later in this guide. It only works on programs that call libc's connect() through dynamic linking, which is why static binaries and setuid programs slip past it, and it only intercepts TCP, which is why UDP and ICMP are never proxied. The power and the constraints are the same fact seen from two sides.

The config file

ProxyChains searches for its config in a fixed order, and the first file it finds wins:

  1. The PROXYCHAINS_CONF_FILE environment variable, or the -f argument
  2. ./proxychains.conf in the current directory
  3. ~/.proxychains/proxychains.conf
  4. /etc/proxychains.conf

That order is useful: a per-project ./proxychains.conf overrides the system file without you touching /etc. The proxies themselves live at the bottom, under [ProxyList], one per line as type host port with optional credentials:

[ProxyList]
# type   host          port   [user    pass]
socks5   127.0.0.1     9050
http     203.0.113.7   8080   myuser   mypass
socks4   198.51.100.14 1080

Recent versions (4.14 and up) also accept the compact URL form, which is easier to paste from a provider dashboard:

[ProxyList]
socks5://myuser:[email protected]:1080

Supported types are http, socks4, and socks5. A wrong or missing password on an HTTP proxy surfaces the same 407 Proxy Authentication Required you would see anywhere else, covered in how to fix 407.

Chain modes: the actual point

Above [ProxyList] you choose exactly one chain mode by uncommenting it. This is the setting that decides how a multi-proxy list behaves, and getting it wrong is the most common reason ProxyChains "randomly" fails:

  • dynamic_chain: route through the listed proxies in order, but skip any that are dead. The chain works as long as at least one proxy is up. This is the right default for real proxy lists, where some entries are always down.
  • strict_chain: route through every proxy in exact order, and fail the whole connection if any single one is unreachable. Use it only when you truly need a fixed, known path.
  • random_chain: for each connection, pick a random subset of the list in random order (length controlled by chain_len). Useful for spreading load unpredictably.
  • round_robin_chain: added in 4.7, rotates the starting proxy on each connection while otherwise behaving like a dynamic chain.
# Pick ONE. dynamic_chain is the forgiving default.
dynamic_chain
#strict_chain
#random_chain
#round_robin_chain

If ProxyChains seems to hang or fail on a list where you know some proxies work, the usual cause is strict_chain left enabled with a dead entry in the list. Switch to dynamic_chain.

Keep DNS from leaking

By default the shipped config enables proxy_dns, and you want to leave it on. Without it, your program resolves hostnames through your own local resolver before ProxyChains ever sees the connection, which leaks every domain you visit to your ISP and defeats much of the point of proxying. With proxy_dns on, hostname resolution is routed through the proxy chain instead:

proxy_dns                          # resolve names through the chain, not locally
remote_dns_subnet 224              # map proxied lookups into 224.0.0.0/... internally

proxy_dns_old is an older, less stable resolver kept only for compatibility with ancient setups; use plain proxy_dns. This is the same local-versus-remote DNS split that socks5h solves for a single tool, which we explain in what is a SOCKS5 proxy. ProxyChains just applies it to every program you wrap.

Chaining multiple hops

Because ProxyChains reads a list, routing through several proxies in sequence is simply listing more than one and using strict_chain (or dynamic_chain):

strict_chain
proxy_dns

[ProxyList]
socks5   127.0.0.1     9050            # local Tor
http     203.0.113.7   8080   u   p    # then out through an HTTP proxy

This is the multi-hop routing a single curl cannot do on its own. Our cURL guide notes that curl takes exactly one proxy per request; ProxyChains is the standard answer when you need curl (or anything else) to traverse several. Each hop adds latency, so chain only as deep as you actually need.

Real usage, including the TCP-only caveat

The everyday form is just a prefix:

# Route curl through the chain
proxychains4 curl -s https://httpbin.org/ip

# Use a specific config instead of the system one
proxychains4 -f ./proxychains.conf curl -s https://httpbin.org/ip

# A tool with no proxy support of its own
proxychains4 nmap -sT -Pn -p 80,443 scanme.nmap.org

That nmap line quietly encodes the biggest limit. ProxyChains carries TCP only, so you must use a TCP connect scan (-sT) and skip ICMP host discovery (-Pn). A SYN scan (-sS) crafts raw packets that never touch libc's connect(), and a UDP scan is not TCP at all, so neither travels through the chain. Any tool built on UDP or ICMP, including plain ping, is simply not proxied.

The limits worth knowing before you trust it

All of these follow from the LD_PRELOAD plus TCP mechanism:

  • TCP only. No UDP, no ICMP. DNS is the one exception, handled specially by proxy_dns over the chain.
  • Dynamically linked programs only. Statically linked binaries, which includes many Go tools, do not load ProxyChains' library, so it silently does nothing and the traffic goes out direct. This is the single most dangerous failure mode, because it fails open, not closed. Always verify (next section) rather than assume.
  • No setuid binaries. The linker strips LD_PRELOAD for setuid programs as a security measure, so ProxyChains cannot hook them.
  • macOS is limited. System Integrity Protection strips the injection for system binaries on modern macOS, so ProxyChains-ng is most reliable on Linux.

Verify the exit IP

Because ProxyChains can fail open on a static binary, verifying is not optional here, it is the whole safety net. Compare direct against wrapped:

# Your real IP
curl -s https://httpbin.org/ip

# Through the chain, should be a proxy's IP
proxychains4 curl -s https://httpbin.org/ip

ProxyChains also prints its hops to stderr, lines like [proxychains] Dynamic chain ... 203.0.113.7:8080 ... OK, which confirm the path it actually took; set quiet_mode 1 in the config to silence them once you trust the setup. If the wrapped IP matches your real one, the hook did not take (static binary, or a program that bypassed connect()), and you should stop and fix that before sending anything sensitive. For a fuller read on any exit, our proxy checker reports exit IP, anonymity grade, real geolocation, and latency in one paste.

Where to go from here

ProxyChains is the universal adapter: when a tool has no proxy support, it gives it one from the outside. Keep three things in mind and it will serve you well. Use dynamic_chain so one dead proxy does not break everything, leave proxy_dns on so you do not leak lookups, and verify the exit IP every time because it can fail open. For a live pool to feed it, the free proxy list re-verifies its entries every few minutes.

From here, the cURL guide is the reference for the single-proxy flags ProxyChains complements, what is a SOCKS5 proxy explains the SOCKS layer most ProxyChains setups ride on, and proxies for web scraping covers choosing the right proxy type for the job. When a project graduates to production and you want IPs nobody else is burning, our paid pools are the upgrade.

Sources

  • proxychains-ng (rofl0r/proxychains-ng): the proxychains4 usage, the config search order, the [ProxyList] format and URL form, the dynamic_chain/strict_chain/random_chain/round_robin_chain modes, proxy_dns, and the TCP-only and dynamic-linking limits.

Frequently asked questions

Why does ProxyChains not work with my Go program (or other static binary)?
Because ProxyChains works by LD_PRELOAD: it injects a small library that intercepts the standard connect() call and reroutes it through the proxy. Statically linked binaries, which many Go programs are, do not load external libraries at runtime, so there is nothing to hook and ProxyChains silently does nothing, sending the traffic out on your real IP. Use a dynamically linked build, or a tool with native proxy support, for those cases.
What is the difference between dynamic_chain, strict_chain and random_chain?
dynamic_chain routes through your proxies in the listed order but skips any that are dead, so it keeps working as long as at least one is up. strict_chain uses them in exact order and fails the whole connection if any one is down. random_chain picks a random subset in random order for each connection. You uncomment exactly one mode in the config, and dynamic_chain is the sane default for real proxy lists.
Does ProxyChains leak DNS?
Not if proxy_dns is enabled, which it is in the shipped default config. With proxy_dns on, hostname lookups are routed through the proxy chain instead of your local resolver, which closes the DNS leak that would otherwise reveal every host you visit to your ISP. If you edited the config, confirm the proxy_dns line is still uncommented.
Can ProxyChains proxy UDP or ICMP traffic like ping or a UDP scan?
No. ProxyChains is TCP only, because the SOCKS and HTTP proxying it relies on carries TCP. Ping (ICMP) and UDP-based tools are not routed through it. With nmap specifically, that means using a TCP connect scan (-sT) and skipping host discovery (-Pn); a SYN scan (-sS) or a UDP scan will not travel through the chain.
Where does ProxyChains look for its config file?
In order: the PROXYCHAINS_CONF_FILE environment variable or the -f argument, then ./proxychains.conf in the current directory, then ~/.proxychains/proxychains.conf, then /etc/proxychains.conf. The first file found wins, so dropping a per-project ./proxychains.conf lets you override the system default without touching /etc.

Proxies that don't die mid-job

Residential, ISP, datacenter and mobile, verified by the same engine that runs tens of millions of checks. They read as a real device and hold up under load. Pay as you go, and your balance never expires.

47M+ proxy checks run · 100+ countries · HTTP / HTTPS / SOCKS · re-checked every few minutes · no signup