HTTP redirect to HTTPS in a different port - node.js

I am trying to redirect every http request to an https server. This works fine if the port of the https server is the 443. However if I try to redirect to a different port it doesn't happen. Here is my code:
http.createServer(function(req,res){
var host = req.headers['host'],
url = req.url;
res.writeHead(301,
{"Location": "https://" + host + ":"+SERVER.SPORT + url})
res.end()
}).listen(SERVER.PORT)
https.createServer(SERVER.HTTPS_OPTIONS,app).listen(SERVER.SPORT)

Your host most likely already includes the port number.
You can make sure if you change this:
var host = req.headers['host']
to:
var host = req.headers['host'].split(':')[0];
Also add some logging:
console.log("https://" + host + ":"+SERVER.SPORT + url);
to see what the URL that you're building looks like.
You can also want to use the url module to work with URLs instead of manually concatenating strings to avoid mistakes like that. See:
https://nodejs.org/api/url.html
In any case add some logging to know what the URL that you're building looks like. Also test it with curl:
curl -v http://localhost:1234
to see what headers are returned.

Related

How do you write an SSL redirect in NodeJS running on AWS EC2 without using port 80 (http) or port 43 (https)?

I have two node servers on a single host. One HTTP server with the responsibility of redirecting to HTTPS, and one HTTPS server responsible for serving my application:
const express = require('express');
const https = require('https');
const http = require('http')
const fs = require('fs');
const app = express();
const httpsOptions = {
key: fs.readFileSync('./local-ssl/key.pem'),
cert: fs.readFileSync('./local-ssl/cert.pem'),
passphrase: '*****'
}
//other stuff
http.createServer(function (req, res) {
res.writeHead(301, { "Location": "https://" + req.headers['host'] + req.url });
res.end();
}).listen(80);
https.createServer(httpsOptions, app).listen(443)
This works great locally.
The issue is, when I deploy this code and run these servers on AWS EC2 you cannot start servers on ports 80 and 443. I am trying to figure out how I can get around this issue. If I run them on different ports, the servers will not respond, and worse, redirect incorrectly.
Example:
If I serve HTTP on 8081 and HTTPS on 8443, when a redirect occurs, the code redirects to
https://my-fun-url.com:8081
which of course does not work because I am not responding to HTTPS on port 8081.
Now, I've explored the option of port forwarding, but how would this work? If I forward ports 80 and 443 to internal ports (let's say) 3000 and 4000 the same redirection problem will occur.
I have scoured the internet for so long and to me this is a simple requirement for any web-app. I would very much appreciate some detailed guidance on my strategy.
If you want to keep ports 8081 and 8443, then you simply replace 8081 with 8443 in the host header:
httpsHost = req.headers.host.replace('8081', '8443');
res.writeHead(301, {
"Location": "https://" + httpsHost + req.url
});
Now, I've explored the option of port forwarding, but how would this work? If I forward ports 80 and 443 to internal ports (let's say) 3000 and 4000 the same redirection problem will occur.
Not exactly. When someone navigates to http://my-fun-url.com (80) the request is forwarded to 3000. Your http server will respond with a redirect to https://my-fun-url.com (443) which will be forwarded to 4000, and the https server will take it from there.
The difference between the two methods is that with ports 80 and 443 being the default, they are implied and therefore can be left out from the host part of the URL. Which makes the redirect easier as there's no port in the host to replace in the first place, just the protocol part (HTTP/HTTPS).

socket.io cannot communicate with back-end through express

