Unexpected response code: 502 nginx - node.js

i have the following setup:
nginx server running as a proxy:
server {
server_name domain.tld;
location / {
# For Read Requests
proxy_pass http://XXX.XXX.XXX.XXX;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location ~* "(/config.json|/nowjs/now.js|socket.io|/stat/1.gif)" {
proxy_pass http://127.0.0.1:9080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
where XXX.XXX.XXX.XXX is the IP domain for my static content pages and assets.
i have a simple chat application running on same server as the nginx on port 9080
in my index.html page, i have this code:
<div id="chat">
<div id="messages"></div>
<input type="text" id="text-input" />
<input type="button" value="Send" id="send-button" />
</div>
<script type="text/javascript" src="http://domain.tld/nowjs/now.js"></script>
<script type="text/javascript">
$(document).ready(function(){
now.receiveMessage = function(name, message){
$("#messages").append('<br />' + '' + name + '' + ': ' + message);
}
$("#send-button").click(function(){
now.distributeMessage($("#text-input").val());
$("#text-input").val("");
});
now.name = "${name}";
});
</script>
and here is the app.js file:
var server = require('http').createServer(function(req, res){
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Chat Server\n');
});
server.listen(9080);
var nowjs = require("now");
var everyone = nowjs.initialize(server);
everyone.now.distributeMessage = function(message){
console.log('User '+this.now.name+' added message ' +message);
everyone.now.receiveMessage(this.now.name, message);
};
everything seems to be running ok, although i keep getting the Unexpected response code: 502 when the page loads up!
is there a way to enable the web proxy for nginx, as looking further using Firefox Firebug, i get this error:
Firefox can't establish a connection to the server at ws://domain.tld/socket.io/1/websocket/-WFvaQTvzASDBMHNpUGA.
any advise much appreciated.

i changed:
var everyone = nowjs.initialize(server);
to
var everyone = nowjs.initialize(server, {socketio: {transports: ["xhr-polling"]}});
seems to have done the job.

Related

What's the correct way to get rid of /public from a domain using node.js and nginx?

I've been structuring my website as follows:
someSite
app.js
public
index.html
css
assets
Project1
Project2
...
I'd like for the path to /public/Project1/index.html to be accessible by going to someSite.com/Project1, and similarly for subfolders. I've found this can be accomplished like this:
var express = require('express');
var app = express();
var http = require('http').createServer(app);
var io = require('socket.io')(http);
app.use('/public',express.static(path.join(__dirname, 'public')));
app.get('/', (req, res) => {
res.sendFile(__dirname + '/public/index.html');
});
app.get('/Project1', (req, res) => {
res.sendFile(__dirname + '/public/Project1/index.html');
});
But I don't know if this is standard, or inefficient. It's also breaking all of my relative calls, such as <img src="../assets/someImage.svg">, which no longer point to the correct place. It can be fixed by using absolute urls everywhere, but that feels wrong.
I'm using nginx as a reverse proxy server, which I think is the right place to make this change. My configuration is as follows:
server {
listen 80;
server_name someSite.com www.someSite.com;
rewrite ^(.*) https://$host$1 permanent;
}
server {
listen 443 ssl;
root /var/www/someSite/public;
server_name someSite.com;
ssl_certificate /path/to/credentials.crt;
ssl_certificate_key /path/to/credentials.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
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://localhost:3000/;
}
}
I still haven't figured out exactly what's wrong with my nginx configuration, but the hosting from node issue was just a matter of changing
app.use('/public',express.static(path.join(__dirname, 'public')));
to
app.use('/',express.static(path.join(__dirname, 'public')));
and removing subsequent app.get calls.

How to appropriately reverse-proxy nodejs subroutes?

I am new to nodejs and nginx as well. So what I am trying to do is reverse-proxy node in nginx. I am able to do so but my subsequent routes from nodejs doesn't get reverse-proxied.
app.get('/', (req, res) => {
res.render('index');
});
app.post('/upload', (req, res) => {
upload(req, res, (err) => {
console.log(req.file);
res.render('index' , {
msg: 'File Uploaded!',
file : `uploads/${req.file.filename}`
});
});
});
So here is the basic code. '/' has the index page with a button. And when you click on the button it goes to the '/upload'.
It works without reverse proxy.
My reverse proxy is configured as below.
location /nodeAdmin/ {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_redirect off;
proxy_buffering off;
proxy_pass http://127.0.0.1:8080/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_cache_bypass $http_upgrade;
}
So now when I go to mydomain.com/nodeAdmin I see the 'index'. But when I click on the upload button, I need to go to /upload of nodejs app but it goes to mydomain.com/upload which does not exist.
It would be great if someone could direct me in the right direction.
I think the issue lies in the html.
Your current html may have something like
upload
Making all the links "relative" should solve your problem
upload
Links starting with / will be relative to the domain, while links starting with ./ will be relative to the current directory (nodeAdmin).

Can we use NGINX as webapp for template engine

I have a requirement for basic html template webapp such as:
http://localhost:3000/myapp?param1=hello&param2=John is called it should return text/html response which looks like this:
<html>
<body>
<p>Nice to see you John. Platform greets you "hello".</p>
</body>
</html>
the name and greeting is templated from param. so template is something like this:
<html>
<body>
<p>Nice to see you {{param1}}. Platform greets you "{{param2}}".</p>
</body>
</html>
I have currently done this in node server using express.js and then the server is exposed publicly via nginx.conf:
server {
listen 80;
# server_name example.com;
location / {
proxy_pass http://private_ip_address: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;
}
}
I was wondering if this could be possible with some plugins or other configuration with bare nginx without hosting the node server on 3000 port.
I was able to solve this using only Nginx to program it using OpenResty's lua module.
The https://github.com/openresty/lua-nginx-module gives ability to program in nginx.conf, where one could use the existing lua libraries such as https://github.com/bungle/lua-resty-template for templating!
myapp.lua:
local template = require("resty.template")
local template_string = ngx.location.capture("/templates/greet.html")
template.render(template_string.body, {
param1 = ngx.req.get_uri_args()["param1"],
param2 = ngx.req.get_uri_args()["param2"]
})
greet.html:
<html>
<body>
<p>Nice to see you {{param1}}. Platform greets you "{{param2}}".</p>
</body>
</html>
nginx.conf:
worker_processes 1;
error_log logs/error.log;
events {
worker_connections 1024;
}
http {
root ./;
server {
listen 8090;
location /myapp {
default_type text/html;
content_by_lua_file ./lua/myapp.lua;
}
}
content_by_lua_file is where the power of openresty comes.
I described the complete process here: https://yogin16.github.io/2018/03/04/nginx-template-engine/
Hopefully, someone would find this helpful.
You can't render file with nginx.
Just send the file with nginx and the rewrite directive then inside the file just include some javascript to replace text content with query parameters
Nginx conf :
location / {
rewrite ^ /static/index.html break;
}
index.html:
<div>My content <span id="name"></span></div>
<script>
function getParameterByName(name, url) {
if (!url) url = window.location.href;
name = name.replace(/[\[\]]/g, "\\$&");
var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g, " "));
}
document.getElementById("name").textContent = getParameterByName("foo"):
</script>

