Can not access NodeJS apps after installing Let's Encrypt and configuring nginx

sure. in a couple of minutes.

grep -i include /etc/nginx/nginx.conf

     include /etc/nginx/mime.types;
    	include /etc/nginx/conf.d/*.conf;
    	include /etc/nginx/sites-enabled/*;

ls -la /etc/nginx/sites-available/

total 28
drwxr-xr-x 2 root root 4096 Sep 22 10:49 .
drwxr-xr-x 6 root root 4096 Sep 19 08:15 ..
-rw-r--r-- 1 root root 4349 Sep 22 08:18 default
-rw-r--r-- 1 root root 4348 Sep 20 08:04 default_backup
-rw-r--r-- 1 root root 2074 Apr 26  2016 default-backup

ls -la /etc/nginx/sites-enabled/

total 8
drwxr-xr-x 2 root root 4096 May 29 05:55 .
drwxr-xr-x 6 root root 4096 Sep 19 08:15 ..
lrwxrwxrwx 1 root root   34 May 29 05:55 default -> /etc/nginx/sites-available/default

grep -ri ‘server_name.*w3rpractice.com’ /etc/nginx/

/etc/nginx/sites-available/default_backup:    server_name w3rpractice.com;
/etc/nginx/sites-available/default:    server_name w3rpractice.com;

Well, now I have removed other two file default_backup, restarted nginx, it is still not working.

@rtwk2010, I see no problem. With that conf, nginx should only load /etc/nginx/sites-available/default and if the content is the same you pasted a few posts above, it should work fine, at least it does in my test machine.

Just in case, move the other available files outside that dir:

mkdir /etc/nginx/backup-sites-available/
mv /etc/nginx/sites-available/{default-backup,default_backup} /etc/nginx/backup-sites-available/

And restart/reload nginx

If using systemd:
systemctl reload nginx

If using initd
service nginx reload

And try again.

If that doesn’t work, remove the SSL part of your conf just to be sure it is affecting your conf:

server {
    listen 80;

    server_name w3rpractice.com;

    location /home/user1/apps/app1.js {
    proxy_pass http://0.0.0.0:9117;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_read_timeout 43200000;

    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    
    }
   
    location /home/user1/apps/app2.js {
    proxy_pass http://0.0.0.0:9118;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_read_timeout 43200000;

    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    location /home/user1/apps/app3.js {
    proxy_pass http://0.0.0.0:9130;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_read_timeout 43200000;

    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    }
}

Restart nginx and try whether it is working fine without ssl.

If that doesn’t work then I run out of ideas :frowning:

Cheers,
sahsanu

It may be problem with the application itself. Assume I have an application like this:

var express = require('express')
var app = express();

app.get('/', function (req, res) {
  res.send('Hello World!')
})

app.listen(3000, function () {
  console.log('Example app listening on port 3000!')
})

Now when SSL is set it’s not working. May be because it is not integrated with SSL. How to do that?

Hi @rtwk2010,

Add a trailing slash to your proxy_pass directives:

Example with app2:

Before:
proxy_pass http://0.0.0.0:9118;

After:
proxy_pass http://0.0.0.0:9118/;

Restart nginx and try again.

Cheers,
sahsanu

Tried that. Not working.

app1 --> http://0.0.0.0:9117
app2 --> http://0.0.0.0:9118
app3 --> http://0.0.0.0:9130

You are not doing load balancing here.you are running three apps, under same domain .But you are accessing it as domain.com:port . I dont think https://domain:[0-65535] under same ssl certs works or not .I never done that before . It should be configured like

domain --> http://0.0.0.0:9117
sub domain1 --> http://0.0.0.0:9118
sub domain2 --> http://0.0.0.0:9130

Whenever you are using nodejs app under production , you should call the domain.com . not domain.com:9123 . the purpose of proxy_pass becomes useless. so make a sub domain for every app and apply webroot . sure it will work .

Thanks for your suggestions. But domain.com:port accepts the data sent and
process. It used to work before SSL was implemented. Can you say whether
the nodejs app should include ssl certificate? I have posted a small
snippet of express code in a post above, would you please tell me if it
requires to be integrated with ssl and if so an example of how to that. I
know with createserver one may create an https server, but here I am not
using any http server.

yes i am aware that domain.com:port is accessible since you have allowed the port via firewall. Its not a best practice to allow those ports outside servers.Thats the reason we are using proxy_pass . which means domain.com is linked with http://localhost:9118 . so we can call domain.com directly .no need to specify ports.Thanks

for letsencrypt it needs a document root to verify its domain by creating .well-known folder inside its document root . so for node js , since we are using proxy_pass , we can provide any document root we want with an index.html file in it . now create letsencrypt certificate for that domain .use it for main app [nodejs ].do not use it for app2, app3 . now create a sub domains , get certs and integrate it with node js apps .

[or]

"letsencrypt-express - npm" this link will help you for what you have asked

@rtwk2010,

When I told you yesterday to put the trailing slash in your proxy_pass directive was becasue I did test it and it worked. Indeed doesn't matter if you are not using SSL, it didn't work too using plain http so it is really strange that it worked on your machine.

This is my conf, I just cloned the one you pasted, changed the server_name, the path to my certificates and instead of use the include calling to options-ssl-nginx.conf I used the content of this file directly.

server {
    listen 80;

    server_name acme1.dicito.net;

    location /home/user1/apps/app1.js {
    proxy_pass http://0.0.0.0:9117;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_read_timeout 43200000;

    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    }

    location /home/user1/apps/app2.js {
    proxy_pass http://0.0.0.0:9118/;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_read_timeout 43200000;

    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    location /home/user1/apps/app3.js {
    proxy_pass http://0.0.0.0:9130;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_read_timeout 43200000;

    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }


    listen 443 ssl; # managed by Certbot
    ssl_certificate /root/.acme.sh/acme1.dicito.net/fullchain.cer; # managed by Certbot
    ssl_certificate_key /root/.acme.sh/acme1.dicito.net/acme1.dicito.net.key; # managed by Certbot

    #include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_session_cache shared:le_nginx_SSL:1m;
    ssl_session_timeout 1440m;

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;

    ssl_ciphers "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS";


    if ($scheme != "https") {
        return 301 https://$host$request_uri;
    } # managed by Certbot

}

Now I've created 2 apps using the example you posted:

1.- app1.js is listening on port 9117 and it should return this message app1 running on port 9117. And I configured it in nginx without trailing slash on proxy_pass directive.

proxy_pass http://0.0.0.0:9117;

The app1.js file contains this:

var express = require('express')
var app = express();

app.get('/', function (req, res) {
  res.send('app1 running on port 9117')
})

app.listen(9117, function () {
  console.log('Example app listening on port 9117!')
})

If I try to reach this app you can see that it is redirected from http to https and after that I get a 404 not found error.

$ curl -ikL http://acme1.dicito.net/home/user1/apps/app1.js
HTTP/1.1 301 Moved Permanently
Server: nginx/1.6.2
Date: Sat, 23 Sep 2017 09:02:26 GMT
Content-Type: text/html
Content-Length: 184
Connection: keep-alive
Location: https://acme1.dicito.net/home/user1/apps/app1.js

HTTP/1.1 404 Not Found
Server: nginx/1.6.2
Date: Sat, 23 Sep 2017 09:02:27 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 162
Connection: keep-alive
X-Powered-By: Express
Content-Security-Policy: default-src 'self'
X-Content-Type-Options: nosniff

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>Cannot GET /home/user1/apps/app1.js</pre>
</body>
</html>

2.- app2.js is listening on port 9118 and it should return this message app2 running on port 9118. And I configured it in nginx with trailing slash on proxy_pass directive.

proxy_pass http://0.0.0.0:9118/;

The app2.js file contains this:

var express = require('express')
var app = express();

app.get('/', function (req, res) {
  res.send('app2 running on port 9118')
})

app.listen(9118, function () {
  console.log('Example app listening on port 9118!')
})

If I try to reach this app you can see that it is redirected from http to https and I get the right message.

$ curl -ikL http://acme1.dicito.net/home/user1/apps/app2.js
HTTP/1.1 301 Moved Permanently
Server: nginx/1.6.2
Date: Sat, 23 Sep 2017 09:04:29 GMT
Content-Type: text/html
Content-Length: 184
Connection: keep-alive
Location: https://acme1.dicito.net/home/user1/apps/app2.js

HTTP/1.1 200 OK
Server: nginx/1.6.2
Date: Sat, 23 Sep 2017 09:04:30 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 25
Connection: keep-alive
X-Powered-By: Express
ETag: W/"19-7cZ1YONwHGWGSmR4y1ENOOY/4wY"

app2 running on port 9118                               

So, using your conf in my test machine:

1.- It doesn't work neither using only http nor https.
2.- It works putting just a trailing slash in proxy_pass directive and it works on http and https.

If you want to test it, the server will be up and running a few hours.

http://acme1.dicito.net/home/user1/apps/app1.js
http://acme1.dicito.net/home/user1/apps/app2.js

There is no need to include a ssl cert in your app, you are using nginx as a proxy and it is terminating the TLS conversation.

I hope someone could help you to solve your issue, it works on my machine with the proxy_pass change and I can't reproduce your issues so sorry, I'm giving up.

Good luck,
sahsanu

2 Likes

Very useful suggestion. Now since I am running several applications, how to
make the server understand which request is for which application?
That is why I mentioned port. Do you think it does not work that way in
https? But there should not be any reason.

When I am sending request through Ajax, my code is like

xhr.open("POST", "https://w3rpractice.com:9118", true);

Do you think that is ok?

@rtwk2010,

No, you can’t access via https to port 9118 you need to access https://w3rpractice.com/home/user1/apps/app2.js.

Cheers,
sahsanu

server {
 listen 80;

server_name mydomain.com;

location /home/user1/apps/app1.js {
proxy_pass http://0.0.0.0:9117;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 43200000;

proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

}

}

this is for one app . make a separate config . and try generating ssl cert and check whether the redirection works for one domain .

When I do that, it spits following error in browser console:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://w3rpractice.com/home/w3r/editor/editor_python.js. (Reason: CORS header 'Access-Control-Allow-Origin' missing).

Sorry, I've no answer: http://bfy.tw/E5e7

add_header Access-Control-Allow-Origin *;

try adding it in config .

any luck with single domain ?