Search code examples
nginxnginx-locationnginx-upstreams

Nginx to secure traffic


I'm trying to set-up a Nginx to secure external traffic to a docker service. My intention is to create a proxy with SSL certificates (letsencryptit) listening on the external IP, then route requests to different servers inside docker containers. So far I've managed to secure the external Nginx server. I tested it has access to static files, and SSL works fine.

Problem is, I tried to route a path to a not-secured nginx server hosting an Angular app, and it has some troubles.

  1. If I fetch the url ending on slash [/] it's fine.
  2. If I fetch the url with no slash I get this error
curl: (35) OpenSSL/3.0.8: error:0A00010B:SSL routines::wrong version number
  1. Angular routing messes with this config. The web-app has links from one view to others views, and clicking on them ends mixing the internal port and the external DNS name

My external, SSL-secured Nginx server config is this:

# web.conf
upstream project1 {
  server nginx:3000;
}

server {
  listen 443 default_server ssl http2;
  listen [::]:443 ssl http2;

  ssl_certificate /etc/letsencrypt/live/my.domain.some/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/my.domain.some/privkey.pem;

  include /etc/letsencrypt/options-ssl-nginx.conf;
  ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

  # Extra config
  add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; always";
  add_header X-Frame-Options SAMEORIGIN;
  add_header X-Content-Type-Options nosniff;
  add_header X-XSS-Protection "1; mode=block";

  server_name my.domain.some;

  location / {
    root /var/www/nginx;
  }

  location /test {
    proxy_pass http://project1;
    proxy_http_version 1.1;
    proxy_set_header    Upgrade         $http_upgrade;
    proxy_set_header    Host            $host;
    proxy_set_header    Connection      'upgrade';
    proxy_cache_bypass  $http_upgrade;
    # Extra config
    proxy_set_header    X-Real-IP           $remote_addr;
    proxy_set_header    X-Forwarded-For     $proxy_add_x_forwarded_for;
    # proxy_set_header    X-Forwarded-Proto   $scheme;
    proxy_set_header    X-Forwarded-Proto   https;
    proxy_set_header    X-Forwarded-Host    $host;
    proxy_set_header    X-Forwarded-Port    $server_port;
  }

}

The Angular project is hosted on another instance of Nginx, whose configuration is:

server {
  listen 3000;
  listen [::]:3000;

  root /var/www/nginx;

  server_tokens off;

  location /test {
    alias /var/www/nginx;
    autoindex off;
    index index.html index.htm;
    try_files $uri $uri/ /index.html;
  }
}

I've tried to proxy_pass both directly or using upstream, but it makes no difference curl on the url gets the expected result only if it's ended on slash

I expect curl -v -L https://my.domain.some/test (no final slash) to retrieve the Angular home page but it returns:

*   Trying 111.111.111.111:443...
* Connected to my.domain.some (111.111.111.111) port 443 (#0)
* ALPN: offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: /etc/ssl/certs
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Request CERT (13):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Certificate (11):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN: server accepted h2
* Server certificate:
*  subject: CN=my.domain.some
*  start date: May  5 13:49:51 2023 GMT
*  expire date: Aug  3 13:49:50 2023 GMT
*  subjectAltName: host "my.domain.some" matched cert's "my.domain.some"
*  issuer: C=US; O=Let's Encrypt; CN=R3
*  SSL certificate verify ok.
* using HTTP/2
* h2h3 [:method: GET]
* h2h3 [:path: /test]
* h2h3 [:scheme: https]
* h2h3 [:authority: my.domain.some]
* h2h3 [user-agent: curl/7.88.1]
* h2h3 [accept: */*]
* Using Stream ID: 1 (easy handle 0x55a78c81e680)
> GET /test HTTP/2
> Host: my.domain.some
> user-agent: curl/7.88.1
> accept: */*
> 
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* old SSL session ID is stale, removing
< HTTP/2 301 
< server: nginx/1.15.12
< date: Mon, 03 Jul 2023 15:42:05 GMT
< content-type: text/html
< content-length: 162
< location: http://my.domain.some:3000/test/
< strict-transport-security: max-age=31536000; includeSubDomains; always
< x-frame-options: SAMEORIGIN
< x-content-type-options: nosniff
< x-xss-protection: 1; mode=block
< 
* Ignoring the response-body
* Connection #0 to host my.domain.some left intact
* Clear auth, redirects to port from 443 to 3000
* Issue another request to this URL: 'http://my.domain.some:3000/test/'
* Switched from HTTP to HTTPS due to HSTS => https://my.domain.some:3000/test/
*   Trying 111.111.111.111:3000...
* Connected to my.domain.some (111.111.111.111) port 3000 (#1)
* ALPN: offers h2,http/1.1
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: /etc/ssl/certs
* OpenSSL/3.0.8: error:0A00010B:SSL routines::wrong version number
* Closing connection 1
curl: (35) OpenSSL/3.0.8: error:0A00010B:SSL routines::wrong version number

I've searched for this error code with no solutions so far.

I appreciate your effort and time. Thank you in advance


Solution

  • I've browsed many posts over the net for some time, now came to a solution. Simply adding a trailing slash to the location path triggers nginx's rewrite module, so it handles it as I expected,

    I modified this path on the web.conf for the seecured nginx and voilà

    ```
    server {
      ...
    
      location /test/ {   ## <<< Notice this path ends on slash!!
        proxy_pass http://project1;
        proxy_http_version 1.1;
        ...
      }
    }
    ```