socket.io + nginx + proxy problems - node.js

I have a socket.io webservice running port 8080 on my production server, it responds to http requests, but I think its having difficulty resolving the proxy when my client is sending over websocket protocols (ws://)
My client is telling me that the server is responding with a 400 (bad request) error, so something is either wrong on my client side, or my production server. Im banking on it being my production server, but neither myself or a co worker of mine can figure out where for sure.
These are the nginx configurations we have for our node.js production box.
I have replaced the real url with someapp.com
NGINX
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name app.someapp.com;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://127.0.0.1:3000;
}
}
server {
listen 8080;
server_name app.someapp.com;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://127.0.0.1:4000;
}
}
server {
listen 80;
server_name tools.someapp.com;
root /var/www/bbclient/dist;
location / {
try_files $uri $uri/ /index.html;
}
}
its a very small and simple socket.io node.js server running on port 8080 in production
Socket.IO
const app = require('express')()
const http = require('http').Server(app)
const io = require('socket.io')(http)
const bodyParser = require('body-parser')
app.use(bodyParser.urlencoded({ extended: true }))
app.use(bodyParser.json())
// this is not responding from the client
// this is working on localhost, but not in production
io.on('connection', (socket) => {
socket.on('USER_ID', (userId) => {
if (socket.userId) {
socket.leave(socket.userId)
}
socket.userId = userId
socket.join(userId)
})
})
// this works over http, and responds in production
// by visiting http://app.someapp.com:8080 in the browser
app.get('/', (req, res) => {
res.send('some app')
})
http.listen(process.env.PORT || '8888', () => {
console.log('listening')
})
Here is what the network tab is saying about the request coming from my client resulting in a 400 error.
chrome browser network tab
Edit 1
NGINX error logs:
2018/02/06 17:30:39 [error] 5954#5954: *86956 upstream timed out (110: Connection timed out) while reading response header from upstream, client: 76.218.92.156, server: app.someapp.com, request: "GET /socket.io/?EIO=3&transport=polling&t=M5iAdrw&sid=Jays0pqU3StUhdjjAACb HTTP/1.1", upstream: "http://127.0.0.1:4000/socket.io/?EIO=3&transport=polling&t=M5iAdrw&sid=Jays0pqU3StUhdjjAACb", host: "someapp.com:8080", referrer: "http://tools.someapp.com/scorecards/estimating"

First of all add socket.io proxy directives:
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
Here's an example.
Then try to increase proxy connection timeout:
proxy_connect_timeout 75s;
proxy_read_timeout 75s;
proxy_send_timeout 75s;

Related

Using Nginx as proxy for Node.js' Express and Socket.io

