Im trying to redirect HTTP requests to my site to HTTPS. Its been extraordinarily hard. My code is:
var express = require('express');
var app = express();
app.use(function(req, res, next) {
console.log('req.protocol is ', req.protocol);
console.log('req.secure is ', req.secure);
if (req.url !== '/health' && !req.secure) {
console.log('redirecting .........');
return res.redirect('https://www.example.net/catch');
}
next();
});
app.get('/catch', function(req, res) {
res.send('Hello World!');
});
app.get('/', function(req, res) {
res.send('Hello World!');
});
app.get('/health', function(req, res) {
res.send('Hello World!');
});
app.listen(8080, function() {
console.log('Example app listening on port 8080!');
});
The load Balancer health check goes to '/health'. Every other request that isnt a health check, and is HTTP (rather than HTTPS) should be caught and redirected to https. However, I end up in an infinite loop as req.protocol always returns 'http' for http or https requests. req.secure therefore is false every time and I end up in a loop. Any ideas why this is?
It sounds like you installed the SSL certificate on your Elastic Load Balancer, so that's where SSL Termination is happening. So your load balancer is doing the SSL termination and always communicating with your server via HTTP. This means you have to check the 'x-forwarded-proto' header to determine if the original request is over HTTPS.
There are several other ways to configure SSL on AWS, including termination on the web server, but SSL termination on the ELB is the generally preferred method on AWS. You just have to be aware that in this configuration the request between the ELB and the web server isn't actually over SSL so you have to check the header accordingly.
Looks like req.protocol will always be 'http' on Amazon Web Services. Now im using:
req.get('x-forwarded-proto')
Related
I'm developing a node.js web server that runs express/express-session/passport for authentication and socket.io for websockets. The web server itself is reverse proxied with Nginx.
Everything seems to work fine and the server can correctly grab the clients information, but when I proxy the site behind Cloudflare, it gets stuck on the auth page.
app.get('/', function (req, res) {
//successfully authenticated
if (req.session && req.session.passport && req.session.passport.user) {
res.sendFile('index.html', { root: 'client/html' });
console.log('Index Served');
}
//request authentication
else {
res.sendFile('auth.html', { root: 'client/html' });
console.log('Auth Served');
};
});
However, I do get "Index Served" in the console, so the authentication seems to be working fine behind Cloudflare. I can even see the players information in the console. I just don't see index.html- I only get auth.html even though "Index Served" is getting sent to the console, so maybe its an express issue?
I have both app.set('trust proxy', true); and proxy set to true in the session parameters.
The following does not seem to run when I proxy the server, as I only see the following console logs when I do not have it proxied:
//dependency: websocket
var io = require('socket.io')(server);
io.use(function(socket, next){
console.log('1 ' + socket);
socket.client.request.originalUrl = socket.client.request.url;
cookieParse(socket.client.request, socket.client.request.res, next);
});
io.use(function(socket, next){
console.log('2 ' + socket);
socket.client.request.originalUrl = socket.client.request.url;
sessionAuthentication(socket.client.request, socket.client.request.res, next);
});
io.use(function(socket, next){
console.log('3 ' + socket);
passportInit(socket.client.request, socket.client.request.res, next);
});
io.use(function(socket, next){
console.log('4 ' + socket);
passportSession(socket.client.request, socket.client.request.res, next);
});
I have the web server running on port 2052, which according the Cloudflare is a proper port for websockets: https://developers.cloudflare.com/fundamentals/get-started/reference/network-ports/
I don't really have a good idea of what's going on, so I want to know what I can do to debug it? I have checked the access and error logs of Nginx and don't get anything useful. Is there a way for me to debug socket.io somehow or maybe express-session?
The entire server.js file can be seen here: https://github.com/Dan-Mizu/Project-Virtual-Pond/blob/update/server/Server.js
So I'm using webpack for a project on 8080 with a backend on 3000. The proxy seems to work fine, as I can send requests to the backend and access it without issue. However. I need to include this middleware that allows me to have a user load the page, and if they've logged in within a certain amount of time, the initial request they send to the server logs them in automatically.
router.use(function (req, res, next) {
//check token for routes beneath vvvv
})
router.post('/preauth', function (req, res) {
//return user account info if req.token is valid
})
When I try to get to prauth, or even any route before that from the page loaded on 8080 I only touch the middleware and nothing else.
When I do npm run build then try it again from the identical page on 3000, it works as expected.
No, CORS is not enabled and the proxy does not rewrite any url.
Does anyone know if something in my Webpack config might be causing this?
You need install Cors in nodejs:npm install cors, you can try the following below or you see: Nodejs + Vuejs
var express = require('express')
var cors = require('cors')
var app = express()
app.use(cors())
app.get('/products/:id', function (req, res, next) {
res.json({msg: 'This is CORS-enabled for all origins!'})
})
app.listen(80, function () {
console.log('This is a CORS-enabled web server listening on port 80')
})
I have a applications running on AWS Windows and Node.js. I can access using http and https. But i need it to forward http to https if anyone access through http.
I can think of many way, but would appreciate any advice on the best approach. The server is a EC2 instance, accessed through a load balancer.
If you're using express, this middleware module makes it easy to enforce https: https://www.npmjs.com/package/express-force-ssl
If you're using a reverse proxy in front of your app (ELB, nginx, etc), you'll need to set the trust proxy setting.
Here's a sample without the above module:
// Forward all requests to HTTPS.
// enable reverse proxy support in Express. This causes the
// the "X-Forwarded-Proto" header field to be trusted so its
// value can be used to determine the protocol. See
// http://expressjs.com/api#app-settings for more details.
app.enable('trust proxy');
// Add a handler to inspect the req.secure flag (see
// http://expressjs.com/api#req.secure). This allows us
// to know whether the request was via http or https.
app.use((req, res, next) => {
if (req.secure) {
// request was via https, so do no special handling
next();
} else {
// request was via http, so redirect to https
console.log('Redirecting to https');
res.redirect('https://' + req.headers.host + req.url);
}
});
Complete sample app.js
var express = require('express');
var app = express();
// Forward all requests to HTTPS.
// enable reverse proxy support in Express. This causes the
// the "X-Forwarded-Proto" header field to be trusted so its
// value can be used to determine the protocol. See
// http://expressjs.com/api#app-settings for more details.
app.enable('trust proxy');
// Add a handler to inspect the req.secure flag (see
// http://expressjs.com/api#req.secure). This allows us
// to know whether the request was via http or https.
app.use((req, res, next) => {
if (req.secure) {
// request was via https, so do no special handling
next();
} else {
// request was via http, so redirect to https
console.log('Redirecting to https');
res.redirect('https://' + req.headers.host + req.url);
}
});
// Respond to any GET requests with our message
app.get('*', (req, res) => {
res.send('This is only served over https');
});
// Listen on the assigned port
var port = process.env.PORT || 3001;
app.listen(port);
console.log('Hello started on port ' + port);
Redirect only GET requests, respond with error for non-GET requests
app.all('*', (req, res, next) => {
if (req.secure) {
next();
} else if (req.method === 'GET') {
res.redirect(`https://${req.headers.host}${req.url}`);
} else {
res.status(401).send('Secure channel required');
}
});
What I am trying to do:
Proxy a java api that runs on https://127.0.0.1:443/api/ along side my UI that runs on non-SSL http://127.0.0.1:1337/ in order to circumnavigate some CORS issues.
My attempt:
Proxy the api at the SSL port 443 to my non-SSL development port of 1338.
proxy my UI to 1337
Proxy 1137 to :8080/index.html and proxy 1338 to :8080/api/
Access my app from localhost:8080
My problem:
The UI comes in just fine... but I can not hit the API at :8080/api/httpSession/init
Yes, I can still hit the API at https://localhost/api/httpSession/init
api.js - Renders index.html at :1337
var app = express();
app.all('*', function (req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type');
next();
});
var options = {
changeOrigin: true,
target: {
https: true
}
};
httpProxy.createServer(443, '127.0.0.1', options).listen(1338);
start.js - Proxies 1337 and 1338 into 8080
// First I start my two servers
uiServer.start(); // renders index.html at 1337
apiServer.start(); //
// I attempt to patch them back into one single non-SSL port.
app
.use('/', proxy({target: 'http://localhost:1337/'}))
.all('/api/*', proxy({target: 'http://localhost:1338/'}))
.listen(8080, function () {
console.log('PROXY SERVER listening at http://localhost:%s', 8080);
});
What you're looking for is request piping. Try this example:
// Make sure request is in your package.json
// if not, npm install --save request
var request = require('request');
// Intercept all routes to /api/...
app.all('/api/*', function (req, res) {
// Get the original url, it's a fully qualified path
var apiPath = req.originalUrl;
// Form the proxied URL to your java API
var url = 'https://127.0.0.1' + apiPath;
// Fire off the request, and pipe the response
// to the res handler
request.get(url).pipe(res);
});
Make sure to add some error handling if the api can't be reached, such as this SO solution.
For the proxy issue, my guess is that it is keeping the /api/* in the url and that's not present on the router in your API service. You could try adding /api to the router in the API service since it's going to keep the url string the same when it sends it. Otherwise, you likely need to proxy and rewrite the url so that the API will match the request to a route.
On another note, what about just installing the cors module and using in the app? I do something similar and it's working well without all the proxy items. https://www.npmjs.com/package/cors
I have got 2 domain names. For instance, example0.org and example1.org.
How to setup nodejs using express to manage both of them?
For instance, I wanna share
/publicexample0
folder as root for
example0.org
and
/publicexample1
folder for
example1.org
as root
This works just for a one domain:
var app = express.createServer();
app.get('/', function(req, res) {
res.send('Hello World');
});
app.listen(3000);
I guess what you can do is to take advantage of the HTTP host header. It contains:
The domain name of the server (for virtual hosting), and the TCP port
number on which the server is listening. The port number may be
omitted if the port is the standard port for the service requested.
Mandatory since HTTP/1.1.
You can see its specification in the RFC 2616 - HTTP v1.1
And obviously you could read the header out of your request in Express and make a decision based on its value.
router.get('/hello', function(req, res){
var host = req.get('host');
if(host === 'example0.org'){
res.send(200,'Welcome from example0.org');
} else if(host === 'example1.org'){
res.send(200,'Welcome from example1.org');
} else {
res.send(200,'Welcome stranger');
}
});