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
Related
I am setting up nginx so that I can access my API built using express through a url like - example.com/api
Here is my nginx config
upstream appfrontend {
server localhost:9008 fail_timeout=0;
}
upstream api {
server localhost:3001;
}
server {
listen 80;
listen [::]:80;
server_name hospoline.com www.hospoline.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
listen [::]:443;
server_name example.com; # replace this with your domain
root /var/www/html/example-certbot-webroot;
# The public and private parts of the certificate are linked here
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
location /.well-known {
root /var/www/html/example;
}
location / {
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://appfrontend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 900s;
}
location /api {
proxy_pass http://api;
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;
}
}
When I visit my site example.com the front end loads perfectly.
When I visit example.com/api/fetch_doctors, I get a 502 bad gateway error.
My API is working fine in localhost. When I send a request to localhost:3001 on my local computer, I get the list of doctors.
Both my front end server and backend server are run using forever.
I am really lost and breaking my head about this for one full day. I have no idea where I'm going wrong. Any help in the right direction would be great! Thank you all!
I am using a simple "hello world" Express.JS (8080 port) application deployed in Ubuntu Server, with NGINX reverse proxy setup as below.
The application working well for http port but not for https port
nginx version: nginx/1.10.3 (Ubuntu)
OpenSSL 1.0.2g 1 Mar 2016
And my configuration file is like this:
server {
listen 80;
listen 443 default ssl;
server_name localhost;
ssl_certificate /root/mydir/ssl/certificate.crt;
ssl_certificate_key /root/mydir/ssl/private.key;
location / {
proxy_pass http://localhost:8080;
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;
}
}
The configuration is working fine for http connection for my domain testdomain.com, but completely failing for https://testdomain.com or https://www.testdomain.com
What went wrong with this configuration?
SSL certs are generated by sslforfree.com.
server {
listen 80;
server_name example.com;
# force redirect http to https
rewrite ^ https://$http_host$request_uri? permanent;
}
server {
listen 443;
ssl on;
ssl_certificate /root/mydir/ssl/certificate.crt;
ssl_certificate_key /root/mydir/ssl/private.key;
server_name example.com;
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto https;
....
}
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;
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";
}
}
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;