I want to run an express server and a socket.io server on an node.js instance which are reachable through nginx. If possible, I would favor to run them both on the same port, but I did not reach that goal either.
I can reach the webserver locally and from extern.
I can only reach the socket server locally.
When I call the page, my browsers log shows the following error:
GET https://example.com/socket.io/?EIO=3&transport=polling&t=O6qCW5Y
400 Bad Request
So I think the problem lies somewhere in the nginx config.
My app.js code for the socket.io server:
const http = require('http').createServer();
const io = require('socket.io')(http);
http.listen(3001, () => {
console.log('Socket-Server listening on port: 3001');
});
io.on('connection', (socket) => {
...
});
My code for the client:
window.onload = function() {
const socket = io.connect('https://box-api.com/');
socket.on('connect', () => {
...
}
}
My nginx config:
server {
server_name example.com;
root /nodejs/example.com;
include static_files.conf;
index app.js;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
}
location /socket.io {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_pass http://127.0.0.1:3001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# Certbot stuff
...
}

NodeJs socket.io via nginx proxy No 'Access-Control-Allow-Origin' header is present on the requested resource

I'm really quite confused, i have a socket.io node app listening behind a reverse nginx proxy and i am getting this error:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
I have nginx setup like this:
upstream chat {
ip_hash;
server 192.168.0.2:3004;
server 192.168.0.3:3004;
server 192.168.0.5:3004;
}
server {
listen 443 ssl;
ssl_certificate /usr/local/etc/ssl/certs/live/gofollow.vip/cert.pem;
ssl_certificate_key /usr/local/etc/ssl/certs/live/gofollow.vip/privkey.pem;
ssl_session_timeout 10m;
ssl_verify_client off;
server_name chat.example.com;
error_log /usr/share/nginx/logs/error-chat.log;
access_log /usr/share/nginx/logs/access-chat.log;
client_max_body_size 1024M;
location / {
proxy_next_upstream error timeout http_502;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_next_upstream_tries 10;
proxy_pass http://chat;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host chat.example.com;
proxy_set_header X-Real-IP $remote_addr;
proxy_ssl_session_reuse on;
proxy_hide_header Access-Control-Allow-Origin;
proxy_set_header Origin https://example.com;
add_header Access-Control-Allow-Origin $http_origin;
proxy_set_header Referer $host:$server_port;
proxy_http_version 1.1;
proxy_set_header X-XSS-Protection 1;
proxy_set_header X-Content-Type-Options nosniff;
proxy_set_header Referrer-Policy origin;
proxy_set_header X-Frame-Options DENY;
proxy_request_buffering off;
}
}
It's using long polling over https, so i would connect to this proxy on https://chat.example.com which would then use the upstream to send the traffic to port 3004. On the other side i have a docker container mapping port 3004 -> 8000 so the node app is then listening on port 8000:
const socket = require("socket.io");
const express = require("express");
const http = require("http");
const redis = require("redis");
const mysql = require('mysql');
const cors = require('cors');
// create the socket
const app = express();
app.use(cors());
const port = process.env.CHAT_PORT || 3001;
const server = http.createServer(app);
const io = socket(server, {
cors:{
origin: '*',
methods: ["GET","POST"]
}
});
// server listen on port
server.listen(port, () => console.log("PORT CONNECTED %d",port));
I clearly have the cors headers set on both the socket and the express https connection so i don't know what it's talking about. I actually have other hosts running through the proxy to other docker containers running for example php, or another internal nginx server and they are not having this issue.
Obviously i must have something wrong but i can't see what?
Note: There are multiple servers in the upstream as the socket server is running on a docker swarm.

Docker + Node.JS + Socket.IO + Nginx (405 & Bad handshake method)

I have a docker containerized application with react front-end and nodeJS/PHP backend (working on different containers). I've successfully installed https with an intermediate container (let'sencrypt certbot) for my front-end build and PHP backend, but have some problem with socket pooling to nodejs backend. When socket.io pooling starts I got the error on POST request:
[POST] https://my.domain/socket.io/?EIO=3&transport=polling&t=MlE0IBv
405 Not Allowed
When I tried to prevent this by next Nginx construction:
error_page 405 #nodejs;
I got the same error code with the next message:
code: 2 message: "Bad handshake method"
There is part of my Nginx configuration (nginx is separate docker container):
upstream node {
ip_hash;
server node:4000; //nodejs container
}
server {
listen 80;
// ...redirect to https
}
server {
listen 443 ssl;
// .... cert's and other settings
// front-end static react build
location / {
try_files $uri /index.html =404;
}
location /static {
try_files $uri #nodejs;
}
location #nodejs {
proxy_pass http://node;
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;
}
// without this string i just got "405 Not Allowed" nginx error page
// with this string i got probably nodejs "Bad handshake method" error
error_page 405 #nodejs;
}
My app.js server code:
const express = require('express');
const http = require('http');
const socketIO = require('socket.io');
const socketRouter = require('./sockets/index');
const app = express();
const server = http.Server(app);
const io = socketIO(server, {origins: '*:*'});
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
io.on('connection', socketRouter.bind({}, io));
module.exports = server;
And index.js:
require('dotenv').config();
const app = require('./src/app');
const PORT = process.env.APP_PORT || 4000;
app.listen(PORT);
console.log('Application started on Port ' + PORT);
console.log('APP_ENV ' + process.env.APP_ENV);
Problem was solved. The correct config is:
location /static {
try_files $uri =404;
}
location /socket.io {
proxy_pass http://node;
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;
add_header Front-End-Https on;
}
error_page 405 #nodejs;

Nginx Proxy Pass on SSL is not Considering Listening URL

