1

I am attempting to setup a server with ExpressJS which uses HTTPS and servers a React app. I want any HTTP requests to be redirected to using HTTPS.

Additional constraint: I am using React router, so the server needs to be able to handle that. e.g. if I request localhost:3000/profile, I want React Router to handle that, I just need Express to server up index.html as I had gone to localhost:3000.

Problem: I think I've been able to setup HTTPS (Chrome complains but I don't mind for now), but I cannot get redirection to work.

For comparison, this is my code for how I setup my HTTP-only server for development (before I ever tried to setup HTTPS):

const express = require('express');
const http = require('http');
const path = require('path');
const app = express();

const DIST_DIR = path.resolve('./dist');
app.use(express.static(DIST_DIR));

app.get('*', (req, res) => {
    res.sendFile(path.resolve(DIST_DIR, './index.html'));
});

const devServer = http.createServer(app);
devServer.listen(3000);

Next, I started with this guide. I created a self-signed SSL certificate then set up my application. I then looked at some examples of how to redirect, such as this question.

However, it doesn't seem to be working.

Here is my code at present:

app.use(express.static(DIST_DIR));

app.use((req, res, next) => {
    if (req.secure) {
        next();
    } else {
        res.redirect(`https://${req.headers.host}${req.url}`);
    }
});

app.get('*', (req, res) => {
    res.sendFile(path.resolve(DIST_DIR, './index.html'));
});

const httpServer = http.createServer(app);
httpServer.listen(3080);

const privateKey = // uses FS to get my key
const certificate = // uses FS to get my cert
const credentials = { key: privateKey, cert: certificate };
const httpsServer = https.createServer(credentials, app);
httpsServer.listen(3443);

I can access https://localhost:3443 and navigate the app as expected, and Express properly handles refreshes on pages like /profile. Great. Chrome complains that "CA root certificate is not trusted. Install this cert in the trusted root certification authorities store" but I haven't put in the work to solve that, because in a real production environment I'd be provided the certificate and key from a trusted source.

However, when I go to http://localhost:3080, I just end up at http://localhost:3080. Chrome devtools shows I'm not using HTTPS. Furthermore, I can't go directly to /profile, as Chrome gives me the error "This site can’t provide a secure connection".

I've tried other methods listed in that stackoverflow question I linked, but they either have the same behavior or straight up don't work. I'm a bit out of my element here and I'm trying to learn, but I don't understand why this isn't working. Any help would be appreciated. Thanks.

cdpautsch
  • 1,769
  • 3
  • 13
  • 24

1 Answers1

2

While you can manage this in your application it is often the convention to have a web server like nginix or apache in front of your application that manages the https redirection. Depending on your setup it is also common to manage your certificates at this front server to simplify certificate management. If you are going to deploy onto aws or another cloud provider I would let their infrastructure handle this for you.

Deadron
  • 5,135
  • 1
  • 16
  • 27
  • 1
    Thanks for the response. Needless to say this was driving me up the wall. I found another guide of sorts which mentioned this (linked below). I assume this is what you are talking about; a reverse proxy with Nginx? https://developer.ibm.com/tutorials/make-https-the-defacto-standard/ – cdpautsch Aug 19 '19 at 20:37
  • In that scenario, would Express still be setup with HTTPS, and just eschew any handling of HTTP because Nginx will redirect everything to HTTPS? – cdpautsch Aug 19 '19 at 20:44
  • You can do it either way. If you are deploying to something aws its common for your application to only serve http. Nodejs apps tend to scale horizontally which means multiple places to manage certificates if its not done at the front server so its easier to manage https just at the one nginix/apache/ELB. – Deadron Aug 19 '19 at 21:52
  • Its also easier to use lets encrypt for no cost ssl certs with an nginix/apache than with your own custom server. – Deadron Aug 19 '19 at 21:54