Guide

How to use ProxyChains (and prove the proxy is really used)

Install proxychains4, write a config that works, run any Linux tool through one or more proxies, read its messages, and prove the exit address changed.

HProxy Team··Updated September 2, 2026·15 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.44/GB, pay as you go.

Proxies for Web Scraping

Prefix the command with proxychains4 and it runs through the proxies in your config: proxychains4 curl https://httpbin.org/ip. ProxyChains-NG hooks the program's own connection calls from underneath, so the program needs no proxy option of its own. That works for any dynamically linked TCP program on Linux. It does nothing, silently, for static binaries, UDP and ICMP, which is why this guide ends with a check you must not skip.

Everything below comes from a run we did on 2 September 2026: proxychains4 4.17-1 on Ubuntu 24.04, public entries from our own list, and every message exactly as printed. Where a step needs a live proxy, pull one from our free proxy API, which returns recently checked entries without a key.

What is ProxyChains and how does it work?

ProxyChains-NG is a small library plus a launcher. The launcher sets LD_PRELOAD. The Linux dynamic linker's manual describes that variable as "a list of additional, user-specified, ELF shared objects to be loaded before all others", which "can be used to selectively override functions in other shared objects". The library overrides the C library's connection call. When the program opens a TCP connection, the hook runs first, dials your proxy, sets up the tunnel, and hands the socket back. The program never learns that a proxy was involved.

The maintainer's README puts both limits in one sentence: it "hooks network-related libc functions in DYNAMICALLY LINKED programs" and "supports TCP only (no UDP/ICMP etc)". Every failure later in this guide follows from those two facts.

ProxyChains hooks the program's own connect() call
  1. Any TCP program

    no proxy option

  2. ProxyChains

    intercepts connect()

  3. Proxy chain

    one or more hops

  4. Target

    sees the last exit

Source: The proxy is applied from outside the program

What do I need before I start?

  • A Linux system. The hook needs LD_PRELOAD, which Windows does not have. On Windows, run it inside WSL, which is what we used. The Windows searches that land here have no native answer.
  • A program that is dynamically linked and speaks TCP. Most C and C++ tools qualify. Many Go tools do not, and the limits section explains why.
  • One or more proxies of type http, socks4 or socks5, with or without a password.
  • Root for the package install. Running the tool itself needs no root, except for setuid programs, which come up in the limits section.

How do I install ProxyChains-NG?

On Debian, Ubuntu and Kali

The package is called proxychains4. On Ubuntu 24.04 it ships version 4.17-1, and 4.17 is the current upstream release, published on 21 January 2024. There is no package named proxychains-ng, and the package named proxychains is the old 3.1 line.

sudo apt install proxychains4
proxychains4

Running it without arguments prints the usage text:

Usage:	proxychains4 -q -f config_file program_name [arguments]
	-q makes proxychains quiet - this overrides the config setting
	-f allows one to manually specify a configfile to use

Tutorials that say apt install proxychains-ng fail on these systems, and the first version of this page made the same mistake. Ubuntu's package index lists that name with no candidate at all.

From source

The maintainer's own install steps from the proxychains-ng repository, which are worth using when your distribution packages an old version:

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 the default /etc/proxychains.conf, the file you edit next.

Where is the config file, and which one wins?

The README lists the search order, and the first file found wins:

  1. The file named in the PROXYCHAINS_CONF_FILE variable, or given with -f
  2. ./proxychains.conf in the current directory
  3. ~/.proxychains/proxychains.conf
  4. /etc/proxychains.conf

The Debian and Ubuntu package adds one more step at the end, /etc/proxychains4.conf, and ships its default there. That default is worth knowing because of what it contains. Run any command with no config of your own and this is what you get:

[proxychains] config file found: /etc/proxychains4.conf
[proxychains] preloading /usr/lib/x86_64-linux-gnu/libproxychains.so.4
[proxychains] DLL init: proxychains-ng 4.17
[proxychains] Strict chain  ...  127.0.0.1:9050  ...  timeout

