Nginx to handle SSL for WebSockets - node.js

I'm very new to Nginx and I'm feeling like a monkey trapped inside a nuclear power plant facility — nothing makes any sense — and I desperately want to get some bananas.
Anyway, I'm using Nginx server for handling SSL and proxying all requests to the NodeJS app. Everything works just fine except for WebSockets. The client gives me an ERR_INSECURE_RESPONSE error. The server is live. What am I missing? What would you advice?
NodeJS
const express = require('express')
const app = express()
const server = require('http').Server(app)
const io = require('socket.io')(server)
app.use(express.static('../app'))
io.on('connection', (socket) => {
console.log('CONNECTED')
})
server.listen(5000)
Nginx config (taken from this tutorial Deploying a NodeJS app with ssl)
# HTTP — redirect all traffic to HTTPS
server {
listen 80;
listen [::]:80 default_server ipv6only=on;
return 301 https://$host$request_uri;
}
# HTTPS — proxy all requests to the Node app
server {
# Enable HTTP/2
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name olmeo.us;
# Use the Let’s Encrypt certificates
ssl_certificate /etc/letsencrypt/live/olmeo.us/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/olmeo.us/privkey.pem;
# Include the SSL configuration from cipherli.st
include snippets/ssl-params.conf;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://localhost:5000/;
proxy_ssl_session_reuse off;
proxy_set_header Host $http_host;
proxy_cache_bypass $http_upgrade;
proxy_redirect off;
}
}
SSL config (include snippets/ssl-params.conf)
# See https://cipherli.st/ for details on this configuration
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
ssl_ecdh_curve secp384r1; # Requires nginx >= 1.1.0
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off; # Requires nginx >= 1.5.9
ssl_stapling on; # Requires nginx >= 1.3.7
ssl_stapling_verify on; # Requires nginx => 1.3.7
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
# Add our strong Diffie-Hellman group
ssl_dhparam /etc/ssl/certs/dhparam.pem;
Client
io.connect('https://52.29.55.217')

Your SSL certificate is likely provided for a given domain, not for the IP address and you are using the IP and not a domain to connect:
io.connect('https://52.29.55.217')
Unless your certificate includes that IP address in the list of hosts that it covers (highly unlikely) then this will not work. Try it with the exact domain name that was used while creating the certificate with Let's Encrypt (not a subdomain, not an IP, the exact domain name).

Related

Nginx proxy to node.js server SSL ERR_SSL_PROTOCOL_ERROR

EDIT:
I have verified that nodejs is running on the correct port, on http, and I have also tried with and without:
app.use('trust proxy', true);
EDIT 2:
I turned off the nodejs server and tried to serve static files just with nginx, and the error persists, so clearly this has something to do with nginx and my ssl cert.
My domain is a free domain from freenom and the ssl certificate was generated with certbot.
Original:
I have a nodejs server running, and want to use nginx and proxy to the nodejs server. (Nginx https -> nodejs http)
Running nginx -t gives no errors.
On ubuntu 20.04.2, nginx 1.18.0 node 14.5.5
I have verified that my site works fine via http (on port 3000), but i get the following error when visiting via browser on https:
ERR_SSL_PROTOCOL_ERROR
Further if i use openssl cli to try and connect, I get this
openssl s_client -connect my_domain.com:443 -servername my_domain.com
CONNECTED(00000003)
139662603941184:error:1408F10B:SSL routines:ssl3_get_record:wrong version number:../ssl/record/ssl3_record.c:331:
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 5 bytes and written 310 bytes
Verification: OK
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)
---
/etc/nginx/conf.d/ssl.conf
server {
listen 443 ssl;
ssl_certificate /server/resources/cert.pem;
ssl_certificate_key /server/resources/privkey.pem;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
If you use Cloudflare, It may Cloudflare not issued SSL certificate for you yet, or Cloudflare failed to connect to origin with secure connection. Check your dashboard.
Following is the working configuration of nginx.conf
I have also setup SSL with certbot + letsencrypt.
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2 default_server;
listen [::]:443 ssl http2 default_server;
server_name example.com www.example.com;
root "/home/ubuntu/domain/code/directory/path/";
index index.html index.htm;
client_max_body_size 75M; # adjust to taste
location /api {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_read_timeout 600s;
}
location / {
try_files $uri $uri/ /index.html;
}
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_session_timeout 1h;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
add_header Strict-Transport-Security “max-age=15768000” always;
ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
}
I guess the above configuration might solve your issue.
URL is https://www.example.com/api/ping redirects to http://localhost:3000/api/ping on the server.

https nginx 403 forbidden

