Nginx Reverse Proxy not working with Nodejs at localhost - node.js

I have a dedicated server with 5 usable IP address,say X.X.X.1 - X.X.X.5 below is my default schema for IP addresses
X.X.X.1 - ns1.ex.com - name server using BIND
X.X.X.2 - ns2.ex.com
X.X.X.3 - www.ex.com - using nginx as the web server
X.X.X.4 - nothing
X.X.X.5 - nothing
Now I am trying to do reverse proxying on nodejs(127.0.0.1:4501).... I have started the app and when I am trying to access the node app through reverse proxy it's not working. I have even tried to call curl like http://localhost:4501/ and also http://localhost:4501/test/ as the app.js is present at /var/www/test/app.js. I also tried changing the app ip addresses to X.X.X.3 but with no result
When I don't set the IP address of the node app then it is working on any port that I put in. I want to set the IP address to localhost so that it is only accessible through Nginx and I have my database that I also want to hide behind Nginx.
Below are my conf files:
nginx.conf: present at /usr/local/nginx/conf/nginx.conf
#===============================================================================
# Main Configuration Settings
#===============================================================================
user root admins;
worker_processes auto;
master_process on;
worker_rlimit_nofile 16384;
worker_priority 0;
#================================================================================
# Error Log Setting Goes HEre
#================================================================================
events {
multi_accept off;
worker_connections 5120;
}
http {
include mime.types;
default_type application/octet-stream;
open_file_cache max=10000 inactive=30s;
open_file_cache_errors on;
client_body_buffer_size 200M; #200 MB
log_not_found on; #LOG All 404 error code
log_format main '{'
' IP:"$remote_addr:$remote_port", Time:"$time_local", Request_Type:"$request", '
' Status:"$status", Referer:"$http_referer", '
' Agent:"$http_user_agent", Forwarded_By:"$http_x_forwarded_for" '
'}';
#===========================================
# Caching DNS records For 1 HR
#==========================================
resolver 8.8.8.8 8.8.4.4 valid=1h;
resolver_timeout 10s;
#sendfile on;
keepalive_timeout 10;
#=================================================================================
# Gzip Module
#=================================================================================
gzip on;
gzip_comp_level 4;
gzip_min_length 20;
gzip_vary on;
gzip_proxied any;
upstream localhost_servers {
server 127.0.0.1:4501;
keepalive 64;
}
server {
listen 80;
server_name www.ex.com ex.com;
charset UTF-8;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarder-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://localhost_servers;
proxy_redirect off;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
app.js: at /var/www/test/app.js
var express = require('express');
var morgan = require('morgan');
var bodyParser = require('body-parser');
var methodOverride = require('method-override');
var app = express();
app.use(express.static(__dirname + '/public'));
app.use(morgan('dev'));
app.use(bodyParser.urlencoded({extended:true}));
app.use(bodyParser.json());
app.use(methodOverride());
app.get('/',function(req,res){
console.log(req.ip,req.host,req.path,req.originalUrl);
res.send(req.body);
});
app.listen('127.0.0.1',4501);
console.log('Magic happens on port 80');

It was a Very silly mistake from my side as pointed by #Ben Fortune express listen method takes port first and then ip address

Related

Express server not working on reverse proxy (NGINX)

I am testing my express server running on proxy. My nginx config file for in sites-available is:
server {
server_name open.yousico.com;
gzip on;
gzip_proxied any;
gzip_types application/javascript application/x-javascript text/css text/javascript;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_min_length 256;
location /_next/static/ {
alias /var/www/yousi-website/.next/static/;
expires 365d;
access_log off;
}
location / {
proxy_pass http://127.0.0.1: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 /api {
rewrite ^/codify(.*) $1 break;
proxy_pass "http://127.0.0.1:3001";
}
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/open.yousico.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/open.yousico.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
server {
if ($host = open.yousico.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
server_name open.yousico.com;
return 404; # managed by Certbot
}
My server file for my express server listening on 3001 is:
const express = require('express');
const app = express();
app.listen(3001, console.log("server is running on 3001"));
app.get('/', (req, res) => {
res.send('API is running');
});
app.get('/hello', (req, res) => {
res.send('Hello World');
});
I tested this express server on my local machine, and it seems to be working fine, but when I deploy it to my cloud server, it displays "Cannot GET /api", is there something wrong with my config file? My understanding is that I set my location to /api and direct it to port 3001, and I'm sure that the server is running on 3001.
"Cannot XXX /YYY" is the Express default response when there is no handler for method XXX for path YYY.
In your case, I don't see an app.get("/api", ...) handler in your server code, so the error is quite warranted.
The rewrite statement in your nginx config,
rewrite ^/codify(.*) $1 break;
doesn't make sense either since there's no way for location /api to match /codify.
If you meant to strip the /api out before the URL is passed to your Express server,
rewrite ^/api(.*) $1 break;
in which case /api would be passed as /, and that would match your app.get("/")...

Nodejs not running in server

I am trying to launch nodejs in my server. this is my node.js code:
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');
}).listen(8080, 'xx.xx.xx.xx');
console.log('Server running at http://xx.xx.xx.xx:8080/');
this is my /etc/nginx/nginx.conf
# For more information on configuration, see:
# * Official English Documentation: http://nginx.org/en/docs/
# * Official Russian Documentation: http://nginx.org/ru/docs/
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /var/run/nginx.pid;
# Load dynamic modules. See /usr/share/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 1024;
}
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
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;
# Load modular configuration files from the /etc/nginx/conf.d directory.
# See http://nginx.org/en/docs/ngx_core_module.html#include
# for more information.
include /etc/nginx/conf.d/*.conf;
server{
location / {
proxy_pass http://xx.xx.xx.xx: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;
}
}
}
#
I also deleted a few lines from default.conf because it was showing up error nginx: [emerg] bind() to [::]:80 failed (98: Address already in use) and following #rednaw's answer
I am trying to run node.js in my xx.xx.xx.xx server. Now it's just showing this at http://xx.xx.xx.xx/ and This site can’t be reached xx.xx.xx.xx refused to connect. ERR_CONNECTION_REFUSED at http://xx.xx.xx.xx:8080/
You have to mention the port number i.e not in use to listen.
Do it some thing like this----
var http = require("http");
function onRequest(request, response) {
console.log("Request received.");
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Hello World");
response.end();
}
http.createServer(onRequest).listen(8083);
In my scenario the port number 8080 was already in use....So i used
another port number like 8083....It works...

Enable Cors on node.js app with nginx proxy

I have set up a digital ocean droplet that is a reverse proxy server using nginx and node. I used this tutorial from digital ocean as a starting point
https://www.digitalocean.com/community/tutorials/how-to-set-up-a-node-js-application-for-production-on-ubuntu-14-04.
I have also set up ssl with lets encrypt. The issue I am currently having is that I am unable to make cross domain ajax calls to the server. I am getting a error of No 'Access-Control-Allow-Origin' header is present. I have set up the appropriate header response in my node app and have attempted to follow the few examples I could find for nginx with no luck. Below is my code.
nginx with my attempts at headers removed
server {
listen 443 ssl;
server_name lefthookservices.com www.lefthookservices.com;
ssl_certificate /etc/letsencrypt/live/lefthookservices.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/lefthookservices.com/privkey.pem;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_dhparam /etc/ssl/certs/dhparam.pem;
ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-$
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_stapling on;
ssl_stapling_verify on;
add_header Strict-Transport-Security max-age=15768000;
location / {
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_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
location ~ /.well-known {
allow all;
}
}
server {
listen 80;
server_name lefthookservices.com www.lefthookservices.com;
return 301 https://$host$request_uri;
}
Here is my app.js script using express
'use strict';
var colors = require('colors/safe');
var express = require('express');
var knack = require('./knack_call.js');
var bodyParser = require('body-parser');
var cors = require('cors');
colors.setTheme({
custom: ['blue', 'bgWhite']
});
var app = express();
app.use(bodyParser.json());
// allow for cross domain ajax
app.get('/', function(request, response){
response.send('hello\n');
});
app.post('/', function(request, response){
response.header("Access-Control-Allow-Origin", "*");
response.header("Access-Control-Allow-Headers", "X-Requested-With");
response.header("Access-Control-Allow-Methods', 'GET,POST");
knack.getData(request, response);
});
app.listen(8080, '127.0.0.1', function(m){
console.log(colors.custom("Captin the server is at full strength"));
});
Any suggestion that could help me set the correct headers to allow CORS would be greatly appreciated. Thank you in advance.
As a result of Tristans answer below my Nginx code now looks like this.
server {
listen 443 ssl;
server_name lefthookservices.com www.lefthookservices.com;
ssl_certificate /etc/letsencrypt/live/lefthookservices.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/lefthookservices.com/privkey.pem;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_dhparam /etc/ssl/certs/dhparam.pem;
ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES$
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_stapling on;
ssl_stapling_verify on;
add_header Strict-Transport-Security max-age=15768000;
location / {
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
if ($http_origin ~*(https?://.*\exponential.singularityu\.org(:[0-9]+)?$)){
set $cors "1";
}
if ($request_method = 'OPTIONS') {
set $cors "${cors}o";
}
if ($cors = "1") {
more_set_headers 'Access-Control-Allow-Origin: $http_origin';
more_set_headers 'Access-Control-Allow-Credentials: true';
proxy_pass http://127.0.0.1:8080;
}
if ($cors = "1o") {
more_set_headers 'Access-Control-Allow-Origin: $http_origin';
more_set_headers 'Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT, DELETE';
more_set_headers 'Access-Control-Allow-Credentials: true';
more_set_headers 'Access-Control-Allow-Headers: Origin,Content-Type,Accept';
add_header Content-Length 0;
add_header Content-Type text/plain;
return 204;
}
proxy_pass http://127.0.0.1:8080;
}
}
location ~ /.well-known {
allow all;
}
}
Sadly this is still not working.
server {
listen 80;
server_name lefthookservices.com www.lefthookservices.com;
return 301 https://$host$request_uri;
}
It turns out the error message I was getting was inaccurate. The issue was not header setting. It turned out that I needed to make the request with jsonp and I needed to handle the incoming data differently. An error in the function called by app.js was erroring and causing the connection to time out. This resulted in the appropriate headers not being returned to the browser which caused the error message.
For anyone hoping to find an NGINX config that worked this is mine.
proxy_pass http://127.0.0.1:8080;
# proxy_http_version 1.1;
proxy_set_header Access-Control-Allow-Origin *;
# proxy_set_header Upgrade $http_upgrade;
# proxy_set_header Connection '';
proxy_set_header Host $host;
# proxy_cache_bypass $http_upgrade;
Thanks you for the suggestions.
Pull Nginx out of this equation. It doesn't have anything to do with your CORs problem if your setup is as similar to mine as I believe it is. I see that you're using the cors module, but you're not actually using it that I can see.
Your settings are simply enough that you might be able to get away with the defaults so, right below app.use(bodyParser.json());, update your app.js with:
app.use(cors());
That might work right out of the box. If it doesn't, you can pass a set of options. Mine looks something like this:
app.use(cors({
origin: myorigin.tld,
allowedHeaders: [ 'Accept-Version', 'Authorization', 'Credentials', 'Content-Type' ]
}));
Other config options are available in the docs.
You're almost there.
You have to think of the proxy as an external server as well as your Node.js application.
So, in short, you need to add a header to your nginx configuration.
Take a look at this link,
https://gist.github.com/pauloricardomg/7084524
In case this ever gets deleted:
#
# Acts as a nginx HTTPS proxy server
# enabling CORS only to domains matched by regex
# /https?://.*\.mckinsey\.com(:[0-9]+)?)/
#
# Based on:
# * http://blog.themillhousegroup.com/2013/05/nginx-as-cors-enabled-https-proxy.html
# * http://enable-cors.org/server_nginx.html
#
server {
listen 443 default_server ssl;
server_name localhost;
# Fake certs - fine for development purposes :-)
ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;
ssl_session_timeout 5m;
location / {
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# Nginx doesn't support nested If statements, so we
# concatenate compound conditions on the $cors variable
# and process later
# If request comes from allowed subdomain
# (*.mckinsey.com) then we enable CORS
if ($http_origin ~* (https?://.*\.mckinsey\.com(:[0-9]+)?$)) {
set $cors "1";
}
# OPTIONS indicates a CORS pre-flight request
if ($request_method = 'OPTIONS') {
set $cors "${cors}o";
}
# Append CORS headers to any request from
# allowed CORS domain, except OPTIONS
if ($cors = "1") {
more_set_headers 'Access-Control-Allow-Origin: $http_origin';
more_set_headers 'Access-Control-Allow-Credentials: true';
proxy_pass http://serverIP:serverPort;
}
# OPTIONS (pre-flight) request from allowed
# CORS domain. return response directly
if ($cors = "1o") {
more_set_headers 'Access-Control-Allow-Origin: $http_origin';
more_set_headers 'Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT, DELETE';
more_set_headers 'Access-Control-Allow-Credentials: true';
more_set_headers 'Access-Control-Allow-Headers: Origin,Content-Type,Accept';
add_header Content-Length 0;
add_header Content-Type text/plain;
return 204;
}
# Requests from non-allowed CORS domains
proxy_pass http://serverIP:serverPort;
}
}

Proxing Websocket Traffic from Nginx to Socket.io (without SSL)

As of yesterday nginx started to support websocket connections, therefore i was trying to get my nginx-nodejs-socket.io application to work without harproxy ect (not much luck though).
What i want exactly to achieve is nginx to send only websocket connection requests to a backed server,or websocket server ,socket.io to be more exact, while in the same time nginx will be serving php files, and all static content including html files.I dont want express to serve static content at all (if this is possible).
Here is my nginx.conf
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
gzip on;
upstream backend {
server 127.0.0.1:8080;
}
server {
listen 80;
server_name localhost;
charset UTF-8;
#access_log logs/host.access.log main;
location / {
root /website/html_public;
index index.php index.html index.htm;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /website/html_public;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
location ~ \.php$ {
root /website/html_public;
try_files $uri =404;
fastcgi_pass unix:/tmp/php5-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
location ~ /\.ht {
deny all;
}
location /connection {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
# another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;
# location / {
# root /website/html_public;
# index index.php index.html index.htm;
# }
#}
}
Here is my server.js file in node
var express = require('express');
var app = express();
var port = 8080;
/* HTTP Server*/
server = require('http').createServer(app);
server.listen(port);
app.use(express.logger(':remote-addr - :method :url HTTP/:http-version :status :res[content-length] - :response-time ms'));
app.use(express.static(__dirname + '/html_public'));
app.use(express.favicon());
app.set('view engine', 'jade');
app.set('view options', { layout: false });
app.set('views', __dirname + '/views');
app.get('/', function(req, res){
res.render('index.html');
});
/*
* Web Sockets
*/
io = require('socket.io').listen(server),
io.configure('production', function(){
io.enable('browser client etag');
io.set('log level', 1);
io.set('transports', [ 'websocket', 'htmlfile', 'xhr-polling', 'jsonp-polling' ]);
});
console.log('Chat Server started with Node '+ process.version +', platform '+ process.platform + 'to port %d',port);
From my client, i try to connect like this :
socket = new io.connect('http://localhost/connection');
Now, the problem is that when i try to connect normally, typing localhost, i see on chrome console:
**GET http://localhost/socket.io/socket.io.js 404 (Not Found)** , and also when type in the browser http://localhost/connection i receive "Cannot GET /connection" which is telling me that nginx doesn't proxy websockets normally with my current configuration.
Thanks in advance for your answers.
Let me guess, you want:
location /connection {
proxy_pass http://backend/;
...
}
but you have:
location /connection {
proxy_pass http://backend;
...
}
http://nginx.org/r/proxy_pass
Just to make sure, do you have Nginx version 1.3.13 ? ( ex. Nginx's PPA don't have that version yet.)

Setup of nginx with node.js

I have setup nginx as a front end to an node.js app.
My nginx conf is:
worker_processes 1;
error_log /tmp/logs/error.log;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
access_log /tmp/logs/access.log;
sendfile on;
keepalive_timeout 65;
include /etc/nginx/sites-enabled/*;
# BELOW IS THE PART TO PROXY MY NODE.JS APP
upstream node_entry {
server unix:/tmp/express.sock
fail_timeout=0;
}
server {
listen 8888;
client_max_body_size 4G;
server_name localhost;
keepalive_timeout 5;
location / {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://node_entry;
}
}
}
My node.js app is:
express = require('express');
app = express.createServer();
app.get('/test', function(req, res){
res.send('TEST');
});
app.listen('/tmp/express.sock');
When I issue a:
curl -XGET 'http://localhost:8888/test'
I get an error instead of proxying to my node.js app.
Any idea ?
I'm doing something similar, but it's all on one host, and I'm using a predefined port number that nginx and node both know (though I'd rather use your way if you can get it working).
Does it work if you have node listen on a specific port, and proxy_pass to http://127.0.0.1:{that_port}? (assuming both are on the same server...)

Resources