2 way SSL between nginx and backend server - node.js

I have a backend server on Node.js and I am trying to setup 2 way SSL between Nginx and this backend server.
But I get an error as:
2015/11/02 06:51:02 [error] 12840#12840: *266 upstream SSL certificate does not match "myLocalMachine" while SSL handshaking to upstream,
and this is when I set proxy_ssl_verify on. If its off then it works fine. Following is my Nginx setup:
upstream myLocalMachine {
server MyPublicIP:8888;
}
server {
listen 8222 ssl;
proxy_cache two;
ssl_certificate /etc/nginx/ssl/server-cert.pem;
ssl_certificate_key /etc/nginx/ssl/server-key.pem;
ssl_client_certificate /etc/nginx/ssl/client-cert.pem;
ssl_verify_client on;
location / {
proxy_ssl_session_reuse off;
proxy_ssl_verify on;
proxy_ssl_trusted_certificate /etc/nginx/ssl/backend-server-cert.pem;
proxy_ssl_certificate /etc/nginx/ssl/server-cert.pem;
proxy_ssl_certificate_key /etc/nginx/ssl/server-key.pem;
proxy_ssl_password_file /etc/nginx/ssl/pwd.pass;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_pass https://myLocalMachine;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_cache_valid any 1m;
proxy_cache_min_uses 1;
#proxy_cache_bypass $cookie_nocache $arg_nocache$arg_comment;
proxy_cache_methods GET HEAD POST;
proxy_cache_key "$request_body";
}
}

Solution:
I had used url in certificates lets say: example.com but I was using some
custom name as myLocalMachine in upstream and proxy_pass which I replaced it with url.
Use url in upstream block & proxy_pass as below
upstream example.com {
# ip & ports are for examples
server 11.11.11.11:2222;
}
proxy_pass https://example.com;

Related

nodejs nginx 502 gateway error

I am trying to use a nodejs app behind an nginx reverse proxy to handle the ssl
I have my app running on localhost:2000. I can confirm this as working with a curl command.
This is my nginx setup:
# the IP(s) on which your node server is running. I chose port 3000.
upstream dreamingoftech.uk {
server 127.0.0.1:2000;
keepalive 16;
}
# the nginx server instance
server {
listen 0.0.0.0:80;
server_name dreamingoftech.uk;
return 301 https://$host$request_uri;
}
#HTTPS
server {
listen 443 ssl http2;
server_name dreamingoftech.uk;
access_log /var/log/nginx/dreamingoftech.log;
error_log /var/log/nginx/dreamingoftech.error.log debug;
ssl_certificate /etc/letsencrypt/live/dreamingoftech.uk/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/dreamingoftech.uk/privkey.pem;
include snippets/ssl-params.conf;
# pass the request to the node.js server with the correct headers and much more can be added, see nginx config options
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://dreamingoftech.uk/;
proxy_redirect off;
#proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "";
proxy_ssl_session_reuse off;
proxy_cache_bypass $http_upgrade;
}
}
if I now curl https://dreamingoftech.uk, it takes a while but I do get the webpage delivered. albeit with the message:
curl: (18) transfer closed with 1 bytes remaining to read
However when viewed from a browser I get a 502 gateway error.
I have checked the error log and this is the result: ERROR LOG
I can't understand why the reverse proxy is adding such a time delay into the process. Any ideas would be greatly appreciated.
PS: in the upstream config I have tried localhost instead of 127.0.0.1 to no avail
I have almost the same configuration. Can you try the following
You can redirect all http to https
server {
listen 80;
return 301 https://$host$request_uri;
}
or for a specific site like this
server {
server_name dreamingoftech.uk;
return 301 https://dreamingoftech.uk$request_uri;
}
but choose only one for your case
and then you make sure you node server is running on http mode and not https.
Also you mentioned that you run node on port 3000, then use port 3000 and not 2000 as I can see in your config.
After you confirm the above redirect all packets into localhost like this
server {
listen 443;
server_name dreamingoftech.uk;
ssl_certificate /etc/letsencrypt/live/dreamingoftech.uk/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/dreamingoftech.uk/privkey.pem;
ssl on;
ssl_session_cache builtin:1000 shared:SSL:10m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;
ssl_prefer_server_ciphers on;
location / {
proxy_set_header Host $host;
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;
# Fix the “It appears that your reverse proxy set up is broken" error.
proxy_pass http://localhost:3000;
proxy_read_timeout 90s;
proxy_redirect http://localhost:3000 https://dreamingoftech.uk;
}
}
Create a file and sum the above code put it in sites-available with a name like dreamingoftech.uk and the use ln -s to create a softlink into sites-enabled. go to your nginx.conf and make sure you include folder sites-enabled
Then must restart nginx to check if it works
#Stamos Thanks for your reply. I tried that but unfortunately it didn't work. I decided to try the most basic node app I could still using the basic modules I am using.
I tried this and it worked straight away.
The problem is with my app therefore. I will spend time rebuilding and testing step by step until I find the issue,
Thanks for your time!

Socket.io disconnects on http request