The shipped list holds one entry, a Tor client on 127.0.0.1:9050, in strict mode. Without Tor running, every command waits eight seconds and fails. That is the first "ProxyChains hangs" most people meet, and it is not a bug.

A ./proxychains.conf in the working directory wins over the system file, which is the clean way to keep one config per project:

[proxychains] config file found: /root/pc-test/proxychains.conf

How do I add proxies to the list?

The proxies live at the bottom of the file, under [ProxyList], one per line as type ip port, with an optional user and password. The shipped file accepts the types http, socks4, socks5 and raw, and it says "only numeric ipv4 addresses are valid".

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

Put a hostname in that column and the tool refuses to start, with a message that also tells you the one exception:

non-numeric ips are only allowed under the following circumstances:
chaintype == strict (true), proxy is not first in list (false), proxy_dns active (thread)

Since version 4.14 a line may also be written as a URL, which is easier to paste from a dashboard:

[ProxyList]
socks5://myuser:mypass@203.0.113.7:1080

A wrong password on an HTTP proxy produces the same 407 Proxy Authentication Required as anywhere else. The fix is in how to fix 407.

Where do the proxies come from?

Our free proxy API returns checked public entries as plain text, one ip:port per line. One sed turns them into ProxyList lines:

curl -s "https://hproxy.com/api/proxy-list?format=txt&protocol=socks5&recent=true&limit=5" \
  | sed 's/^/socks5 /; s/:/ /' >> proxychains.conf

Public entries are for testing the setup, not for running it. In our probe on 2 September 2026 at 10:08 UTC, 2 of 38 fresh entries carried a request end to end, and an entry that worked at 09:58 was dead by 10:05. Own proxies do not churn like that, and the verify section shows a second reason to be careful with public ones.

Which chain mode should I use?

Above [ProxyList] you pick exactly one mode by leaving it uncommented. The shipped file says it plainly: "only one option should be uncommented at time, otherwise the last appearing option will be accepted".

modewhat it does with the lista dead entryuse it when
strict_chainevery proxy, in order (the shipped default)the connection failsyou need one fixed path
dynamic_chainevery proxy, in order, skipping dead onesskipped after the connect timeouta real list where some entries are down
round_robin_chainchain_len proxies, starting after the last one used (since 4.7)skippedspreading load across a list
random_chainchain_len random proxies per connectionno skip is promised in the configunpredictable paths
# pick ONE
dynamic_chain
#strict_chain
#round_robin_chain
#random_chain

What happens when a proxy in the list is dead?

We put an unroutable address first in the list and ran the same request in both modes. Strict mode gave up:

[proxychains] Strict chain  ...  192.0.2.1:1080  ...  timeout

That took 8.0 seconds and curl exited with code 7. Dynamic mode waited the same 8 seconds, then went on to the next entry:

[proxychains] Dynamic chain  ...  192.0.2.1:1080  ...  timeout
[proxychains] Dynamic chain  ...  18.185.116.137:59865  ...  httpbin.org:443  ...  OK

The eight seconds come from tcp_connect_time_out 8000 in the shipped file, and tcp_read_time_out defaults to 15000. With a long list of public entries, lower the connect timeout so dead hops cost less:

tcp_connect_time_out 3000
tcp_read_time_out 15000

How do I stop DNS from leaking?

Leave proxy_dns on. The shipped file enables it and explains the trick: "a thread is spawned that serves DNS requests and hands down an ip assigned from an internal list (via remote_dns_subnet)". The program asks for a hostname and receives a stand-in address from the 224.0.0.0/8 range. When it connects to that address, the hook sends the real name to the proxy, which resolves it. You can see the stand-in with curl -v:

*   Trying 224.0.0.1:443...
[proxychains] Dynamic chain  ...  103.237.102.191:11111  ...  109.123.251.109:1080  ...  httpbin.org:443  ...  OK

