Reputation: 607
I have an app on Heroku that was created using create-react-app
. Just today, I got an SSL cert using Heroku's automated(-ish) SSL cert process ExpeditedSSL, and the documentation then suggests rerouting all http requests to https.
I have a server.js file and express I use just to attempt to run middleware and then serve my React app.
I know the SSL cert is working as if I go to https://myapp.com I see my Heroku app, but when I go to http://myapp.com it is not redirected to the https version of my Heroku app.
I have tried many, many solutions
today from StackOverflow, Google, and otherwise and none of the the solutions have worked for me. I don't get any errors, either. It just doesn't work.
Attempt using https library
:
const https = require("https");
const express = require('express');
const app = express();
app.use(express.static(path.join(__dirname, 'build')));
app.get('/', function (req, res) {
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});
https.createServer(app).listen(3000);
Another attempt using heroku-ssl-redirect
:
var sslRedirect = require('heroku-ssl-redirect');
var express = require('express');
var app = express();
// enable ssl redirect
app.use(sslRedirect(['production'], 301));
app.use(express.static(path.join(__dirname, 'build')));
app.get('*', (req, res, next) => {
if (req.headers['x-forwarded-proto'] != 'https'){
res.redirect('https://' + req.hostname + req.url);
} else {
next();
}
});
app.get('/', function (req, res) {
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});
app.listen(process.env.PORT || 3000);
Attempt using x-forward-proto
:
const express = require('express');
const env = process.env.NODE_ENV || 'development';
const bodyParser = require('body-parser');
const path = require('path');
const app = express();
var forceSsl = function (req, res, next) {
if (req.headers['x-forwarded-proto'] !== 'https') {
return res.redirect(['https://', req.get('Host'), req.url].join(''));
}
return next();
};
if (env === 'production') {
app.use(forceSsl);
}
app.use(express.static(path.join(__dirname, 'build')));
app.get('/', function (req, res) {
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});
app.listen(process.env.PORT || 8080);
I've also attempted a number of random node installs from various blogs and SO posts, and nothing has worked. Without any errors I am having a hard time figuring out why this doesn't work.
Upvotes: 16
Views: 6986
Reputation: 5687
This seem to work for me React on Heroku
Buildpack https://github.com/mars/create-react-app-buildpack
root/static.json
{
"root": "build/",
"routes": {
"/**": "index.html"
},
"https_only": true
}
Upvotes: 0
Reputation: 2358
UPDATED and SECURE solution below:
Since you are deploying your react app via Heroku using create-react-app and it's buidlpack (recommended, if you are not: create-react-app-buildpack). So as the official docs says:
The web server may be configured via the static buildpack.
The config file static.json
should be committed at the root of the repo. It will not be recognized, if this file in a sub-directory
The default static.json
, if it does not exist in the repo, is:
{
"root": "build/",
"routes": {
"/**": "index.html"
}
}
Enforce secure connections by automatically redirecting insecure requests to https://, in static.json
:
{
"root": "build/",
"routes": {
"/**": "index.html"
},
"https_only": true
}
The method by @misterfoxy works but is not the right way!
Upvotes: 10
Reputation: 613
Try adding this to your index.html file Place it in the header, so it would run before other scripts
<script>
const domain1 = "www.example.com";
const domain2 = "example.com";
const host = window.location.host;
if ((domain === host || domain2 === host) && (window.location.protocol !== "https:")){
window.location.href = "https://www.example.com";
}
</script>
Upvotes: 0
Reputation: 194
Try adding the following to the header of your index.html file
<script>
var host = "www.URL.com" || "URL.com";
if ((host == window.location.host) && (window.location.protocol != "https:")){
window.location.protocol = "https";
}
</script>
I was dealing with a similar issue and this allowed me to resolve it. Placing it in the header ensures that the script will run before any of your bundled JavaScript, but I suppose it would work above your bundle.js file
Upvotes: 17
Reputation: 5261
Try using express-https-redirect
.
Install with:
npm install express-https-redirect --save
Then you should be able to do something like:
const express = require('express');
const httpsRedirect = require('express-https-redirect');
const app = express();
app.use('/', httpsRedirect());
app.set('port', process.env.PORT || 3000);
app.use(express.static(path.join(__dirname, 'build')));
app.get('/', function (req, res) {
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});
app.listen(app.get('port'), function () {
console.log('Express server listening on port ' + app.get('port'));
});
Upvotes: 0