3

I was following stack question How can I set up a letsencrypt SSL certificate and use it in a Spring Boot application? to configure my Springboot app to use https(certbot) but my Nginx is not redirecting properly to my application.

More context: I am using Cloudflare, to redirect www.example.com (my domain) requests to the machine where I have Nginx and my Springboot app. I want Nginx to redirect this http on port 80 requests to my application that is running on port 8443 (https). I have installed certbot (letsencrypt) certificates and set up my nginx config with those.

My configuration after generating my certificate is below:

Springboot application.properties

server.port=8443
security.require-ssl=true
server.ssl.key-store=/etc/letsencrypt/live/mydomain/keystore.p12
server.ssl.key-store-password=mydomain
server.ssl.keyStoreType=PKCS12
server.ssl.keyAlias=myAlias

Update 1 >> Nginx /etc/nginx/nginx.conf

pid /run/nginx.pid;

events {
    worker_connections 768;
}

http {

    log_format formatWithUpstreamLogging '[$time_local] $remote_addr - $remote_user - $server_name to: $upstream_addr: $request';

    access_log  /var/log/nginx/access.log formatWithUpstreamLogging;
    error_log   /var/log/nginx/error.log;

    server {

      listen 80;

      server_name www.example.com example.com;

      return 301 https://$server_name$request_uri;

    }

   # SSL configuration
    server {

       listen 443 ssl;
       server_name www.example.com example.com;

       ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; 
       ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

       location / {
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header Host $host;
                proxy_set_header X-NginX-Proxy true;
                proxy_pass https://localhost:8443/;
       }
    }
}    

Output of the command nginx -T

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
# configuration file /etc/nginx/nginx.conf:
pid /run/nginx.pid;

events {
    worker_connections 768;
}

http {

    log_format formatWithUpstreamLogging '[$time_local] $remote_addr - $remote_user - $server_name to: $upstream_addr: $request';

    access_log  /var/log/nginx/access.log formatWithUpstreamLogging;
    error_log   /var/log/nginx/error.log;

    server {    

      listen 80;

      server_name www.example.com example.com;

      return 301 https://$server_name$request_uri;

    }

   # SSL configuration
    server {

       listen 443 ssl;
       server_name www.example.com example.com;

       ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
       ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

        # managed by Certbot
       location / {
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header Host $host;
                proxy_set_header X-NginX-Proxy true;
                proxy_pass https://localhost:8443/;
       }
   }
}   

Output of the command nginx -T

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
# configuration file /etc/nginx/nginx.conf:
pid /run/nginx.pid;

events {
    worker_connections 768;
}

http {

    log_format formatWithUpstreamLogging '[$time_local] $remote_addr - $remote_user - $server_name to: $upstream_addr: $request';

    access_log  /var/log/nginx/access.log formatWithUpstreamLogging;
    error_log   /var/log/nginx/error.log;

    server {    

      listen 80;

      server_name www.example.com example.com;

      return 301 https://$server_name$request_uri;

    }

   # SSL configuration
    server {

       listen 443 ssl;
       server_name www.example.com example.com;

       ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
       ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

        # managed by Certbot
       location / {
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header Host $host;
                proxy_set_header X-NginX-Proxy true;
                proxy_pass https://localhost:8443/;
       }
   }
}   

Update 2 >>> Nginx /etc/nginx/nginx.conf

    pid /run/nginx.pid;

    events {
        worker_connections 768;
    }

    http {

        log_format formatWithUpstreamLogging '[$time_local] $remote_addr - $remote_user - $server_name to: $upstream_addr: $request';

        access_log  /var/log/nginx/access.log formatWithUpstreamLogging;
        error_log   /var/log/nginx/error.log;

    server {

      listen 80;

      server_name www.codeonblue.com.br codeonblue.com.br;

       ssl_certificate /etc/letsencrypt/live/codeonblue.com.br/fullchain.pem; # managed by Certbot
       ssl_certificate_key /etc/letsencrypt/live/codeonblue.com.br/privkey.pem;

        # managed by Certbot
       location / {
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header Host $host;
                proxy_set_header X-NginX-Proxy true;
                proxy_pass https://localhost:8443/;
       }


    }    
 }