With proxy_dns commented out, the same command showed Trying 44.194.227.11:443. The connection still went through the chain, but the name was resolved by the local resolver first, so your resolver saw every host before the proxy did. For a socks5 hop the hook sends the name inside the request, using the domain-name address type that RFC 1928 defines. For a socks4 hop it uses the SOCKS4a form, which the README names as the supported variant. That is the same split that socks5h fixes for a single tool: curl's manual says "socks5h:// makes the proxy resolve the host name", and what is a SOCKS5 proxy explains the rest.

The shipped file warns that this method "might not work and/or cause crashes" with "very complex software like webbrowsers". For those cases version 4.15 added proxy_dns_old, the slower proxychains 3.1 method, and proxy_dns_daemon, which needs proxychains4-daemon running first. Plain proxy_dns is the right choice for command-line tools.

How do I chain several proxies?

A chain is a list with more than one entry. Each hop connects to the next, and the target sees the last one:

dynamic_chain
proxy_dns

[ProxyList]
http     103.237.102.191   11111
socks5   109.123.251.109   1080

The chain line names every hop in order, and the body of the request shows the exit:

[proxychains] Dynamic chain  ...  103.237.102.191:11111  ...  109.123.251.109:1080  ...  httpbin.org:443  ...  OK
{
  "origin": "109.123.251.109"
}

Every hop adds latency. In five timed runs on 2 September 2026 the direct request took 0.38 to 0.73 seconds and the two-hop chain took 2.29 to 7.04 seconds. Chain only as deep as the job needs. This is also the multi-hop routing a single curl cannot do, since curl takes one proxy per request, as our cURL guide explains.

How do I run nmap through ProxyChains?

Use a TCP connect scan and skip host discovery:

proxychains4 nmap -sT -Pn -p 80,443 45.33.32.156

The Nmap reference guide explains why -sT is the one scan type that goes through: "Nmap asks the underlying operating system to establish a connection with the target machine and port by issuing the connect system call". A SYN scan writes raw packets, so the hook never sees it, and the README adds that "pcap based scanning does not work". -Pn skips the host discovery probes, which are not TCP connects either.

Why should the target be numeric?

With proxy_dns on and a hostname on the command line, nmap receives the 224.x stand-in address and scans that. Our run against scanme.nmap.org, which permits scans, came back with a confident and wrong report:

Nmap scan report for scanme.nmap.org (224.0.0.1)
rDNS record for 224.0.0.1: all-systems.mcast.net
PORT    STATE  SERVICE
80/tcp  closed http
443/tcp closed https

The README lists this under known problems and gives the fixes: use a numeric IP, or disable proxy_dns. With the numeric target the chain line for port 80 ended in OK and nmap reported it open:

[proxychains] Dynamic chain  ...  103.237.102.191:11111  ...  109.123.251.109:1080  ...  45.33.32.156:80  ...  OK
PORT    STATE  SERVICE
80/tcp  open   http
443/tcp closed https

Resolving the name yourself sends that one lookup through your local resolver, so decide which matters more for the job.

Does ProxyChains support UDP?

No. The README states "It supports TCP only (no UDP/ICMP etc)", and the tool does not warn you. We ran ping -c 1 1.1.1.1 under proxychains4 and got the reply straight from the network, with no chain line at all. A UDP scan, a DNS client, a game or a VoIP tool behaves the same way: the traffic leaves direct. A SOCKS5 server may relay UDP through its UDP ASSOCIATE command, but the client has to speak that itself, as SOCKS4 vs SOCKS5 explains.

What about Firefox and Chrome?

Browsers are the wrong job for this tool. The shipped config warns that the threaded proxy_dns "might not work and/or cause crashes" with browsers, and the maintainer's issue tracker carries reports of Firefox opening under the hook with no page loading. Every browser has a proxy setting of its own, and an extension can switch it per site. Use that instead.

What do the messages on the chain line mean?

Every hooked connection prints one line to stderr. Read it before you change anything.

line ends withwhat happened in our runfix
... OKthe tunnel to the last hop openednothing yet: verify the exit
... timeoutthe hop did not answer within tcp_connect_time_outdrop the entry or switch to dynamic_chain
<--deniedthe hop refused the request: wrong type, or a CONNECT it does not allowmatch the type to the port; try another entry
<--socket error or timeout!the hop accepted and then dropped the connectionthe entry is dying; replace it
error: no valid proxy found in config[ProxyList] is empty or every line is malformedcheck the header, the type and the numeric ip
no DLL init line at allthe program is not dynamically linked; nothing was hookedsee the verify section

