23

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
    Commented May 11, 2021 at 22:00

2 Answers 2

11

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/;
  }
}
6
  • 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
    Commented May 31, 2017 at 0:00
  • 2
    @NJones: unfortunately no, that's what we had to go with. Commented Jun 29, 2017 at 18:51
  • 3
    What if everything must answer for the same domain www.example.com? Can an approach like this still work? Commented Mar 19, 2020 at 22:24
  • 5
    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
    Commented May 11, 2021 at 20:26
  • 1
    @Freedom_Ben you can have two server blocks on the same domain but listening on two different ports. Commented Aug 22, 2023 at 19:33
9

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/;
  }
}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .