OpenShift Invalid certificate | SSL on NodeJS app - node.js

Here's what I'm working with:
NodeJS/Express app
OpenShift environment (Enterprise account)
Works over HTTP
Certificate trust error over HTTPS
Using default wildcard certificate provided by OpenShift
Begins working if I go manually accept the exception the browsers are raising
Latest Express
Server.js looks something like:
var express = require("express"),
app = express(),
IP = process.env.OPENSHIFT_NODEJS_IP || "127.0.0.1",
PORT = process.env.OPENSHIFT_NODEJS_PORT || 8888; // its 8080 on openshift. i use 8888 only on my local environment for irrelevant reasons
// we sometimes need special endpoints that arent files
app.get("/something-special", function(req, res) {
res.send("something special");
});
// but typically it's static files
app.use(express.static(__dirname + "/public"));
// go!
app.listen(PORT, IP);
When I go to https://myserver/file.js (which lives in /public/file.js), I get an error saying the certificate is not trusted.
I dont much understand certificates, and I barely know Node. This is a learning project so I'm trying to work through all of the issues I come across without changing course.
I've tried everything I can think of, including:
app.enable('trust store') recommended on a different SO
simplifying my Node app and using req.secure to force HTTPS

You might try visiting your app using the https://appname-yourdomainname.rhcloud.com/ version of the URL. The underlying digital certificate is *.rhcloud.com and was issued by "Geotrust SSL CA" for what it's worth. If you do it this way you don't get certificate-related errors because they applied a wildcard-based cert to the servers.
I'm not sure that the free version of the hosting allows for private SSLs to be provided/bound... Yeah, you need Bronze or better to allow a private SSL for your application. Bummer

More than likely what is happening is that you are trying to use the *.rhcloud.com wildcard ssl certificate with your custom domain, and that won't work. OpenShift supplies you with an ssl certificate that matches your app-domain.rhcloud.com address. if you want to use SSL correctly with your custom domain, then you need to acquire (or purchase) a custom ssl certificate for your domain name. You can get one at lots of companies online, or you can get a free on here: https://www.startssl.com
Also, the SSL is terminated on the proxy, before it gets to your gear. Check out this developer center article for more information about how it all works: https://developers.openshift.com/en/managing-port-binding-routing.html

Related

Is there a convention for communicating the domain name of a server back to itself?

I'm starting out learning Linux and NodeJS development and part of my current project has an API for which I'm serving documentation with Swagger UI. To support the "try it out" functionality of Swagger I need to specify a host name of the server in the API specs. Everything works fine when I'm running things locally and have the server hard coded to localhost:3000, but in production I obviously want this to show up as myactualdomain.example and not localhost.
Is there a convention for communicating to domain name of a server back to itself? I tried using a HOSTNAME environment variable as follows:
const HOSTNAME = process.env.HOSTNAME || "localhost";
var PORT = process.env.PORT || 80;
const apiSpecs = YAML.load("./api-spec.yml");
apiSpecs.servers = [{ url: `http://${HOSTNAME}:${PORT}` }];
app.use("/api-docs", swaggerUI.serve, swaggerUI.setup(apiSpecs));
This works, but sets the URL to the random host name the Docker container my app is running in is assigned. I could of course override HOSTNAME to myactualdomain.example but I'm not sure if this is "correct" way to do this or if the convention is to use a different environment variable or use another method entirely?

how do i correctly proxy https requests to another https server for cordova

I have a number of different servers running on my system, all of them running a secure connection on there own port, etc. 50001,50002,50003...
all of thees can be accessed directly from https://domain1.com:50001 ...
now, not only do I want to limit the number of ports, but also change the domain so etc.
https://domain1.com:50001 <- https://srv1.domain2.com:443
https://domain1.com:50002 <- https://srv2.domain2.com:443
https://domain1.com:50003 <- https://srv3.domain2.com:443
All of thees servers run separate nodejs instances.
Now I want to build a proxy than redirect this, and I have chosen nodejs since everything else we do is in nodejs.
what i have now:
var app = require('express')();
var options = {
key : fs.readFileSync(CONFIG.sslKey).toString(),
cert : fs.readFileSync(CONFIG.sslCertificate).toString(),
ca : fs.readFileSync(CONFIG.sslCA).toString()
};
var http = require('https').Server(options,app);
var httpProxy = require('http-proxy');
var proxy = httpProxy.createProxyServer({
ssl: {
key : fs.readFileSync(CONFIGsecure.sslKey).toString(),
cert : fs.readFileSync(CONFIGsecure.sslCertificate).toString(),
ca : fs.readFileSync(CONFIGsecure.sslCA).toString()
},
secure: true
});
var handleRequests = function(req, res){
proxyTo = "https://domain1.com:50001"; <= some logic chooses this based on req.headers.host
proxy.web(req, res, { target: proxyTo });
};
app.get('/*', handleRequests );
app.post('/*', handleRequests );
app.put('/*', handleRequests );
app.delete('/*', handleRequests );
http.listen(443, function(){});
okay so this actually works very well, everything is going where it should go in a browser, and in a cordova app using jquery ajax everything also works very well.
however if i use
FileTransfer().download(...)
I get error code 3 (connection error).
If I connect directly to https://domain1.com:50001 (direct) the app works, but if i connect to https://srv1.domain2.com:443 (the proxy) the app does not work.
All the certificates are valid, wildcard certificate on *.domain2.com and single certificate on domain1.com.
The end servers has domain1.com certificate installed and the proxy has *.domain2.com wildcard certificate installed.
Any idea on how to correctly setup a proxy server? The system is windows server 2012 R2 and I am open to use a real proxy if needed. However it would be nice with a solution as simple as possible.
I have tried example two form here:
http://blog.nodejitsu.com/http-proxy-intro/
however this is the same problem, and it is only GET requests.
I have also tried disabling https on the end server so thats it's only the proxy that is secure, however, same result...
Thanks...
Okay so i found the issue, for some reason req.headers.host string also contained the :port, and i was only switching on the address. now everything works perfekt.

NodeJs SSL on Gandi Simple Hosting: listen EACCES

I am pretty desperate, the following problem is haunting me for weeks now:
I am encountering the "listen EACCES" error on my Gandi Simple Hosting instance, when i try to run my NodeJs instance on port 443.
Is there something i did wrong i didn't know about?
I must say that I'm very new to the whole hosting topic.
I am using NodeJs with Express, here's the relevant code:
var express = require('express')
, https = require('https');
var fs = require('fs');
var options = {
key: fs.readFileSync('./scrt/apiKey.key'),
cert: fs.readFileSync('./scrt/apiCrt.crt')
};
//....
app.set('port', process.env.PORT || 443);
//.....
https.createServer(options, app).listen(app.get('port'), function(){
});
Do you have any idea what i miss?
Maybe i have to change some configuration for the port 443?
I was just told by Gandi, that port 443 is the right port for SSL, so actually it should work...
Thank you very much in advance for your help!
Edit: No one here ever had the same problems with SSL on nodejs? :/
In Gandi Simple Hosting, SSL is done by a SSL offloader, you do not need to handle it by yourself.
The ssl offloader then redirects all incoming trafic (HTTP and HTTPS) on the instance's 8080 port.
To see if a request is secure, I bet you could look at the X-Forwarded-Proto header.
Ok I have had the answer from Gandi support team: all the traffic, SSL and not SSL is routed to the port 8080.
I still could not get it working since nodejs needs to handle one port for both traffic and it is not straightforward, see these posts
Is possible to run http and https server with same port no in node.js using express?
A node.js proxy that accepts HTTP and HTTPS traffic on the same port.
EDIT: #themouette is right, it works out of the box, no need to handle it in nodejs, but you need to activate the certificate on the domain level, but from your instance's admin page, which is not written in the docs.

Meteor: How to get the hostname, server side

On the client I can use window.location.hostname to get the hostname. How can I get the same on the server?
I need this to work behind an Apache proxy, unfortunately Meteor.absoluteUrl() gives me localhost:3000. I also want it to work for different domains, I want one Meteor app that gives different results for different domains.
This question is somewhat related: Get hostname of current request in node.js Express
Meteor.absoluteUrl() given that your ROOT_URL env variable is set correctly.
See the following docs: http://docs.meteor.com/#meteor_absoluteurl.
Meteor doesn't know the outside-facing address of the proxy that it's sitting behind, and the (virtual) domain that this proxy was accessed by would have to be forwarded to the Meteor app for it to do what you are asking for. I don't think this is currently supported.
According to this you can now get the Host header inside Meteor.publish() and Meteor.methods() calls by accessing:
this.connection.httpHeaders.host
Elsewhere in the application, it's probably difficult to determine the Host header that is being used to connect.
If you want the hostname of the server, as configured in /etc/hostname for example:
With meteorite:
$ mrt add npm
In your server code:
os = Npm.require('os')
hostname = os.hostname()
This has no connection to the Host header provided in the incoming request.
updated answer with some of chmac's words from the comment below
In any server-side meteor file you can add:
if (Meteor.isServer) {
Meteor.onConnection(function(result){
var hostname = result.httpHeaders.referer; //This returns http://foo.example.com
});
}
You can fetch host as EnvironmentVariable from DDP object in method and publication. Meteor accounts-base package fetch userId via this way.
const currentDomain = function() {
const currentInvocation = DDP._CurrentMethodInvocation.get() || DDP._CurrentPublicationInvocation.get();
return currentInvocation.connection.httpHeaders.host;
}

Yeoman generator-angular-fullstack enabling ssl

Trying to be able to run a SSL server using the generator-angular-fullstack https://github.com/DaftMonk/generator-angular-fullstack.
However when I look at all the examples for enabling SSL, when I comb through the code it doesn't seem to initialize the server the same way as the NodeJS documentation explains to:
var options = {
key: fs.readFileSync('test/fixtures/keys/agent2-key.pem'),
cert: fs.readFileSync('test/fixtures/keys/agent2-cert.pem')
};
// Create a service (the app object is just a callback).
var app = express();
// Create an HTTP service.
http.createServer(app).listen(80);
// Create an HTTPS service identical to the HTTP service.
https.createServer(options, app).listen(443);
Has anyone had any success in doing it? Outside of that this generator seems to be incredible and easy to use.
Yes, the code above is how you run your app on 443, using the key and cert you have specified above. This should allow you to communicate with your app over HTTPS, assuming you have those keys (and of course you'll get warnings in the browser if they're self signed).
But yes, that works, and is how it's done. I've found that most people like to keep the Node app running on HTTP and instead use a web server (such as nginx) to deal with SSL. The communication from the web server to the Node app is then over HTTP. This helps keep the Node app easy to run in a development/test environment, and then in production you have the security of SSL.

Resources