Nginx as forward proxy for HTTPS

While I was able to successfully configure nginx to proxy HTTP traffic (using this guide), all attempts to proxy HTTPS requests resulted in code 400 (Bad Request).

Nginx debug logs weren't helpful at all:

2013/06/05 14:38:33 [info] 74946#0: *589
    client sent invalid request while reading client request line, client: 127.0.0.1,
    server: google.com, request: "CONNECT google.com:443 HTTP/1.1"

What are these CONNECT requests? Is it even possible to proxy_pass HTTPS requests in nginx?

Update

Need to add that a proxy server is part of my web development workflow/toolkit. It's a great way to test/debug client-side JavaScript in production environment (using rewrites before the proxy).

Also nginx's config language is arguably a programming language in it's own right. It has variables!


Solution 1:

Seems like nginx does not support forward proxy mode with SSL. You will need to use something like Squid instead. Here is a link with more explanation from nginx's author: HTTPS and nginx as Forward Proxy.

Solution 2:

Just to clarify: as I wrote on my blog's comment feed, nginx doesn't handle CONNECT method calls which are used to establish a raw TCP connection to a remote host through an HTTP proxy - which makes sense, considering that nginx is not supposed to work as a forward proxy, it just happens to work quite well for regular HTTP regardless.

Nginx just literally has no idea what to do with those method calls, that's why the error messages in the logs are rather useless. I've always found myself using privoxy for HTTPS: http://www.privoxy.org/ - it's insanely easy to set up, too. But it's still impossible to filter or mangle the content of HTTPS relays, because HTTPS connections are handled with a raw connection through the CONNECT method and the server has no idea what it's relaying.

Solution 3:

If you don't mind compiling nginx from source, you could install ngx_http_proxy_connect_module. The following worked for me in Debian 9 "Stretch" on a Raspberry Pi (after I added deb-src URLs to /etc/apt/sources.list and did apt-get update):

cd /tmp &&
apt-get source nginx &&
git clone https://github.com/chobits/ngx_http_proxy_connect_module &&
cd nginx-* &&
patch -p1 < ../ngx_http_proxy_connect_module/proxy_connect.patch &&
sudo apt-get install libpcre3-dev &&
./configure --add-module=/tmp/ngx_http_proxy_connect_module &&
make && sudo make install

Then edit /usr/local/nginx/conf/nginx.conf and make it look like this (I've included an example of domains you want to block, which works with both SSL and non-SSL proxying):

user www-data;
worker_processes auto;
events { }
http {
    server_names_hash_bucket_size 128;
    server {
        listen       8888;
        server_name  spam.example.com *.spam.example.com;
        server_name  spam2.example.com *.spam2.example.com;
        access_log off;
        return 404;
    }
    server {
        listen       8888;
        server_name ~.+;
        proxy_connect;
        proxy_max_temp_file_size 0;
        resolver 8.8.8.8;
        location / {
           proxy_pass http://$http_host;
           proxy_set_header Host $http_host;
        }
    }
}

Then run /usr/local/nginx/sbin/nginx. It will quite happily coexist with Debian's stock nginx package if you're also running a production webserver on port 80 and don't want to risk messing with that (but make sure to start the /usr/local version separately on boot); alternatively, with more configuration you could run both services from the nginx you've compiled. But if you do set your compiled nginx to run on a port that your firewall allows traffic to, beware you'd have to check manually for nginx security updates as the Debian package system will no longer do it for you.

Solution 4:

I just followed the instructions from Silas S. Brown and I was able to compile a Nginx binary which can deal with forwarding and SSL. I bundled everything together into a Docker image. The Dockerfile and the configuration is here on GitHub: https://github.com/reiz/nginx_proxy.

The Nginx Docker image in this Docker Hub repository can handle SSL connection and forwarding: https://hub.docker.com/r/reiz/nginx_proxy/.