I am currently trying to set up nginx virtual server blocks, which I have me absolutely ripping my hair out.
Essentially, I have a NodeJS instance running on a droplet at DigitalOcean. The point of this application, is to host both a website as well as an api. I want both of these to run on the same droplet.
I have set up my NodeJS app with express to create the routing and so on, and then create an http server with the express app. As my explanation might cause confusion, I have included the essentials of the code below:
const API_PORT = 8080;
const WEB_PORT = 8081;
const api = express();
const web = express();
web.use(express.static(path.join(__dirname, '../build')));
web.get('//', (req, res) => {
res.sendFile(path.join(__dirname, '../build', 'index.html'));
})
api.use((req, res, next) => {
const ip = (req. headers['x-forwarded-for'] || '').split(',').pop()
|| req.connection.remoteAddress
|| req.socket.remoteAddress
|| req.connection.socket.remoteAddress
if (req.headers.auth !== AUTHCODE) {
httpError(400, 'Validation failed');
console.warn('Bad Auth Code');
console.warn(req.headers.auth);
console.warn(ip);
return (res.json('Validation failed'));
}
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', '*');
res.setHeader('Access-Control-Allow-Headers', '*');
next();
});
Graph.route(api);
const apiServer = http.createServer(api);
const webServer = http.createServer(web);
apiServer.listen(WEB_PORT, '127.0.0.1', () => {
console.log(`API Server is running on port ${API_PORT}`);
});
webServer.listen(API_PORT, '127.0.0.1', () => {
console.log(`WEB Server is running on port ${WEB_PORT}`);
});
What I want to achieve is shown in the code above, but essentially I am trying to have a my api server listening to port 8080, and my website server to listen on port 8081.
I was told that I could use nginx to create a proxy_pass for this although I have not managed to make it work as intended. Below you see two examples of what I tried to do !
Anyone able to help me out would forever be my hero !
server {
listen lace.guide:443 ssl;
server_name lace.guide www.lace.guide;
ssl_certificate /var/my-server/ssl/myapp.crt;
ssl_certificate_key /var/my-server/ssl/myapp.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
location / {
proxy_pass http://127.0.0.1:8080/$request_uri;
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;
}
}
server {
listen api.lace.guide:443 ssl default_server;
server_name api.lace.guide www.api.lace.guide;
ssl_certificate /var/my-server/ssl/myapp.crt;
ssl_certificate_key /var/my-server/ssl/myapp.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
location / {
proxy_pass http://127.0.0.1:8081/$request_uri;
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 am also having another quite peculiar error which means that if I access my api.lace.url/something/somethingElse it actually hits //something/somethingElse on my server (console.log from req.url)
Here is an example of how server and client live on one server and are being managed with nginx (ssl setup omitted for simplicity). All request prefixed with /api get routed to the server and the rest - to the client.
upstream client {
server client:3000;
}
upstream api {
server api:5000;
}
server {
listen 80;
location / {
proxy_pass http://client;
}
location /api {
proxy_set_header X-Forwarded-For $remote_addr;
rewrite /api/(.*) /$1 break;
proxy_pass http://api;
}
}

Deploy Nginx, Socket IO, Linode 404 error

I have been struggling trying to deploy a NodeJS server as SocketIO server on Linode. I have deployed my Django projects that works fine and I have redirected a subdomain to talk to the node server listening on port 8002 of local host.
I get a 404 error in my nginx log.
"GET /socket.io/?EIO=3&transport=polling HTTP/1.1" 404 72 "-" "Dalvik/2.1.0 (Linux; U; Android 5.0.1; LG-D850 Build/LRX21Y)"
Here is my nginx config
server {
listen 80;
server_name www.domain.com;
location / {
proxy_pass http://127.0.0.1:8000;
}
location /static {
alias /home/exampledir/staticfiles;
}
access_log /home/exampledir/nginx-access.log;
error_log /home/exampledir/nginx-error.log info;
}
server {
listen 80;
server subdomain.domain.com;
location / {
proxy_pass http://127.0.0.1:8002;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
}
}
Here is my nodejs server file
var socket = require('socket.io');
var express = require('express');
var http = require('http');
var app = express();
var server = http.createServer(app);
server.listen(8002, '127.0.0.1');
var io = socket.listen(server);
var redis = require('redis');
var sub = redis.createClient();
sub.subscribe('notify');
io.on('connection', function(socket){
socket.on('join', function (data) {
...
});
});
//Grab message from Redis and send to client
sub.on('message', function(channel, message){
...
});
I have tried using CORS and stuff but it does not work just keeps giving me a 404. I have verified the node server is running at 127.0.0.1:8002
My android socket is connecting to
mSocket = IO.socket("http://subdomain.domain.com/);
Please help.
Try this config
server {
listen 80;
# Make site accessible from http://localhost/
server_name domain.com;
location / {
proxy_pass http://127.0.0.1:8000;
}
location / {
proxy_pass http://127.0.0.1:8000;
}
location /static {
alias /home/example-dir/staticfiles;
}
access_log /home/example-dir/nginx-access.log;
error_log /home/example-dir/nginx-error.log info;
}
server {
listen 80;
server_name subdomain.domain.com;
location / {
proxy_pass http://127.0.0.1:8002;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
}
access_log /home/example-dir/socketnginx-access.log;
error_log /home/example-dir/socketnginx-error.log info;
}

Resources