nginx and express router get+post request issue - node.js

I am trying to setup the 2 node/express sites behind nginx. I think I have tried all possible solutions that I found in the forums, but they only work partially for me.
What I want to achive is:
- one domain with 2 node/express apps
1.) node.dev/site3
2.) node.dev/site4
This works all okay for the main index file, however selecting any button/Route I get a 404 error.
Here is the nginx setup:
server {
listen 80;
root /var/www/node.dev;
server_name node.dev;
index index.htm index.html;
access_log /var/log/nginx/node;
charset utf8;
sendfile off;
location /site3/ {
proxy_pass http://0.0.0.0:8088/;
#rewrite ^/site3/(.*)$ /$1 break;
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 Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_cache_bypass $http_upgrade;
}
location /site4/ {
proxy_pass http://0.0.0.0:8080;
#rewrite ^/site4/(.*)$ /$1 break;
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_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_cache_bypass $http_upgrade;
}
}
and this is my Express route setup:
var express = require('express');
module.exports = function(app) {
var router = express.Router();
router.get('/ping', function(req, res){
res.send("pong!", 200);
});
router.get('/walk/:walk_name', function(req, res, next) {
res.send("walk!", 200);
});
router.get('/walk', function(req, res, next) {
res.send("No walker!", 200);
});
router.get('*', function(req, res) {
res.sendfile('./public/index.html'); // load the single view file (angular will handle the page changes on the front-end)
});
app.use('/', router);
}
accessing the site with //node.dev/site3 returns the index file as expected, however clicking on WALK for example, it should return //node.dev/site3/walk, but instead it returns http://node.dev/walk and with that a 404 error.
I can't do any changes in the node/express app. Is there any way to achieve this with the nginx configuration.
Please help. Thanks in advance.

Try setting proxy_pass to 127.0.0.1 not 0.0.0.0. The former means "localhost" the latter means "any host". While you might listen on "any ip", you want to connect to a /specific/ IP.
There may be another issue, but this might help.

Related

Websocket (Socket.io) works on my local machine but not on NGINX

I have worked on an application using node.js and express for the backend and reactjs for the frontend.
On the nodejs backend, set up socket.io as such
const port = process.env.PORT || 8000
const server = app.listen(port, () =>
console.log(`Server running on port ${port}`)
)
const io = require('socket.io')(server, {
cors: {
origin: '*',
},
})
Then on the react frontend, I sent up the socket.io for client as:
if (!socket.current) {
socket.current = io(process.env.REACT_APP_API2)
}
Where my REACT_APP_API2='http://localhost:8000' while my api is connected on REACT_APP_API='http://localhost:8000/api'
Locally, this works very well and my websocket connects and works well.
But in production, i get the error wss://+ myDomain + .com:3000/ws connection failed:
This is how I set up my NGINX Server
I first set up this '/' to point to the root (React APP)
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;
}
NEXT, I Set up /api to point to the backend api
location /api {
proxy_pass http://localhost: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;
}
Finally, I set this /socket.io for my sockets.
location /socket.io {
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 false;
proxy_pass http://localhost:8000;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
This is how i set up my enviromment variables in my frontend
REACT_APP_API = '/api'
REACT_APP_API2 = '/'
What I have tried:
I have changed the REACT_APP_API2 to '/api'
I have changed the proxy_pass http://localhost:8000; to 3000
NB: my application on nginx is secure ie 'https'

Socket.io with Nodejs not working with nginx reverse proxy

I have a Nodejs server app with Express and Socket.io (Ubuntu 18.04). It always worked fine until nGinx (1.14) reverse proxy entered the scene. The nginx server is running on a different machine of Node.js apps, each app on it's own vm, inside the same network.
Server and Client on version 2.1.1.
The nginx server is responsible for multiple app redirects.
I tried several configuration combinations but nothing works.
Here what I've tried (examples for "company1"):
default.conf in /etc/nginx/conf.d
location /company1-srv/ {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-NginX-Proxy true;
proxy_redirect off;
proxy_pass http://172.16.0.25:51001/;
}
Then in the client code I connect using "path" options because socket.io misplace it's library path.
// companySrv and URL is actually returned by another service (following code is for illustrative purposes):
let companyUrl = 'https://api.myserver.com/company1-srv';
let companySrv = '/company1-srv';
socket(companyUrl, {
path: companySrv + '/socket.io/'
});
I also tried to remove the path option and configured a specific /location for the socket.io stuff (for testing purposes):
location /socket.io/ {
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_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-NginX-Proxy true;
proxy_redirect off;
proxy_pass http://172.16.0.25:51001/socket.io/;
}
Nothing worked.
It connects, but does'n emits anything. And after a short while (a minute or so), it becomes unavailable, raising the "disconnect" (reason: transport close) client event.
Server:
const io = require('socket.io')(https || http, {
transports: ['polling', 'websocket'],
allowUpgrades: true,
pingInterval: 60000*60*24,
pingTimeout: 60000*60*24
});
I also tried to edit the nginx.conf and write the "upstream socket_nodes { ..." and use the proxy_pass http://socket_nodes. It didn't make sense as I need a exact redirect depending on the company, but for the sake of tests I did, but it doesn't work as well.
What I need to do?
Thanks
We as well use socket.io with reverse-proxy from ngnix. I can share a little bit of our setup, maybe it helps to rule things out.
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 768;
}
stream {
log_format basic '$time_iso8601 $remote_addr '
'$protocol $status $bytes_sent $bytes_received '
'$session_time $upstream_addr '
'"$upstream_bytes_sent" "$upstream_bytes_received" "$upstream_connect_time"';
access_log /var/log/nginx/stream.log basic;
}
http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
gzip on;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
##
# Server Blocks
##
# DOMAINEXAMPLE A
server {
server_name exampleA.domain.com;
location / {
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://192.168.21.105:5050;
}
}
# DOMAINEXAMPLE B
server {
server_name exampleB.domain.com;
location /api {
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://192.168.21.106:5050;
}
}
}
The most interesting part here are probably the server blocks
# DOMAINEXAMPLE A
server {
server_name exampleA.domain.com;
location / {
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://192.168.21.105:5050;
}
}
# DOMAINEXAMPLE B
server {
server_name exampleB.domain.com;
location /api {
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://192.168.21.106:5050;
}
}
Domain Example A
For location / at http://192.168.21.105:5050 we have a NodeJS process running, including the setup for socket.io
const express = require('express');
const http = require('http');
const app = express();
const server = http.createServer(app);
const io = require('socket.io')(server);
Domain Example B
For location /api at http://192.168.21.106:5050 we have another NodeJS process running, including a slightly different setup for socket.io
const express = require('express');
const http = require('http');
const app = express();
const server = http.createServer(app);
const io = require('socket.io')(server, {path: '/api/socket.io'});
In both cases socket.io works perfectly fine for us
Connecting from Client (Example B)
What we actually do on the server side here is creating a namespace for socket.io, like
const io= require('socket.io')(server, {path: '/api/socket.io'});
const nsp = io.of('/api/frontend');
and then on the client side , connect to it like
import io from 'socket.io-client'
const socket = io('https://exampleB.domain.com/api/frontend', {path: "/api/socket.io"});

