I have nginx proxy server for forward request to nodejs server
for example
http://localhost/api/test//////test should be forwarded as test//////test
So,problem is, Nginx removes duplicate slashes
http://localhost/api/test//////test becomes test/test
how I can solve this?
nginx config
upstream backend_server {
server backend:4000;
}
server {
listen 80;
server_name no_name;
location /api/ {
proxy_pass http://backend_server/;
}
}
Nodejs server
router.all('*', function(req, res, next) {
console.log('SERVER WAS REQUESTED url: ' + req.originalUrl);
request(req.originalUrl.substr(1)).pipe(res)
})
So, I find a solution
merge_slashes off
helps me
Related
I am running a MEAN stack application. It works fine on my localhost. However, when MEAN stack is deployed on AWS ubuntu server HTTP requests are not getting forwarded to the back-end.
The app.js file looks like:
var app = express();
app.all('*', (req, res, next) => {
if (req.secure) {
return next();
}
else {
res.redirect(307, 'https://' + req.hostname + ':' + app.get('secPort') + req.url);
}
});
On my localhost every HTTP request is entering into if(req.secure) loop and respective routers defined in app.js are getting invoked.
However, when i deploy my MEAN stack application on EC2, the control does not enter into the if condition at all.
I have used NGINX reverse proxy to forward the back-end requests are below:
server {
charset utf-8;
listen 80 default_server;
server_name _;
location / {
root /opt/front-end;
try_files $uri /index.html;
}
location /* {
proxy_pass http://localhost:/3000;
}
}
I'm new to Nginx, and I have some trouble with hosting 2 websites on my RaspberryPi (Raspbian).
I have 2 domains, site1.com (:8080) and site2.com(:8000), both are Node.JS apps (with Express). I have working SSL certifications with Let's Encrypt for both.
This is my site1 nginx config (/etc/nginx/site-available/site1):
server {
server_name site2.com;
listen 80;
listen [::]:80;
location / {
include /etc/nginx/proxy_params;
proxy_pass http://192.168.1.11:8080;
}
}
This is my site2 nginx config (/etc/nginx/site-available/site2):
server {
server_name site1.com;
listen 80;
listen [::]:80;
location / {
include /etc/nginx/proxy_params;
proxy_pass http://192.168.1.11:8000;
}
}
So indeed there is no part of 443 in these conf files but https://site2.com is working well but https://site1.com redirect me to the webpage of https://site2.com (keeping the site1 URL). I guess it's because my_server_ip:443 is already taken by site2 (no ??).
And the http://site2.com give me a 502 Bad Gateway and is not redirected to https (site1 is well redirected to his https).
This is the server part of my Node apps, they are the same for the 2 apps (except a port and SSL URI)
const express = require('express')
const app = express()
var https = require('https');
var http = require('http');
var fs = require('fs');
const privateKey = fs.readFileSync('/etc/letsencrypt/live/site1or2.com/privkey.pem', 'utf8');
const certificate = fs.readFileSync('/etc/letsencrypt/live/site1or2.com/cert.pem', 'utf8');
const ca = fs.readFileSync('/etc/letsencrypt/live/site1or2.com/chain.pem', 'utf8');
const credentials = {
key: privateKey,
cert: certificate,
ca: ca
};
const httpsServer = https.createServer(credentials, app);
const bodyParser = require("body-parser");
const urlencodedParser = app.use(bodyParser.urlencoded({
extended: true
}));
http.createServer(function (req, res) {
//redirect to https
res.writeHead(301, { "Location": "https://" + req.headers['host'] + req.url });
res.end();
}).listen(8080); //8000 for my site2.com
httpsServer.listen('443', () => {
console.log('Server https listening on Port 443');
})
I tried to change the Nginx confs to add 'listen 443; SSL on;...' but I have always errors like 'Failed to start A high-performance web server and a reverse proxy server' and I don't understand how to fix it.
So is the problem from my JS code or my Nginx confs? (or both maybe..?)
Thank for reading, it's my first StackOverflow post, I hope I didn't forget information and sorry if there is an English mistake.
Have a good evening (or day)!
I finaly understood how does multiples node websites hosting with SSL works, in the node.JS configuration (app.js) the app has to only listen to 1 port (8080 and 8000 for me) and must not refer to SSL and port 443 at all.
All the ssl configurations and https redirections have to be in the Nginx conf, for exemple, my file /etc/nginx/sites-available/site1:
server {
server_name site1.com;
listen 80;
listen [::]:80;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
ssl_certificate /etc/letsencrypt/live/site1.com/cert.pem;
ssl_certificate_key /etc/letsencrypt/live/site1.com/privkey.pem;
server_name site1.com;
location / {
proxy_pass http://192.168.1.11: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;
}
}
And the same for site2 with port 8000.
I am using node and express, AWS Ec2 Linux and running two web apps in port number 8080 and 8081 using pm2.
added subdomains to my Elastic IP admin.example.com and app.example.com.
My both app running in localhost:8080 and 8081.
/etc/nginx/conf.d/virtual.conf // After Edit
server {
listen admin.example.com:80;
server_name admin.example.com;
location / {
proxy_pass http://localhost:8080;
}
}
/etc/nginx/conf.d/virtual.conf // Before Edit
#
# A 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 html;
# index index.html index.htm;
# }
#}
server.js
const express = require('express');
const bodyParser = require('body-parser')
const path = require('path');
const app = express();
app.use(express.static(path.join(__dirname, 'build')));
app.get('/login', function (req, res) {
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});
app.get('/logout', function (req, res) {
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});
app.listen('8080');
console.log('Server started at port 8080');
nginx running fine after the restart but did not remove port number 8080 from my domain.
What are the things to be done with port 80?, I just enabled 80 from my AWS Instance inbound rule, Anything else I miss?
You are providing the domain with the port.
Try it this way:
server {
server_name admin.example.com;
listen 80;
location / {
proxy_pass http://127.0.0.1:8081;
}
}
change virtual.conf to :
server {
listen 80;
server_name admin.example.com;
location / {
proxy_pass http://127.0.0.1:8080;
}
}
And make sure you have done creating DNS record to point to your public ip address.
Issues Fixed :
Inbound rules added only ::/0 in the source for port 80, after remove and add HTTP, source updated like 0.0.0.0/0, ::/0 now all runs fine.
I am having a problem today that has something to do with routing. I have two main codes: one is the frontend and the other one is the backend.
The frontend is written using Vue.js so it's a SPA. This webapp is kind of complex and involves a lot of routing and backend AJAX API calls.
// All imports
import ...
loadMap(Highcharts);
loadDrilldown(Highcharts);
boost(Highcharts);
Vue.config.productionTip = false
Vue.use(VueCookie);
Vue.use(ElementUI, {locale});
Vue.use(VueRouter);
Vue.use(VueHighcharts, {Highcharts });
Vue.use(HighMaps);
// This is a global component declaration
Vue.component('app-oven', Devices);
Vue.component('app-sidebar', SideBar);
Vue.component('app-header', Header);
Vue.component('app-footer', Footer);
Vue.component('app-query', Query);
Vue.component('app-deviceproperties', DeviceProperties);
Vue.component('app-device', Device)
Vue.component('app-queryselection', QuerySelection)
Vue.component('app-index', Index)
Vue.component('app-index', Error)
Vue.component('app-realtime', RealTime);
Vue.component('app-login', Login)
Vue.component('app-preferences', Preferences)
const routes = [
{ path: '/index', component: Index},
{ path: '/', component: Login},
{ path: '/device/:deviceId', component: Device},
{ path: '/preferences', component: Preferences},
{ path: '*', component: Error}
];
const router = new VueRouter({
routes: routes,
mode: "history" // Gets rid of the # before the path
})
new Vue({
el: '#app',
router: router,
components: { App },
template: '<App/>'
})
The backend is written using Express on Node.js and it answers to specific AJAX calls from the Frontend.
// All imports
import ...
function prepareApp() {
let app = new Express();
app.use(cors({
origin: "*",
allowedHeaders: "Content-type",
methods: "GET,POST,PUT,DELETE,OPTIONS" }));
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
app.use(helmet());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
// Get all parameters
app.get('/params', params.parameters);
// Get all devices ever seen on the databases
app.get('/devices', params.devices);
app.get('/organizeData', organizer.updateAll);
// WebApp used services to access various things
app.post('/customQuery', stats.query);
app.post('/statistics', stats.statistics)
app.post('/getUserInfo', stats.getUserInfo)
app.post('/setUserInfo', stats.setUserInfo)
app.post('/genericQuery', stats.genericQuery)
app.post('/NOSQLQuery', stats.NOSQLQuery)
// Users check and insertion
app.get('/insertUser', stats.insertUser)
app.post('/verifyUser', stats.verifyUser)
app.get('/', errors.hello); // Returns a normal "hello" page
app.get('*', errors.error404); // Catch 404 and forward to error handler
app.use(errors.error); // Other errors handler
return app;
}
let app = prepareApp();
//App listener on localhost:8080
app.listen(8080, () => {
console.log("App listening on http://localhost:8080");
});
I only used this setup during development so I had both running at the same time on localhost with a different port for both. Now I would like to start the production cycle but I have no idea where to start.
Most importantly I am deploying both applications onto a Virtual Machine that is running on an external server. It already has a DNS association and a static IP address so that is already covered.
The problem arises when I try to run both programs at the same time on this production machine since its open ports are only the port 80 and the port 443. I think this is pretty normal in a production environment but I don't know how to adapt my applications so that they can still talk to each other and retrieve useful information from the Database while still using a single port.
I hope I explained the problem kinda well. Looking forward to a nice (and maybe long) answer.
I'd recommend running the backend on port 3000 internally and have nginx listening on 80 and 443 and proxying urls starting with '/api' to 3000 and deliver the frontend directly since it's just a bunch of static files.
This would be your nginx configuration. Just make sure backend server has some api prefix like '/api'. Build your vuejs app with 'npm run build' and copy the folder to /opt/frontend.
upstream backend {
server 127.0.0.1:3000;
}
server {
listen 80 default_server;
listen [::]:80 default_server;
location /api/ {
proxy_pass http://backend;
proxy_redirect off;
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 X-Forwarded-Host $server_name;
}
location / {
root /opt/frontend/dist;
try_files $uri $uri/ /index.html;
}
}
Alternatively, you could use the backend to host the frontend. However, a webserver like nginx is more efficient at serving static files than your backend api server.
If you don't have a way to open more ports, you can build your frontend into production mode and then take its index.html and dist folder to the same folder where your nodejs app are.
Then you create a express app listening to port 80 and send the HTML file.
var express = require('express');
var app = express();
var path = require('path');
var dir = '//vm//path//here';
app.get('/', function(req, res) {
res.sendFile(path.join(dir + '/index.html'));
});
app.listen(80);
In my case, my backend server doesn't run in cluster mode( e.g. with 3001, 3002... together with 80 port)
My case: rails server running with passenger ( mydomain.com , 80 port )
and I need to run my Vuejs project with the same domain ,the same port.
so the only solution is to run vue in specified URL.
this is my solution:
1.change your nginx config.
http {
# our backend app is passenger( rails server, running on 80 port)
passenger_root /usr/local/rvm/gems/ruby-2.2.10/gems/passenger-6.0.0;
passenger_ruby /usr/local/rvm/gems/ruby-2.2.10/wrappers/ruby;
include mime.types;
default_type application/octet-stream;
server {
listen 80;
passenger_enabled on;
# we are using this folder as the root of our backend app.
root /mnt/web/php/public;
charset utf-8;
location ~ ^/(images|javascripts|stylesheets|upload|assets|video)/ {
root /mnt/www/php/public;
expires 30d;
add_header Cache-Control public;
add_header ETag "";
}
# vuejs related content
location /vue.html {
root /mnt/web/vuejs/h5/dist;
}
location /static {
root /mnt/web/vuejs/h5/dist;
}
}
}
2.in your vue project's dist folder:
$ mv index.html vue.html
3.all the requested url in your vuejs project should be changed according to the nginx config.
I have some trouble with nginx proxy_pass redirection on localhost subdomain. I have a domain "domain.com", i want to redirect all request on *.domain.com on *.localhost:9000. Then node handle all request on *.localhost:9000 to the good express app.
On nginx conf when i try the following :
server {
server_name extranet.domain.com;
listen 80;
location / {
proxy_pass http://extranet.localhost:9000;
}
}
Request on extranet.domain.com are well redirected to the good express webapp.
With this :
server {
server_name ~^(.*?)\.domain\.com$;
listen 80;
location / {
proxy_pass http://localhost:9000/$1;
}
}
Express app running on localhost:9000 handle request /mysubdomainname, which implie that regex is good.
But when i try :
server {
server_name ~^(.*?)\.domain\.com$;
listen 80;
location / {
proxy_pass http://$1.localhost:9000;
}
}
All request on *.domain.com return http code 502.
Why http://localhost:9000/$1; works and not http://$1.localhost:9000; ?
(all subdomain are set in /etc/hosts).
Thanks in advance. I'm totally lost !
When a host name isn't known at run-time, nginx has to use its own resolver. Unlike the resolver provided by OS, it doesn't use your /etc/hosts file.
Maybe this will give you a hint, I wanted to pass the subdomain from Nginx to an Express app. Here is my code:
nginx.conf
http {
upstream express {
server localhost:3000;
}
domain.com inside nginx/sites-available
server {
listen 80;
server_name ~^(?<subdomain>.+)\.domain\.com$;
location / {
proxy_set_header Subdomain $subdomain;
proxy_set_header Host $host;
proxy_pass http://express;
}
}
Express app index.js
var express = require('express');
var app = express();
app.get('/', function (req, res) {
const subdomain = req.headers.subdomain;
});
app.listen(3000, function () {
console.log('Example app listening on port 4000!');
});