I am using socket.io for fetching some data from the express app. Everything works fine on localhost:8080 but when i deploy my code to the server, client side socket.io cannot communicate with back-end socket.io through express server. I've an apache on the server that forwards everything to localhost:8080 including domain.com/socket.io/?transform=polling... and it extends the request to the express server but express returns a 404 (it comes from the express, not from apache). I am out of ideas, what could be the problem? Here is my code:
express = require "express"
jade = require "jade"
fs = require "fs"
class Bootstrap
_self = undefined
routes:
DEFAULT_PATH: "/"
TEMPLATE_PATH: "/load/:view"
DIRECTIVE_PATH: "/directive/:template"
options:
templatePath: "#{__dirname}/../src/templates"
isDev: "#{__dirname}/../dev"
contentPath: "#{__dirname}/../frontend"
libraryPath: "#{__dirname}/../bower_components"
port: 8080
status:
notFound: 404
isDev: undefined
constructor: ->
_self = #
#isDev = fs.existsSync #options.isDev
#app = express()
#app.use "/frontend", express.static(#options.contentPath)
#app.use "/bower_components", express.static(#options.libraryPath)
#app.set "views", #options.templatePath
#app.set "view engine", "jade"
#app.engine "jade", jade.__express
#app.get #routes.DEFAULT_PATH, (request, response)->
appData =
data:
isDev: _self.isDev
response.render "index", appData
#app.get #routes.TEMPLATE_PATH, (request, response)->
view = request.param "view"
response.render view
#app.get #routes.DIRECTIVE_PATH, (request, response)->
template = request.param("template").replace ".html", ""
response.render "directives/"+template
#app.use (request, response, next)->
_self.logger.warning "404 Not Found!: " + request.originalUrl
response.status(_self.options.status.notFound)
appData =
data:
isDev : _self.isDev
request: request
response.render "404", appData
#server = #app.listen #options.port
#io = require("socket.io").listen #server
#logger = require("./logger.js")
#logger.init #isDev
#socketConnector = require("./live.js")
#socketConnector.init #io
#
new Bootstrap()
You can find the entire code here: https://github.com/eyurdakul/ejder.be
Since you specifically said it works locally and I don't see anything special in your code, I really think the issue resides in your Apache config.
There is a module called mod_proxy_wstunnel you need to have and enable in order to get your WebSocket traffic to work and get proxied correctly to your express application. Either you have Apache 2.4 or, you'll need to apply this patch found in this blogpost and compile again. There is also another blog detailing step by step what you should do under Ubuntu.
After making sure you have the module and its loaded, you'll have to tweak your config to add some WebSocket proxying using the ProxyPass directive
ProxyRequests Off
ProxyPass "/socket-io/" "ws://localhost:8080/socket.io/"
ProxyPassReverse "/socket-io/" "ws://localhost:8080/socket.io/"
You might also want to try to use a rewrite condition on the Upgrade header that is sent with WebSockets:
RewriteEngine On
RewriteCond %{HTTP:Connection} Upgrade [NC]
RewriteRule /(.*) ws://localhost:8000/$1 [P,L]
ProxyPass / http://localhost:8000/
has seen in this comment or this specific thread in general, which exposes a few other possible solutions you can try.
A debugging step that you should take is to have a mock client run in your express app and try to connect to the server port using localhost, or whatever the loopback IP address is. In other words (purely as a temporary testing tool) you place a socket.io Node client into your Express app that gets instantiated and immediately tries to connect to the Socket.io server (which is also in the express app). This should work.
If it does work, you've established that your express server is not the problem. Then, on the client you just added to your express app, you should change the connection address from the local IP to the actual IP address of the server.
If it doesn't work, your problem is probably server side.
My guess is that your apache server is forwarding the polling requests properly, but when Socket.io tries to make the handoff to websockets, Apache is denying the WS request and socket.io is handling this denial internally -- which is why the 404 seems to come from express.
Even I had same issue. The port on which the server is listening , is that open on server. As on local all the ports are open but on server , it's not the case.

Node.js returning empty response for HTTPS

I have the following extremely basic Node.js server:
"use strict";
const http = require("http");
const https = require("https");
const fs = require("fs");
http.createServer((req, res) => {
console.log("regular works");
res.end("Regular response");
}).listen(3000);
https.createServer({
key: fs.readFileSync("/etc/letsencrypt/live/domain.com/privkey.pem"),
cert: fs.readFileSync("/etc/letsencrypt/live/domain.com/cert.pem")
}, (req, res) => {
console.log("secure works");
res.end("Secure response");
}).listen(3001);
I run this as sudo node filename.js, only because files in /etc/letsencrypt/live are root-only. I will do this properly later, this is only for testing.
When run, I can hit port 3000 just fine. The server console prints regular works, and the browser displays Regular response. However, port 3001 returns an empty response, and no message is printed to the server.
The LetsEncrypt files were generated with ./letsencrypt-auto certonly --standalone -d domain.com --email email#gmail.com --agree-tos and appear valid.
What am I missing to have the expected result?
There are two issues here:
Assuming you're not obscuring the real hostname/IP, you should use 127.0.0.1 or similar (if you're on the same machine) instead of 255.255.255.255.
HTTP is the default for cURL, so you're currently sending a plaintext HTTP request to your HTTPS server, which is not going to work (the HTTPS server sees the literal HTTP request as an invalid TLS handshake which causes the connection to end abruptly). To remedy this, explicitly include https:// (e.g. curl -I --verbose https://127.0.0.1:3001).
need to check that the URL contains https:// not http://

Redirect from http to https in Node.js and Express.js using Windows

I've seen this topic about the same issue but the provided solutions don't seem to change the port from 3000 to the default 443 used with SSL.
I've seen in some places iptables should be used to accomplish it, but in a windows environment this can not be done that way.
Temporarily I've fixed it by manually removing the 3000 port by myself:
//redirecting to HTTPS if the connection is not secure
app.use(function(req,resp,next){
if (!req.secure) {
return resp.redirect(301, 'https://' + req.headers.host.replace(':3000', '') + req.url);
} else {
return next();
}
});
Any proper solution for it?

Running a forward proxy server in nodejitsu using node js

I am new to proxy server. What I want to do is: I want to write some node.js code, and then upload to my nodejitsu account to run as a proxy server. Then I would like to use my nodejitsu proxy server on my computer, by configuring the http proxy as "abc.jit.su" (my jitsu URL), and the port as "80" in Chrome, Firefox or IE. That's to say, I want my nodejitsu proxy server to have the same function as the proxies listed here: http://www.freeproxylists.net/. Any ideas?
You can write a simple proxy using the request module, like this:
var http = require('http'),
request = require('request');
// For nodejitsu, this will be port 80 externally
var port = process.env.PORT || 8000;
http.createServer(function(req,res) {
req.pipe(request(req.url)).pipe(res)
}).listen(port);
However, this will only work with http, not https.
Nodejitsu also produces a proxy module, you may get some ideas on what to do next by looking at that.

Resources