-q and quiet_mode silence all of these, including the failures. In our run a failing chain under -q printed nothing and the only signal was the exit code. Keep the lines on until the setup is proven.

How do I verify the proxy is really being used?

Compare the address the target sees without and with the wrapper, then run the same check with a static binary. This capture is our own run, with our real address blanked:

Terminal capture: a direct request shows our own address, the same request through proxychains4 shows the chain line ending in OK and the exit address, and a static busybox binary launched under proxychains4 prints our own address again.
Three commands from our run on 2 September 2026. The middle one is proxied. The last one is not, although it was launched under proxychains4, because busybox is statically linked and the hook never loaded. Our real address is blanked.
curl -s https://httpbin.org/ip
proxychains4 -f proxychains.conf curl -s https://httpbin.org/ip
proxychains4 -f proxychains.conf busybox wget -qO- http://httpbin.org/ip

The third command is the one to remember. The tool printed its preloading line, never printed DLL init, and busybox went out on our real address with exit code 0. A statically linked program is not hooked, and it fails open. The Go FAQ notes that "the linker in the gc toolchain creates statically-linked binaries by default", which is why so many Go tools slip past the hook.

OK on the chain line is not proof either. In our probe of 38 public entries, 19 of the 20 socks5 entries opened the tunnel with OK and then handed curl a certificate it refused, with exit code 60 and "unable to get local issuer certificate". Three of them, tested again with verification switched off, returned a page as if nothing were wrong. An exit that presents its own certificate can read everything inside the connection. Never turn certificate checks off to make a chain "work".

For a fuller read on any exit, our proxy checker reports the exit address, the anonymity grade, the real location and the latency in one paste. The free proxy list is re-checked every few minutes and is the right pool for proving a setup. For work that has to keep running, our paid pools give you exits nobody else is burning.

What ProxyChains cannot do

  • Static binaries. Not hooked, and the traffic leaves direct with no error. Many Go tools are static. Test with the check above.
  • Setuid programs. The dynamic linker's manual says that in secure-execution mode "preload pathnames containing slashes are ignored", so an unprivileged user cannot hook a setuid program. The man page says you have to be root to run them through the tool.
  • UDP and ICMP. Never proxied. See the UDP section.
  • Programs that load modules with dlopen(). The README names Python and Perl, whose C modules escape the hook on glibc.
  • Windows. No LD_PRELOAD, so WSL or a Linux VM only.
  • macOS system binaries. System Integrity Protection blocks the hook. The README's workaround is a copy of the binary in your home directory, or partially disabling SIP.
  • Raw-packet tools. SYN scans, UDP scans and anything built on pcap go around the hook.

Where to go from here

Use dynamic_chain so one dead entry does not stop the job, leave proxy_dns on so hostnames stay off your resolver, and verify the exit every time because the tool fails open. The cURL guide covers the single-proxy flags that the wrapper complements. What is a SOCKS5 proxy explains the SOCKS layer most chains ride on. Proxies for web scraping covers choosing the right proxy type for the job. If the list should be rebuilt by a script rather than edited by hand, the proxy API reference covers ordering, plan generation and pulling the current endpoint list.

