18

We use Nginx as a reverse proxy to our web application server. Nginx handles our SSL and such but otherwise just acts as a reverse proxy.

We want to require a valid client cert for requests to /jsonrpc but not require them anywhere else. The best way we've found is to

server {
  listen       *:443 ssl;

  ssl on;
  ssl_certificate         /etc/nginx/server.crt;
  ssl_certificate_key     /etc/nginx/server.key;
  ssl_client_certificate  /etc/nginx/client-ca.crt;

  ssl_verify_client optional;

  location /jsonrpc {
    if ($ssl_client_verify != "SUCCESS") { return 403; }

    proxy_pass          http://localhost:8282/jsonrpc-api;
    proxy_read_timeout  90;
    proxy_redirect      http://localhost/ $scheme://$host:$server_port/;
  }
}

This works fine for most browsers, but some browsers such as Safari and Chrome-on-Android end up prompting the user to provide a client cert no matter where on the website they go.

How do we get Nginx to accept but not really care about a client cert everywhere except our /jsonrpc location?

1
  • Can anybody comment on whether this is still an issue on any semi-recent browser?
    – ntninja
    May 11 at 22:00
10

Why not to try second server block instead? Code duplication is bad but sometimes unavoidable. I assume /jsonrpc represents an API so it can use its own subdomain if not already use it:

server {
  listen       *:443 ssl;
  server_name api.example.com;

  ssl on;
  ssl_certificate         /etc/nginx/server.crt;
  ssl_certificate_key     /etc/nginx/server.key;
  ssl_client_certificate  /etc/nginx/client-ca.crt;

  ssl_verify_client on;

  location =/jsonrpc {
    proxy_pass          http://localhost:8282/jsonrpc-api;
    proxy_read_timeout  90;
    proxy_redirect      http://localhost/ $scheme://$host:$server_port/;
  }
}

server {
  listen       *:443 ssl;

  ssl on;
  ssl_certificate         /etc/nginx/server.crt;
  ssl_certificate_key     /etc/nginx/server.key;
  ssl_client_certificate  /etc/nginx/client-ca.crt;

  ssl_verify_client off;

  location / {
    proxy_pass          http://localhost:8282/;
    proxy_read_timeout  90;
    proxy_redirect      http://localhost/ $scheme://$host:$server_port/;
  }
}
5
  • This is what we'll probably end up doing if we can't figure out a way to put the right configuration all in the same server block. We haven't had this same issue when using Apache, so I'd hoped there was some setting that would work here. Sep 13 '15 at 19:03
  • 1
    @EliCourtwright I know this question was a long time ago, but did you ever find a solution better than two server blocks?
    – N Jones
    May 31 '17 at 0:00
  • 2
    @NJones: unfortunately no, that's what we had to go with. Jun 29 '17 at 18:51
  • 1
    What if everything must answer for the same domain www.example.com? Can an approach like this still work? Mar 19 '20 at 22:24
  • The reason this works in Apache is mentioned in passing in the SSLVerifyClient docs: […] In per-directory context [this directive] forces a SSL renegotiation with the reconfigured client verification level after the HTTP request was read but before the HTTP response is sent. – Needless to say that nginx doesn't offer that option…
    – ntninja
    May 11 at 20:26
1

Stumbled over this question while looking for something else.

Perhaps I misunderstood the question:

But shouldn't following work.

This has two location settings, but only one server setting.

server {
  listen       *:443 ssl;
  server_name api.example.com;

  ssl on;
  ssl_certificate         /etc/nginx/server.crt;
  ssl_certificate_key     /etc/nginx/server.key;
  ssl_client_certificate  /etc/nginx/client-ca.crt;

 ssl_verify_client optional;

  location =/jsonrpc {
    if ($ssl_client_verify != "SUCCESS") { return 403; }
    proxy_pass          http://localhost:8282/jsonrpc-api;
    proxy_read_timeout  90;
    proxy_redirect      http://localhost/ $scheme://$host:$server_port/;
  }

  location / {
    proxy_pass          http://localhost:8282/;
    proxy_read_timeout  90;
    proxy_redirect      http://localhost/ $scheme://$host:$server_port/;
  }
}

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.