I have server A with IP, which does not have a connection to the internet so it must pass all internet http traffic to a squid proxy on server B with ip listening on port 8080.

I used the following rule which does establish a connection to the squid proxy, however I get back a 400 bad request error when I initiate a wget:

iptables -t nat -A OUTPUT -p tcp --dport 80 -j DNAT --to-destination IP:8080


wget external.example.net/v4/Picture/pic1.jpg
--2015-09-05 18:42:01--  http://external.example.net/v4/Picture/pic1.jpg
Resolving external.example.net...,,, ...
Connecting to external.example.net||:80... connected.
HTTP request sent, awaiting response... 400 Bad Request
2015-09-05 18:42:01 ERROR 400: Bad Request.

When I check the squid log I see the domain is missing from the url.

1 NONE/400 1186 GET /v4/Picture/pic1.jpg - NONE/- -

If I use bash http_proxy instead of the iptables rule I can successfully download the image and squid logs the complete url

export http_proxy=
wget external.example.net/v4/Picture/pic1.jpg


2015-09-05 18:55:48--  http://external.example.net/v4/Picture/pic1.jpg
Connecting to connected.
Proxy request sent, awaiting response... 200 OK
Length: 83760 (82K) [image/jpeg]
Saving to: `pic1.jpg'

Squid log

 7 TCP_HIT/200 84455 GET http://external.example.net/v4/Picture/pic1.jpg - NONE/- image/jpeg

Why doesn't my first request work?


This isn't quite how proxies work.

When you send a request through an HTTP proxy, it looks something like this, where proxy.example.net is the proxy, and target.example.net is the site you're trying to get:

GET http://target.example.net/path/to/resource HTTP/1.1
Host: proxy.example.net

This is illustrative, because you'll notice the URL used to make that HTTP request to the proxy is this:


When you use DNAT to simply redirect the traffic, wget will resolve target.example.net and send the path part of the URI as the request body instead of the URL to proxy, and so it sends only this:

GET /path/to/resource HTTP/1.1
Host: target.example.net

The squid server is understandably confused by this, since it isn't target.example.net and isn't serving a document at /path/to/resource.

If you configure squid to be a transparent proxy, you can actually do this, with the following directives, for squid prior to version 2.6:

httpd_accel_host virtual
httpd_accel_port 8080
httpd_accel_with_proxy on
httpd_accel_uses_host_header on

That last one, httpd_accel_uses_host_header on, tells squid to use the Host: header from my examples above (which requires HTTP 1.1) to figure out where to get the resource from, instead of using the explicit proxy request I mentioned above. See http://squidconfiguration.com/config-manual-2-4/httpd-accelerator-options/httpd_accel_uses_host_header/.

For newer versions of squid (3.1 and up), use this listen directive:

http_port 8080 intercept

See here: http://www.squid-cache.org/Doc/config/http_port/

For some older versions of squid, it's "transparent" and not "intercept".

And a good tutorial from the squid wiki: http://wiki.squid-cache.org/ConfigExamples/Intercept/LinuxRedirect

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.