When I start nginx and my springboot application and try to access www.example.com in Chrome I get this page (image below)

Error in Chrome

Here is what I get when I try to access by Firefox: enter image description here

Since /var/log/nginx/error.log had no entries I have check the access log and there are dozens of requests like this (though I only did one request):

Nginx access log (/var/log/nginx/access.log)

[06/Mar/2019:12:59:52 +0000] <same-IP-address> - - - www.example.com to: -: GET / HTTP/1.1

Here are the curl results:

curl -I https://www.example.com/

HTTP/1.1 301 Moved Permanently
Date: Wed, 06 Mar 2019 14:32:26 GMT
Content-Type: text/html
Connection: keep-alive
Set-Cookie: __cfduid=d330e880850b37d5a9870c1edb71ab8c01551882746; expires=Thu, 05-Mar-20 14:32:26 GMT; path=/; domain=.example.com; HttpOnly
Location: https://www.example.com/
Expect-CT: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
Server: cloudflare
CF-RAY: 4b3509fdb8e0c879-MIA

curl -I http://www.example.com/

HTTP/1.1 301 Moved Permanently
Date: Wed, 06 Mar 2019 14:32:56 GMT
Content-Type: text/html
Connection: keep-alive
Set-Cookie: __cfduid=d9e1f2908ee4037d46bffa6866549c3151551882776; expires=Thu, 05-Mar-20 14:32:56 GMT; path=/; domain=.example.com; HttpOnly
Location: https://www.example.com/
Server: cloudflare
CF-RAY: 4b350ab9d83fc895-MIA

Could anyone help me on this issue? What did I miss?

Update 3 >>> More changes in nginx.conf and cleaning cloudflare cache

Nginx /etc/nginx/nginx.conf

pid /run/nginx.pid;

events {
    worker_connections 768;
}

http {

    log_format formatWithUpstreamLogging '[$time_local] $remote_addr - $remote_user - $server_name to: $upstream_addr: $request';

    #main log format
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                               '$status $body_bytes_sent "$http_referer" '
                               '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log main;
    error_log   /var/log/nginx/error.log;

    server {

      listen 80;

      server_name www.codeonblue.com.br codeonblue.com.br;

       ssl_certificate /etc/letsencrypt/live/codeonblue.com.br/fullchain.pem; # managed by Certbot
       ssl_certificate_key /etc/letsencrypt/live/codeonblue.com.br/privkey.pem;

        # managed by Certbot
       location / {
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header Host $host;
                proxy_set_header X-NginX-Proxy true;
                proxy_pass https://localhost:8443/;
       }

    }
}

After this update part of the problem was solved:

Curl test

curl -I http://www.example.com
HTTP/1.1 200 
Date: Wed, 06 Mar 2019 22:19:11 GMT
Content-Type: text/html;charset=UTF-8
Connection: keep-alive
Set-Cookie: __cfduid=d3f91ee93c3657a851354dbb4f03741a31551910750; expires=Thu, 05-Mar-20 22:19:10 GMT; path=/; domain=.example.com; HttpOnly
Last-Modified: Wed, 06 Mar 2019 22:03:01 GMT
Accept-Ranges: bytes
Content-Language: en-US
Server: cloudflare
CF-RAY: 4b37b5b08cf05eb2-TPA

In the browsers Firefox / Chrome the front end part is visible as you can see in the picture below:

Firefox

Accessed from Firefox

Chrome

Accessed from Chrome

New issues:

  • The certificate being used is from cloudflare, not from certbot (letsencrypt). Chrome does not consider it good enough and keep showing as "Not secure".
  • The endpoint of my application is not been called I don't know why yet. Maybe I am calling the wrong address. How should I call my endpoint?

In the access log I have accessed:

  1. curl -I www.example.com.br
  2. Accessed http://www.example.com.br in Firefox
  3. Accessed http://www.example.com.br in Chrome
  4. Try to access my endpoint in Postman

Nginx access log (/var/log/nginx/access.log)

