nginx proxy based on host when using https
Asked Answered
S

3

16

I need to use Nginx as an SSL proxy, which forwards traffic to different back ends depending on the subdomain.

I have seem everywhere that I should define multiple "server {" sections but that doesn't work correctly for SSL. Doing that I would always have the SSL being processed in the first virtual host as the server name is unknown until you process the https traffic.

Scenario:

  • One IP address
  • One SSL wildcard wildcard
  • Multiple backends which needs to be accessed like the following:

    https://one.mysite.com/ -> http://localhost:8080
    https://two.mysite.com/ -> http://localhost:8090
    

Nginx says "if" is evil: http://wiki.nginx.org/IfIsEvil, but what else can I do?

I have tried this, but it doesn't work, I get an 500 error but nothing in the error logs.

    server {
    listen 443;
    server_name *.mysite.com;

    ssl on;
    ssl_certificate ssl/mysite.com.crt;
    ssl_certificate_key ssl/mysite.com.key;

    location / {
        if ($server_name ~ "one.mysite.com") {
            proxy_pass http://localhost:8080;
        }
        if ($server_name ~ "two.mysite.com") {
            proxy_pass http://localhost:8090;
        }
    }

Has anyone managed to accomplish this with Nginx? Any help/alternatives, link, would be much appreciated.

Skipp answered 19/8, 2013 at 17:34 Comment(0)
S
28

I found the solution which is basically to define the SSL options and the SSL certificate outside the "server" block:

ssl_certificate ssl/mysite.com.crt;
ssl_certificate_key ssl/mysite.com.key;
ssl_session_timeout  5m;
ssl_protocols        SSLv3 TLSv1;
ssl_ciphers          ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+EXP;
ssl_prefer_server_ciphers   on;

server {
    listen 80;
    server_name *.mysite.com;
    rewrite ^ https://$host$request_uri? permanent;
}
server {
    listen 443 ssl;
    server_name one.mysite.com;

    ssl on;

    location / {
        proxy_pass http://localhost:8080;
    }
}
server {
    listen 443 ssl;
    server_name two.mysite.com;

    ssl on;

    location / {
        proxy_pass http://localhost:8090;
    }
}

Key things:

  • "ssl on;" is the only thing that needs to be within the "server" blocks that listen in https, you can put it outside too, but what will make the "server" blocks that listen in port 80 to use https protocol and not the expected http.
  • Because the "ssl_certificate", "ssl_ciphers: and other "ssl_*" are outside the "server" block, Nginx does the SSL offloading without a server_name. Which is what it should do, as the SSL decryption cannot happen based on any host name, as at this stage the URL is encrypted.
  • JAVA and curl don't fail to work now. There is no server_name - host miss match.
Skipp answered 20/8, 2013 at 14:44 Comment(1)
Thanks, this info was very helpful to me. FYI: I found out that when you use listen 443 ssl; you don't also need to do ssl on; because nginx will turn on SSL mode for you. Source: nginx.org/en/docs/http/ngx_http_core_module.html#listenMccarthy
D
4

The short answer is to use Server Name Indication. This should work by default in common browsers and cURL.

Disfigure answered 20/8, 2013 at 16:13 Comment(0)
T
1

according to http://www.informit.com/articles/article.aspx?p=1994795, you should indeed have two "server" sections, with two different server names. In each one, you should include your ssl_* directives.

Tutuila answered 19/8, 2013 at 18:24 Comment(2)
There one problem with that, let me explain it with an example: if you have you have two "server" sections with SSL listening in port 443 Nginx will do the SSL decription using the first virtualhost, because it still doesn't know what domain you have. Once the domain can be matched it will execute the directives of the right virtual host but the SSL decription will happen in the wrong virtual host. JAVA and curl (possibly more SSL clients) will fail because there is mismatch with the host name and the domain actually used.Skipp
This is what SNI fixes. Most reasonably modern browsers support it now, which makes life significantly simpler.Pavkovic

© 2022 - 2024 — McMap. All rights reserved.