I create droplet on DigitalOcean, setup my nodeJS app on it, connected my domain and everything works ok, but I wanted to setup https andI installed all certificates etc. I run it on CentOS 7.5, my nodeJS app is in this directory:
/home/mdurakovic/mensurdurakovic.com
HTTP works fine, but I when I try to open my website with HTTPS I get error message in browser
403 Forbidden nginx/1.12.2
So I looked up in nginx logs and I see this error:
2019/01/02 23:03:39 [error] 11014#0: *1 directory index of "/home/mdurakovic/mensurdurakovic.com/public/" is forbidden, client: 213.149.62.113, server: mensurdurakovic.com, request: "GET / HTTP/2.0", host: "mensurdurakovic.com"
I changed group permissions so when I execute this command:
f: /home/mdurakovic/mensurdurakovic.com/public/
dr-xr-xr-x root root /
drwxr-xr-x root root home
drwx--x--- mdurakovic nginx mdurakovic
drwxrwxrwx nginx nginx mensurdurakovic.com
drwxrwxrwx nginx nginx public
As you can clearly see, nginx has rights to execute user's home dir, but it still doesn't work. Any help will be appreciated.
EDIT:
Here is my /etc/nginx/conf.d/mensurdurakovic.com.conf file:
server {
listen 80;
server_name mensurdurakovic.com;
location / {
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://68.183.69.186:8080;
}
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name mensurdurakovic.com;
root /home/mdurakovic/mensurdurakovic.com/public;
# certs sent to the client in SERVER HELLO are concatenated in ssl_certificate
ssl_certificate /etc/letsencrypt/live/mensurdurakovic.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mensurdurakovic.com/privkey.pem;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;
# intermediate configuration. tweak to your needs.
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
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-$
ssl_prefer_server_ciphers on;
# HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months)
add_header Strict-Transport-Security max-age=15768000;
resolver 8.8.8.8;
}
You are having your http connection proxy the request, but not https. If you add a block in your ssl config (and remove root and resolver) it should work as expected:
location / {
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://68.183.69.186:8080;
}

NGINX Only pass requests coming from main domain

My current NGInx setup is such that it takes all requests from Http and redirects them to HTTPS and then it passes the request to my Node server running on Unbutu localhost.
My quest is, how do I make it so it only accepts requests coming from my app.domain.com (which is hosted somewhere else) and my api.domain.com which is hosted on my Ubuntu cloud. So if you visit api.domain.com you will never get passed to the Node server or if you send a request from anywhere else than app.domain.com you will also never get passed to the Node server.
server {
listen 80;
listen [::]:80 default_server ipv6only=on;
return 301 https://$host$request_uri;
}
# HTTPS — proxy all requests to the Node app
server {
# Enable HTTP/2
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name api.maindomain.com;
# Use the Let’s Encrypt certificates
ssl_certificate /etc/letsencrypt/live/api.maindomain.com/xxxx.pem;
ssl_certificate_key /etc/letsencrypt/live/api.maindomain.com/xxx.pem;
# Include the SSL configuration from cipherli.st
include snippets/ssl-params.conf;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://localhost:xxxx/;
proxy_ssl_session_reuse off;
proxy_set_header Host $http_host;
proxy_cache_bypass $http_upgrade;
proxy_redirect off;
}
}

Unable to show domain name instead of IP with nginx

I configured a node.js api in digitaloceans and I'm trying to show mydomain.com instead of the IP Server using nginx. I have the following configuration in my default nginx config:
server {
keepalive_timeout 30;
listen server_ip:443 ssl;
ssl_certificate /tmp/mycrt.crt;
ssl_certificate_key /tmp/mykey.key;
ssl_session_cache shared:SSL:10m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_session_timeout 10m;
server_name _;
location / {
proxy_pass http://server_ip:8000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;}
}
I configured the domain record with domain_name A IP_Server. It redirects to my server but it change to https://server_ip instead of https://my_domain.com.
What I'm missing?
Thanks you.
You need to add following code in the config file:
server {
listen 80;
# Listen to your server ip address
server_name your-server-ip;
# Redirect all traffic comming from your-server-ip to your domain
return 301 $scheme://example.com$request_uri;
}
For more details follow steps from here.
I solve it following this guide
Thanks you.

NodeJs + Nginx .. upstream prematurely closed connection while reading response header fro m upstream

My website was running on port 80 (http) and I was using nginx without any problem. Below is default file that I was using in nginx
server {
listen 80;
server_name www.example.com;
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
Now I am planning to use https and downloaded Lets encrypt certs.Currently I am not able to access the website. I am getting following error .
*[error] 754#754: 1 upstream prematurely closed connection while reading response header fro
m upstream, client: xxx.xx.xxx.xxx, server: example.com, request: "GET /favicon.ico HTTP/2.0", upstream: "h
ttp://127.0.0.1:3000/favicon.ico", host: "www.exapmple.com", referrer: "https://www.example.com/"
Below is my default file from nginx
# HTTP — redirect all traffic to HTTPS
server {
listen 80;
listen [::]:80 default_server ipv6only=on;
return 301 https://$host$request_uri;
}
server {
listen 443 default_server ssl;
listen [::]:443 ssl http2;
server_name example.com www.example.com;
# certs sent to the client in SERVER HELLO are concatenated in ssl_certificate
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;
# intermediate configuration. tweak to your needs.
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
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';
ssl_prefer_server_ciphers on;
# HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months)
add_header Strict-Transport-Security max-age=15768000;
# OCSP Stapling ---
# fetch OCSP records from URL in ssl_certificate and cache them
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8;
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
My nodejs code is as follows
var app = express();
var port = 3000;
var server = https.createServer(app).listen(port, function() {
console.log("Application connected on port " + port);
});
and server is running at port 3000.
Thanks in advance.. J
This issue is resolved now. Problem was with nodejs code.
I changed above code to
var app = express();
var port = 3000;
var server = app.listen(port, function() {
console.log("Application connected on port " + port);
});
https.createserver calls the http.server() internally and creates the instance.
so by removing this, the error got resolved.
Thanks for help !!
this reason is because you request url has space, "h ttp://127.0.0.1:3000/favicon.ico",and node http server doesn't support url has uncoded space,so you may delete the space or use net server instead. wish to solve you problem

Resources