172.68.78.24 - - [06/Mar/2019:22:19:11 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/7.47.0" "<ip-address-of-my-machine>"

172.68.78.24 - - [06/Mar/2019:22:19:46 +0000] "GET / HTTP/1.1" 200 578 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:65.0) Gecko/20100101 Firefox/65.0" "<ip-address-of-my-machine>"
172.68.78.36 - - [06/Mar/2019:22:19:46 +0000] "GET /runtime.js HTTP/1.1" 200 6224 "https://www.example.com/" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:65.0) Gecko/20100101 Firefox/65.0" "<ip-address-of-my-machine>"
172.68.78.42 - - [06/Mar/2019:22:19:46 +0000] "GET /main.js HTTP/1.1" 200 19198 "https://www.example.com/" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:65.0) Gecko/20100101 Firefox/65.0" "<ip-address-of-my-machine>"
172.68.78.54 - - [06/Mar/2019:22:19:46 +0000] "GET /styles.js HTTP/1.1" 200 185363 "https://www.example.com/" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:65.0) Gecko/20100101 Firefox/65.0" "<ip-address-of-my-machine>"
172.68.78.96 - - [06/Mar/2019:22:19:46 +0000] "GET /polyfills.js HTTP/1.1" 200 228524 "https://www.example.com/" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:65.0) Gecko/20100101 Firefox/65.0" "<ip-address-of-my-machine>"
172.68.78.42 - - [06/Mar/2019:22:19:46 +0000] "GET /vendor.js HTTP/1.1" 200 6821593 "https://www.example.com/" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:65.0) Gecko/20100101 Firefox/65.0" "<ip-address-of-my-machine>"
172.68.78.18 - - [06/Mar/2019:22:19:48 +0000] "GET /favicon.ico HTTP/1.1" 200 5430 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:65.0) Gecko/20100101 Firefox/65.0" "<ip-address-of-my-machine>"