I'm running nginx for my node.js application on a AWS EC2 instance. I want to use websockets (socket.io) and normal http request/response. My problem is, whenever I have an active socket connection from my mobile device to the server and try to make a normal http request, the mobile device's socket.io error function is called with the message "502 Bad Gateway".
Only socket works. Only normal http request works as well.
I figured out, that this problem occurred after I setup nginx to use https only.
Here is my nginx config in /sites-enabled /sites-available:
server {
listen 80;
listen 443 ssl;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
if ($scheme != "https") {
rewrite ^ https://$host$request_uri? permanent;
}
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
}
}
Nginx error log:
[error] 14117#14117: *50 upstream prematurely closed connection while reading response header from upstream, client: 78.94.9.226, server: example.com, request: "GET /socket.io/?transport=polling&b64=1&sid=rgXMQhL6mbSET8ktAAAA HTTP/1.1", upstream: "http://127.0.0.1:3000/socket.io/?transport=polling&b64=1&sid=rgXMQhL6mbSET8ktAAAA", host: "example.com"
iOS error log:
LOG SocketIOClient: Handling event: error with data: ["Got unknown error from server <html>\r\n<head><title>502 Bad Gateway</title></head>\r\n<body bgcolor=\"white\">\r\n<center><h1>502 Bad Gateway</h1></center>\r\n<hr><center>nginx/1.10.3 (Ubuntu)</center>\r\n</body>\r\n</html>\r\n"]
If you need any more information, let me know!
I fixed the problem by myself. It was a really dumbass problem. I created a file inside my node.js server folder called access.log and told the morgan logger to write into the file. The thing I forgot was, that I'm using PM2 to restart the server whenever there is a change in code inside the server folder. So PM2 restarted the server every time I made a http request and the socket disconnected.
Change your nginx config into two blocks
server {
listen 80;
listen 443 ssl;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
if ($scheme != "https") {
rewrite ^ https://$host$request_uri? permanent;
}
location /socket.io {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
}
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
}
}
You want to only upgrade connection for socket.io and not other urls

Cross-domain WebSocket connection failed during WebSocket handshake: Unexpected response code: 400

I am trying to use socket.io in a Node js application. I have the application sitting on a subdomain and the front-end running on the www version of the domain.
Running the front-end and Node js service on the same domain is not an option.
Sending data back and forth from the client to the server seems to be working. I have sent data both ways and it has worked fine.
However, In the console of the browser I get the following error.
WebSocket connection to 'wss://subdomain.domain.com/socket.io/?EIO=3&transport=websocket&sid=6bNHWyXcCdlMI0HHAAAB' failed: Error during WebSocket handshake: Unexpected response code: 400
My Nginx configuration looks like this:
# HTTP - redirect all requests to HTTPS:
server {
listen 80;
listen [::]:80 default_server ipv6only=on;
return 301 https://$host$request_uri;
}
# HTTPS - proxy requests on to local Node.js app:
server {
listen 443;
server_name subdomain.domain.com;
ssl on;
# Use certificate and key provided by Let's Encrypt:
ssl_certificate /etc/letsencrypt/live/subdomain.domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/subdomain.domain.com/privkey.pem;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers '*******';
# Pass requests for / to localhost:3000:
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:3000/;
proxy_ssl_session_reuse off;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Connection "upgrade";
}
}
Both the client and the Node js are using https.
Does anyone know what is causing this issue and how it could be fixed?
Thank you
It looks like you forgot about Upgrade header. It's required if you want to use Nginx as a reverse proxy for WebSockets.
As said here, just try to add one more header:
proxy_set_header Upgrade $http_upgrade;

SSL on nginx acting as a reverse proxy to a node server

I need to access my nodejs api which is reverse proxied by a nginx server over https. To achieve that I generated a self signed cert at location /etc/nginx and then modified the nginx configuration like below:
server {
listen 443;
server_name api.something.com;
ssl_certificate /etc/nginx/cert.crt;
ssl_certificate_key /etc/nginx/cert.key;
ssl on;
add_header Strict-Transport-Security max-age=500;
location / {
proxy_pass http://10.132.176.xx:8888; #private ip
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 whenever I try to access https://api.something.com I always get a connection refused error in google chrome. Plain http works fine. Any clues?

Node js + Nginx + Amazon Linux + SSL

I have a node js application running on AWS linux server with ssl. I wanted to implement nginx to the same. I googled it and read that if I implement ssl in nginx then the node application runs on http. So I configured the nginx conf as follows and ran the node js application with normal http server:
listen 443 ssl;
server_name myserver.com;
ssl_certificate myserver.chained.crt;
ssl_certificate_key myserver.key;
ssl_client_certificate myserver.crt;
ssl_verify_client optional;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header VERIFIED $ssl_client_verify;
proxy_set_header DN $ssl_client_s_dn;
proxy_pass http://127.0.0.1:3000;
}
Now the application is running on http as well as https. I want the nginx to be implemented and through ssl and the application to run only on https.
Is my approach right and what am I missing?
I see you have the application running on port 3000, what you will want to do so that it only runs on https is to block all requests on port 3000 to the server (using a firewall or security group rules in aws), and for every request on port 80 you will want to redirect them to the https version (port 443). Something like this:
server {
listen 80;
server_name my.domain.com;
return 301 https://$server_name$request_uri;
}
I found the above rule in this answer on serverfault.
upstream app
{
server 127.0.0.1:3000;
}
server
{
listen 80;
listen 443 ssl;
server_name www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
client_header_buffer_size 64k;
large_client_header_buffers 4 64k;
if ($scheme = http) {
return 301 https://$server_name$request_uri;
}
location ~ ^/(assets/|images/|img/|javascript/|js/|css/|stylesheets/|flash/|media/|static/|robots.txt|humans.txt|favicon.ico) {
root /var/www/example.com/public/;
access_log off;
expires 24h;
}
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://app$uri$is_args$args;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}

Resources