Socket.io set cookie with nginx

My app architecture is here.
front-server 3000 - domain.com, serve files to browser
api-server 3001 - api.domain.com
socket-server 3003 - io.domain.com
In dev mode, socket request have all http request cookies,
But in production mode with nginx (down to conf),
socket cookie just have a cookie io
In dev
In prod
This is nginx conf(part of socket server).
server {
server_name io.domain.com;
location / {
include proxy_params;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-NginX-Proxy true;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Forwared-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_http_version 1.1;
proxy_pass http://127.0.0.1:3003;
}
location /socket.io/ {
include proxy_params;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-NginX-Proxy true;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Forwared-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_http_version 1.1;
proxy_pass http://127.0.0.1:3003;
}
}
Here is socket client
const io = require('socket.io-client');
let socket;
if (process.env.NODE_ENV === 'production') {
socket = io.connect('http://io.domain.com/noti');
} else {
socket = io.connect('http://localhost:3003/noti');
}
module.exports = socket;
In development env, it works well but in production mode because of the problem, I can't retrieve user values.
I need to use cookie value sessionId, token to auth, but two cookie values are disappeared.
What's wrong with it?
Most of all, Set cookie with domain.
For example in node js,
res.setCookie({...
domain: 'domain.com'
});
And in nginx conf,
proxy_cookie_domain io.domain.com domain.com

How do I setup NGINX with a reverse proxy to port 80 for two apps that both need socket.io?