172.68.78.60 - - [06/Mar/2019:22:20:36 +0000] "GET / HTTP/1.1" 200 578 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36" "<ip-address-of-my-machine>"
172.68.78.60 - - [06/Mar/2019:22:21:33 +0000] "GET / HTTP/1.1" 200 578 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36" "<ip-address-of-my-machine>"
172.68.78.60 - - [06/Mar/2019:22:22:06 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36" "<ip-address-of-my-machine>"
221.229.166.47 - - [06/Mar/2019:22:32:53 +0000] "GET / HTTP/1.1" 200 578 "-" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1" "-"

172.68.78.60 - - [06/Mar/2019:22:44:06 +0000] "GET / HTTP/1.1" 200 578 "-" "PostmanRuntime/7.1.1" "<ip-address-of-my-machine>"

In Postman when I try to access the endpoint like:

https://www.example.com:8443/api/cars

I get a big output where I think this part is more important:

(...)
<title>www.example.com | 522: Connection timed out</title>
(...)
    <h2 class="cf-subheadline">Connection timed out</h2>
(...)
        <span class="cf-status-desc">www.example.com</span>
(...)
        <h2>What happened?</h2>
        <p>The initial connection between Cloudflare's network and the origin web server timed out. As a result, the web page can not be displayed.</p>
                <h5>If you're the owner of this website:</h5>
                   <span>Contact your hosting provider letting them know your web server is not completing requests. An Error 522 means that                         the request was able to connect to your web server, but that the request didn't finish. The most likely cause is that 
                         something on your server is hogging resources.
                   </span>
(...)

I presume the time out is due to the wrong way I am accessing my service / endpoint. So, how should I access it now? How can I set up nginx to use the certbot certificate instead of cloudflare's ?

James Freitas
  • 504
  • 2
  • 8
  • 21
  • I removed the line you said, restart the nginx and my app. After testing it the access.log did not change and the error.log has this: 2019/03/05 14:02:16 [warn] 26131#26131: server name "https://$server_name$request_uri" has suspicious symbols in /etc/nginx/nginx.conf:20. Why does it say it is suspicious? Same problem is still happening though – James Freitas Mar 05 '19 at 14:07
  • Braces removed and question updated as well. New restart of Nginx and my spring app but same problem still happens. – James Freitas Mar 06 '19 at 02:55
  • I have added the output of this command in my question. By the way thank you for your help so far. – James Freitas Mar 06 '19 at 12:18
  • After your last comment things changed. It seems some redirecting issue is happening now but I am not sure. You can see by the updates – James Freitas Mar 06 '19 at 13:31
  • Yes, I am using cloudflare. The goal is when the user does a http://www.example.com (port 80) request to my domain he or she be redirected to https://www.example.com where my application is running (port 8443). I am updating the question with curl results – James Freitas Mar 06 '19 at 14:40
  • If cloudflare is terminating SSL, you do not need SSL at the Nginx server. Cloudflare connects to your server's port 80 (not 443) – Richard Smith Mar 06 '19 at 14:55
  • I have removed ssl config from Nginx server. You can see on the update #2. Did I make it correctly? – James Freitas Mar 06 '19 at 15:16
  • Do you purge the Cloudflare cache? – Richard Smith Mar 06 '19 at 15:23
  • I did now that you said, then restarted Nginx and my app and cleaned the browser cache as well but still the same problem is happening – James Freitas Mar 06 '19 at 15:44
  • You have another redirect loop? You should use Curl to test the server, and check the corresponding access log entries (can you use default access log format - as it contains the status code which may be useful). Does your 8443 service have any log files? – Richard Smith Mar 06 '19 at 15:55
  • Part of the problem is solved as you can see in update 3 but I don't know how to set up the nginx to get certbot certificate instead cloudflare's. Plus, how could I use my endpoint now after this change? – James Freitas Mar 07 '19 at 00:24

3 Answers3

1

My problem is partially solved. Here is my scenario and the configuration I have used:

  • Application: Springboot + Angular6 (Springboot app uses ssl on port 8443 and is configured to use certbot certificates)

  • Domain Resolution: CloudFlare (configured to resolve DNS from my domain to the IP of my cloud server)

  • Cloud Server: Amazon Lightsail (linux machine in the cloud where Nginx and my application are running)

  • Web Server: Nginx (used in the Amazon machine to redirect http traffic on port 80 to https on port 8443 which is used by my springboot application )

Springboot application.properties

server.port=8443
security.require-ssl=true
server.ssl.key-store=/etc/letsencrypt/live/www.example.com/keystore.p12
server.ssl.key-store-password=www.example.com
server.ssl.keyStoreType=PKCS12
server.ssl.keyAlias=myAlias

How Angular 6 services should use the API

getAll(): Observable<any> {
   return this.http.get('/api/cars');  // production
}

Nginx /etc/nginx/nginx.conf

pid /run/nginx.pid;

events {
    worker_connections 768;
}

http {

    log_format formatWithUpstreamLogging '[$time_local] $remote_addr - $remote_user - $server_name to: $upstream_addr: $request';

    #main log format
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                               '$status $body_bytes_sent "$http_referer" '
                               '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log main;
    error_log   /var/log/nginx/error.log;

    server {

        listen 80;

        server_name www.example.com example.com;

        ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
        ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

        # managed by Certbot
        location / {
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header Host $host;
                proxy_set_header X-NginX-Proxy true;
                proxy_pass https://localhost:8443/;
                proxy_redirect http://localhost:8443/ https://localhost:8443/;
       }

    }

}

Other settings:

http traffic still is not being redirected to https by Nginx though

If anyone knows how to make this redirect work please let me know :)

Ps.: I would like to thank Richard Smith for all help and time spent on this question!

James Freitas
  • 504
  • 2
  • 8
  • 21
1

You need to add this to your server block:

# Redirect non-https traffic to https
if ($scheme != "https") {
    return 301 https://$host$request_uri;
}
Emmanuel Osimosu
  • 5,625
  • 2
  • 38
  • 39
0

I know this is old, but I'd like to share my Nginx configuration for other people who may end up in this post.

My entire configuration is larger, but the redirection part looks as follows:

server {
    listen 80;

    location / {
        return 301 https://$host:8443$request_uri;
    }
}

Basically, if you're serving the application on HTTPS using what Spring provides you don't need Proxy pass, ssl_certificate or anything else on Nginx. The configuration above will simply return a 301 Redirect to the browser when an HTTP request arrives to port 80.

Uyric
  • 646
  • 7
  • 17