Multiple node.js projects with one domain name, each using path '/' as base url. Nginx & Express.js

I am successfully able to reverse proxy multiple node.js projects to different ports as in the Nginx set up below. What I am trying to accomplish however, is viewing the url as the root when it gets to the Node.js server.
For example, When someone goes to mydomain.com/projects/music_player, is it possible to have the Express application view the request url as just '/' instead of '/projects/music_player'.
My current Nginx setup, and Express configuration example are as follows.
Nginx:
server {
listen 80;
server_name mydomain_name.com;
location / {
proxy_pass http://localhost:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
location /projects/music_player/ {
proxy_pass http://localhost:8000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
I want to do this:
app.get("/", function (req, res) {
res.sendFile("index.html");
});
app.listen(8000);
Instead of this:
app.get("/projects/music_player", function (req, res) {
res.sendFile("index.html");
});
app.listen(8000);
I am not sure if that is even possible. The reason is that I would like each of my node node.js/express applications to be deployable as standalone applications, without restructuring the code. I am trying to avoid having a bunch of domain names for each project, plus I think it would be pretty cool.
Yes! Of course you can.
I think the best way to do this is to rewrite your entire program into one express app, but you say you want to avoid this.
Then I think the short way with your current setup is to make each program listen to a different port and then map routes to them in your nginx.
For example:
dog.js
app.get("/", function (req, res) {
res.sendFile("dog.html");
});
app.listen(8001);
cat.js
app.get("/", function (req, res) {
res.sendFile("cat.html");
});
app.listen(8002);
And finally in your nginx config file:
server {
listen 80;
server_name mydomain_name.com;
location / {
proxy_pass http://localhost:8001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
location /cat/ {
rewrite /cat/ / break;
proxy_pass http://localhost:8002;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
Notice the rewrite directive, this prevents for the /cat/ location from being sent to your cat.js app that only expects the / route.
I ran into this same problem, where I didn't want to fully restructure my backend services while wanting to change the endpoint to match others.
I ended up using node-http-proxy with http-proxy-rules. Grabbing an example from the http-proxy-rules github README, you're solution would resemble the following.
var http = require('http'),
httpProxy = require('http-proxy'),
HttpProxyRules = require('http-proxy-rules');
// Set up proxy rules instance
var proxyRules = new HttpProxyRules({
rules: {
'.*/test': 'http://localhost:8080/cool', // Rule (1)
'.*/test2/': 'http://localhost:8080/cool2/' // Rule (2)
},
default: 'http://localhost:8080' // default target
});
// Create reverse proxy instance
var proxy = httpProxy.createProxy();
// Create http server that leverages reverse proxy instance
// and proxy rules to proxy requests to different targets
http.createServer(function(req, res) {
// a match method is exposed on the proxy rules instance
// to test a request to see if it matches against one of the specified rules
var target = proxyRules.match(req);
if (target) {
return proxy.web(req, res, {
target: target
});
}
res.writeHead(500, { 'Content-Type': 'text/plain' });
res.end('The request url and path did not match any of the listed rules!');
}).listen(6010, cb);
Happy hacking!

node.js: route request to different port on same host

I have a host computer which serves a number of webapplications (not node.js based). It does this using different ports. This means that for example the following applications are live:
app1: http://hostname:3000
app2: http://hostname:3001
app3: http://hostname:3003
Next to that I have a node.js based webapp (running on port 80) which I want to use as a sort of router. When someone navigates to http://localhost/app/app1. I want it to navigate to http://hostname:3000. This is relatively straightforward using a simple redirect. However, I would want to preserve the url http://localhost/app/app1. Can someone point me to a way to make this work using node.js/express?
My routing logic looks somewhat like this (pseudo-code).
app.route('/app/:appName')
.get(appEngine.gotoApp);
appEngine.gotoApp = function(req, res) {
redirectToApp logic
}
You probably better use Nginx setting up a reverse proxy with different locations per application.
It's not what you ask for because it does not use node.js, but if it's the only purpose, Nginx really suits your needs.
For example a Nginx configuration file like should work the way you want :
server {
listen 80;
server_name myapp.com;
location /app1 {
proxy_pass http://APP_PRIVATE_IP_ADDRESS: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;
}
location /app2 {
proxy_pass http://APP_PRIVATE_IP_ADDRESS:3001;
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;
}
location /app3 {
proxy_pass http://APP_PRIVATE_IP_ADDRESS:3003;
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 express, you can try to create the app with the cli express application generator.
It creates an express app and returns it with module exports.
In the server.js file it pass to listen function of the server instance the express app object.
You can create more server object and listen different app with different port.
var server = http.createServer(app);
server.listen(port);
var server2 = http.createServer(app2);
server2.listen(port2);
If you want to point different app based on the url, you can instance an express router instead of express object.
var app1 = express.Router();
Then you can set all your routes into this object with classic get or post or other methods.
Now you are able to pass the router as a middleware of your main express app.
app.use( "app1/", app1 );
You can also pass an express app to middleware, instead of router object, in order to gain the possibility of exec the app with a different url and port server listening.
There is a nice http-proxy lib designed exactly for that!
const httpProxy = require('http-proxy');
const url = require('url');
const proxy = httpProxy.createProxy();
const options = {
'/app/app1': 'http://localhost:3000',
'/app/app2': 'http://localhost:3001',
'/app/app3': 'http://localhost:3003',
}
require('http').createServer((req, res) => {
const pathname = url.parse(req.url).pathname;
for (const [pattern, target] of Object.entries(options)) {
if (pathname === pattern ||
pathname.startsWith(pattern + '/')
) {
proxy.web(req, res, {target});
}
}
}).listen(80);

Resources