https nginx 403 forbidden - node.js

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

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.

wss connection to node ws server via nginx, ERR_CERT_AUTHORITY_INVALID

I have a websocket server running behind nginx.
Connecting via http works ok (ws://mywebsite.com) with following nginx config:
http {
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /usr/share/nginx/html;
location /myWebSocket {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://localhost:5000;
}
}
}
I'd like to connect to this via https (wss://mywebsite.com) and have tried this:
http {
server {
listen 443 ssl http2 ;
listen [::]:443 ssl http2 ;
server_name mywebsite.com; # managed by Certbot
root /usr/share/nginx/html;
ssl_certificate /etc/mycert.pem;
ssl_certificate_key /etc/mykey.pem;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 10m;
ssl_ciphers PROFILE=SYSTEM;
ssl_prefer_server_ciphers on;
location /myWebSocket {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass http://localhost:5000;
}
}
}
However, I get a ERR_CERT_AUTHORITY_INVALID on the browser side (e.g. with wss://myWebsite/myWebSocket).
My understanding is that WSS is a connection to a standard websocket via https, is this correct?
Is my approach above correct?
Is there something obvious I'm doing wrong?
To confirm the cert was installed with certbot, and the e.g. https://example.com works.
Note also, there is another server block listening on 443, this does not define the /myWebSocket location (I think it is the nginx default ssl block that is superceded by certbot block).
Edit: note removing that first ssl server block results in the browser side websocket connection error message changing to ERR_CERT_COMMON_NAME_INVALID.
Another Edit: I was connecting using the server's IP address not the DNS name - that removed the error. :-)

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.

Nginx to handle SSL for WebSockets

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).

Nginx server IP on droplet redirect to specific domain

I have 2 domains running with nginx on a DigitalOcean Droplet
Domain1 is an node app proxypassing to localhost:3000.
Works great!
Domain2 is a static site working great too.
However whenever I load the server IP (without the port 3000), I always get redirected to domain1 (node app).
Domain1 is a sort of a private site, whereas domain2 is a public blog.
My question is what do I have to change for people to get redirected to domain2 whenever they load the IP in order to protect domain1 from beeing easily reachable. (The VPS IP is easy to look up)
Here are the "sites-available" files :
Node App :
server {
listen [::]:80;
listen 80;
server_name www.domain1.com domain1.com;
# and redirect to the https host (declared below)
return 301 https://domain1.com$request_uri;
}
server {
listen 443;
server_name domain1.com www.domain1.com;
ssl on;
# Use certificate and key provided by Let's Encrypt:
ssl_certificate /etc/letsencrypt/live/domain1.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/domain1.com/privkey.pem;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://localhost:3000/;
proxy_ssl_session_reuse off;
proxy_set_header Host $http_host;
proxy_cache_bypass $http_upgrade;
proxy_redirect off;
}
}
And the static one :
server {
listen [::]:80;
listen 80;
server_name www.domain2.com domain2.com;
root /var/www/html/domain2;
index index.html index.htm;
return 301 https://domain2.com$request_uri;
}
server {
listen [::]:443 ssl;
listen 443 ssl;
root /var/www/html/domain2;
index index.html index.htm;
ssl_certificate /etc/letsencrypt/live/domain2.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/domain2.com/privkey.pem;
}
Any help/hint is appreciated, thank you in advance!
So both your domains are listening on port 80. When your nginx server receives a request, it then checks the domain before determining its route... but because there is no domain to check when you just type in the ip address, it will default to the first listed server (which i'm guessing is domain1)
you can circumvent this by declaring a default server, or switching the order in which they are listed.
I hope i could be of help. A nice little reference http://nginx.org/en/docs/http/request_processing.html

Resources