Nginx – Nginx Stream Proxy vs HTTP Proxy for SSL Termination

nginxreverse-proxy

I am running an HTTP service and want to put nginx in front for SSL termination. This can be done in two ways; either as a stream proxy

stream {
    server {
        listen               443 ssl;
        ssl_certificate      /certs/fullchain.pem;
        ssl_certificate_key  /certs/privkey.pem;
        proxy_pass           ip-for-backend-service:80;
    }
}

or as an http proxy

http {
    server {
        listen 443 ssl;
        ssl_certificate      /certs/fullchain.pem;
        ssl_certificate_key  /certs/privkey.pem;

        location / {
            proxy_pass       http://ip-for-backend-service:80;
            proxy_set_header ...;
        }
    }
}

From a quick glance it seems like that the configuration of the stream proxy is much simpler since you don't have to add a bunch of extra headers (proxy_set_header etc) and other configuration.

I am trying to understand the pros and cons between these two methods, and in particular I have the following questions:

  1. Will either method leak more information about the backend service? For example, will the ip-for-backend-service be visible?

  2. Will either method result in better protection from attacks? I guess if the backend service has flaws it will be visible/exploitable through both options?

  3. Which option is more efficient? I think that the stream option might be faster since it just routes the traffic and there is no http-server in the middle?

Best Answer

With both methods the upstream IP address will remain hidden.

As for the rest:

  • stream is certainly faster, since less code is executed. However both are well-written C code and when you compare it with network delays, the difference might not be noticeable.
  • With stream the upstream logs will only contain one client IP address (the address of the proxy server). This can be changed with the proxy_bind directive, but requires additional networking setup. On the other hand adding an X-Forwarded-For header in the http setup is straightforward:

    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    
  • With stream the upstream server needs to be manually configured to consider the incoming connection secure: e.g. Tomcat requires the addition of scheme="https" and secure="true" on the <Connector> element. Using the http proxy and a X-Forwarded-Proto header the upstream server can decide whether HTTP or HTTPS was used on a per-connection basis.

The question of the security of the setup is quite opinion-based:

  • Using the http proxy, you can limit the URI paths that will be proxied, hence you will not expose to the public the administrative part of your website,
  • On the other hand, by adding additional computational strain on your system (against the alternative of accessing the upstream server directly), you are more exposed to DDoS attacks.