I've been going around this for a couple few days now. I get so close and then a connection seems to die or socket.io cannot be found. But then maybe I'm doing it wrong?
My NGINX files looks something like this:
upstream appOne {
server demo.someserver.com:1111;
}
upstream appTwo {
server demo.someserver.com:2222;
}
location /appOne/ {
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;
proxy_pass http://appOne/;
}
location /appTwo/ {
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;
proxy_pass http://appTwo/;
}
location /socket.io/ {
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;
proxy_pass http://appOne/socket.io/;
}
So what I'm trying to do here is have appOne running in a subfolder at demo.someserver.com/appOne and have appTwo running in a subfolder at demo.someserver.com/appTwo but both have a reverse proxy.
All connects great except both apps need socket.io to run and shouldn't really need to connect to each other (Although I'm starting to think this wouldn't be a bad idea). But at the moment they both connection to appOne/socket.io/socket.io.js because of the last NGINX location. This causes all sorts of problems when connecting like the socket connection not being on the same port etc.
What I'm trying to avoid is naming the ports and the app name inside any frontend JS files as appOne and appTwo in this context could be clientOne and clientTwo.
I did think of something like this:
if ($request_uri == 'appOne') {
proxy_pass http://appOne/socket.io/;
}
if ($request_uri == 'appTwo') {
proxy_pass http://appTwo/socket.io/;
}
But I have no idea how that actually works. Any pointers or has anyone tried to do something the same?
So my question is - how can I have separate connections to socket.io through the reverse proxy. Or should I have one socket.io connection and both attach to that? (but I could have multiple clients on one server)
If you need two separate socket.io apps, you can perform this by setting (undocumented) path option when initializing socket.io on the client.
To be consistent, I will provide you full working example of Nginx config and Node files:
nginx config:
upstream appOne {
server demo.someserver.com:1111;
}
upstream appTwo {
server demo.someserver.com:2222;
}
server {
listen 80;
server_name demo.someserver.com;
root /path/to/working/dir; #probably not necessary
location /appOne/ {
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;
proxy_pass http://appOne/;
}
location /appTwo/ {
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;
proxy_pass http://appTwo/;
}
# no need for /socket.io location
# each app will connect socket.io via /appOne/socket.io or /appTwo/socket.io
}
app1.js and app2.js (Express + Socket.io example):
var app = require('express')();
var server = require('http').Server(app);
var io = require('socket.io')(server);
var port = 1111; //or 2222 for app2.js
app.get('*', function(req, res) {
res.sendFile(__dirname + '/index1.html'); //or index2.html for app2.js
});
io.on('connection', function(socket) {
socket.emit('hello', {port: port});
});
server.listen(port);
index1.html and index2.html:
<!DOCTYPE html>
<html>
<head>
<script src="/appOne/socket.io/socket.io.js"></script>
<!--<script src="/appTwo/socket.io/socket.io.js"></script>-->
<script>
var socket = io('/', {path: '/appOne/socket.io'});
//var socket = io('/', {path: '/appTwo/socket.io'});
socket.on('hello', function(data) {
console.log(data.port);
});
</script>
</head>
<body>
<h1>app</h1>
</body>
</html>
So if you launch both app1.js and app2.js and navigate to
http://demo.someserver.com/appOne
and then
http://demo.someserver.com/appTwo
you will see in your console 1111 and 2222 respectively, which means that you have two independent socket.io apps.
You can set a custom path to socket.io in your script.
Sets the path v under which engine.io and the static files will be
served. Defaults to /socket.io.
If no arguments are supplied this method returns the current value.
Source: http://socket.io/docs/server-api/#server#path%28v:string%29:server

Routed traffic with cookies Nginx

first time i'm trying to setup nginx.
I have following problem i would like to solve.
I have two versions of backend v1 and v2.
User is routed to "/v2" (proxy_pass '127.0.0.1:3000;')
Traffic tru "/" (javascript + sockets) has be routed to the same server '127.0.0.1:3000;' by looking at the cookie.
Heres my problem the cookie doesn't exists and therefore 404 will be returned
Any suggestion?
map $cookie_version $site_version {
default "";
"v1" "version=v1;Domain=localhost;Path=/";
"v2" "version=v2;Domain=localhost;Path=/";
}
server {
listen 8081;
server_name localhost;
location / {
if ($cookie_version ~* "v1") {
proxy_pass http://127.0.0.1:8080;
}
if ($cookie_version ~* "v2") {
proxy_pass http://127.0.0.1:3000;
}
}
location /v1 {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_http_version 1.1;
set $cookie_version "v1";
add_header Set-Cookie $site_version;
rewrite ^/v1(.*) /$1 break;
proxy_pass http://127.0.0.1:8080;
}
location /v2 {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_http_version 1.1;
set $cookie_version "v2";
add_header Set-Cookie $site_version;
rewrite ^/v2(.*) /$1 break;
proxy_pass http://127.0.0.1:3000;
}
}
First of all, read why if is evil http://wiki.nginx.org/IfIsEvil. Use map instead.
My suggestion:
map $cookie_version $mybackend {
default "127.0.0.1:3000";
"v1" "127.0.0.1:8080";
"v2" "127.0.0.1:3000";
}
...
location / {
proxy_pass http://$mybackend;
}
...
location ~ ^/(?<cver>v[12])/ {
...
add_header Set-Cookie "version=$cver;Domain=localhost;Path=/";
rewrite ^/v[12]/(.*)$ /$1 redirect;
}

Resources