Sources

  • proxychains-ng README, version 4.17. rofl0r, GitHub, file last changed 26 April 2026. The mechanism, the config search order, the known problems with nmap, macOS and dlopen(), and the changelog.
  • proxychains-ng default configuration, src/proxychains.conf. rofl0r, GitHub, last changed 22 January 2022. The chain modes, proxy_dns, remote_dns_subnet, the timeouts and the ProxyList format.
  • proxychains-ng releases. rofl0r, GitHub. 4.17 published 21 January 2024; 4.14 on 16 March 2019.
  • Ubuntu package proxychains4 4.17-1 (noble). Canonical package index, Ubuntu 24.04.
  • proxychains4(1) manual page. Debian project, 11 July 2019, as shipped in Ubuntu 24.04. The config file list including /etc/proxychains4.conf and the note on suid programs.
  • ld.so(8), the dynamic linker manual. Linux man-pages project, man7.org. LD_PRELOAD and secure-execution mode.
  • Nmap Reference Guide: port scanning techniques and host discovery. Nmap project. The connect system call behind -sT, and -Pn.
  • Go FAQ, "Why is my trivial program such a large binary?". The Go project. Static linking by default.
  • RFC 1928, SOCKS Protocol Version 5. IETF, March 1996. The domain-name address type that carries a hostname to a SOCKS5 proxy, and the CONNECT, BIND and UDP ASSOCIATE commands.
  • SOCKS 4A: A Simple Extension to SOCKS 4 Protocol. Ying-Da Lee, NEC. The hostname form used for socks4 hops.
  • curl manual page, the --proxy option. curl project. The socks5h:// scheme that makes the proxy resolve the host name.
  • Our own run of 2 September 2026: proxychains4 4.17-1, curl 8.5.0, busybox-static 1.36.1 and nmap 7.94SVN on Ubuntu 24.04 under WSL2, with public entries from hproxy.com/free-proxy-list. Raw output is kept in the page's research folder.

Frequently asked questions

Does ProxyChains support UDP?
No. The maintainer's README states that it supports TCP only, with no UDP or ICMP. In our run, ping under proxychains4 got its reply straight from the network with no chain line at all, because ICMP never passes through the hook. A tool that needs UDP through a SOCKS5 proxy has to support SOCKS5 UDP itself.
Does ProxyChains leak DNS?
Not when proxy_dns is on, which it is in the shipped config. With it on, the program is handed a stand-in address from the 224.0.0.0/8 range and the hostname travels to the proxy, which resolves it. With it off, the program asks the local resolver first, so every hostname you visit reaches your resolver before the chain sees the connection. In our run curl -v showed Trying 224.0.0.1:443 with proxy_dns on and the real address with it off.
Does ProxyChains work on Windows?
Not natively. It depends on LD_PRELOAD, a feature of the Linux dynamic linker, so on Windows it runs only inside WSL or a Linux virtual machine. Every command in this guide was run in WSL2 with Ubuntu 24.04.
Where do I get a proxy list for ProxyChains?
Any http, socks4 or socks5 proxy works, with or without a password. Our free proxy API returns recently checked public entries as plain text, one ip:port per line, which a one-line sed turns into ProxyList lines. Public entries die within minutes, so for work that has to keep running use proxies you control.
Why does ProxyChains say no valid proxy found in config?
The ProxyList section is empty or every line in it is malformed. Lines are type ip port, with an optional user and password, and the ip must be numeric IPv4 unless the entry is a non-first hop in strict mode with proxy_dns on. Check that the line sits below the [ProxyList] header and that the type is http, socks4, socks5 or raw.
Why does proxychains4 not work with my Python script?
The README lists it as a known problem: the glibc dynamic linker does not apply the hook to modules loaded with dlopen(), and Python and Perl load their C modules that way. Run the interpreter with a proxy setting of its own, or use the proxy support of the library you call, such as the proxy argument in HTTPX or requests.
Why does ProxyChains not work on macOS?
System Integrity Protection blocks the hook for system binaries. The README's workarounds are to copy the binary into your home directory and run it from there, or to partially disable SIP. We measured Linux only.
Should I install proxychains, proxychains4 or proxychains-ng?
On Debian, Ubuntu and Kali install proxychains4. That package is proxychains-ng, the maintained line, and ships version 4.17-1 on Ubuntu 24.04. The package named proxychains is the old 3.1 line, and a package named proxychains-ng does not exist there.

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. $0.44/GB is the 2,000 GB+ rate; a single gigabyte is $0.50/GB, with no minimum order.

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

HProxy.

Honest guides and comparisons on proxies, scraping and staying unblocked, from the team that runs the network.

RSS feed