Reputation: 1226
I am trying to host a react app I created and tested locally using the facebook boilerplate.
The client app interacts with an API I made using node.js, and with which I had no issue setting up a secure connection (with a node.js client sending my SSL certificate, for testing).
However, I am encountering difficulties when it comes to using react to send my SSL certificate instead of a self-signed one which causes me to encounter this error using chrome and trying to access to https://example.net:3000 :
Your connection is not private (NET:ERR_CERT_AUTHORITY_INVALID)
The documentation did not quite help me:
Note that the server will use a self-signed certificate, so your web browser will almost definitely display a warning upon accessing the page. https://github.com/facebookincubator/create-react-app/blob/master/packages/react-scripts/template/README.md#using-https-in-development
How can I use my own SSL certificate (which I already use on another app on my domain and works like a charm) instead of this self-signed one ? Did I miss something ?
Upvotes: 59
Views: 150812
Reputation: 5510
Here's a detailed answer since certificate errors tend to be very vague. I use IIS's Application Request Routing and url rewrite to manage it all.
Okay first, my backend is Node.js app uses this same certificate, so I created a symlink between devserver/_certs and devclient/_certs, but the front-end and back-end want different files
Here's the relevant NodeJS code
const app = express()
...
const serverProcess = https.createServer(getSSLFiles(), app);
serverProcess.listen(11001, () => {
console.log(`Server online.`)
});
function getSSLFiles() {
return {
// Note these two files used
cert: fs.readFileSync(path.join(__dirname, "..", "_certs", "fullchain.pem")),
key: fs.readFileSync(path.join(__dirname, "..", "_certs", "privkey.pem")),
}
}
// This is unnecessary for the demonstration, just a nice function to always makre sure
setInterval(function () {
serverProcess.setSecureContext(getSSLFiles())
}, 86400000); // 60 * 60 * 24 * 1000, once a day
And then I use this env file, literally named .env
, again with the symlink noded above. Some answers on the web say to use SSL_CERT_FILE, but it's SSL_CRT_FILE (no E in CRT)
# Whatever port you want
PORT="11002"
HOST="mydevsite.local"
HTTPS="true"
SSL_CRT_FILE="./_certs/cert.crt"
SSL_KEY_FILE="./_certs/privkey.pem"
with this command, (npm run dev
)
"dev": "env-cmd -f .env react-scripts start",
And then finally my web.config file that takes advantage of of both of these. There are two api rewrite rules, one is disabled. Choose whichever style you like
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<clear />
<rule name="well-known">
<match url="^\.well-known/acme-challenge/([\w-]+)$" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false" />
<action type="Rewrite" url="/.well-known/acme-challenge/{R:1}" />
</rule>
<rule name="api-https" stopProcessing="true">
<!-- Note that this rewrites
https://mydevsite.local/api/path/to/dest to https://mydevsite.local:11001/path/to/dest,
'api' is deliberately removed -->
<match url="api/(.*)" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{CACHE_URL}" pattern="^https://" />
</conditions>
<action type="Rewrite" url="https://mydevsite.local:11001/{R:1}" />
<!-- ^ 11001, my server port -->
</rule>
<rule name="api-https2" stopProcessing="true" enabled="false">
<!-- Note that this rewrites
https://mydevsite.local/api/path/to/dest to https://mydevsite.local:11001/api/path/to/dest -->
<match url="api/.*" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{CACHE_URL}" pattern="^https://" />
</conditions>
<action type="Rewrite" url="https://mydevsite.local:11001/{R:0}" />
<!-- ^ 11001, my server port -->
</rule>
<rule name="ReverseProxy" stopProcessing="true">
<match url="(.*)" />
<action type="Rewrite" url="https://mydevsite.local:11002/{R:1}" />
<!-- ^ 11002, my client port -->
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
Upvotes: 0
Reputation: 725
Do not use self-signed certificates as I saw in some answers. There are lots of trusted certificate providers over the web. You just need to have a valid domain and you can easily prove that you are the owner. My certificate was provided by this authority for free: https://www.noip.com/.
Create your private key
and the Certificate Signing Request
(CSR
):
openssl req -new -newkey rsa:2048 -nodes -keyout your_domain.key -out your_domain.csr
Go to a certificate provider like noip
and request a certificate by submitting your CSR
and you'll receive at your email a trusted signed cerificate. Don't forget to keep secret your private key
, just share the CRS with your authority!
Then in react you just need to have your .env
file configured as follows (.cert/
folder in the root directory):
HOST=<YOUR_IP_OR_DOMAIN>
HTTPS=true
PORT=443
SSL_CRT_FILE=.cert/your_domain.crt
SSL_KEY_FILE=.cert/your_domain.key
Note: In my case I did not use the 443 port because I'm using port forwarding, so I can use any port inside my internal network. Also the IP address you can use the public one directly or you can forward to any private address (this is what I do).
Upvotes: 2
Reputation: 3040
Ultimately, this is what helped me. on Windows.
"scripts": {
"start": "set HTTPS=true&&set SSL_CRT_FILE=./.cert/cert.pem&&set SSL_KEY_FILE=./cert/key.pem&&react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
But first, i got the certificates like this.
//create a certficate folder
mkdir -p .cert
//create the actual certificates in the folder
mkcert -key-file ./.cert/key.pem -cert-file ./.cert/cert.pem "localhost"
note : i had to install mkcert using chocolatey, on windows. So, you probably have to start with this, before getting the React js app to work with https on windows.
Update1 : I put the entire code on github, if someone wants to see a full solution in action. link here - https://github.com/Jay-study-nildana/FrontEndForStudents/tree/main/ReactJSForStudents/httpshelloworld
Upvotes: 7
Reputation: 4036
Simplest way is to run reactjs with SSL on Ubuntu and windows is -
Create cert.pem and key.pem file and put it in ssl folder in app root folder
add below lines in scripts of package.json
"scripts": {
"start": "...",
"build": "...",
"ssl-linux": "export HTTPS=true&&SSL_CRT_FILE=/ssl/cert.pem&&SSL_KEY_FILE=/ssl/key.pem craco start",
"ssl-win": "set HTTPS=true&&npm start"
},
Ubuntu - npm run ssl-linux on ubuntu
Windows - npm run ssl-win
To create pem file on ubuntu
Step 1. openssl req -x509 -newkey rsa:2048 -keyout keytmp.pem -out cert.pem -days 365
Step 2. openssl rsa -in keytmp.pem -out key.pem
Sample folder structure
Upvotes: 1
Reputation: 2770
Are we looking for integration of SSL (HTTPS) to localhost for application? Or securely API call with any encryption (specific) algo.
If SSL enablement only,
Need to change at package.json file with HTTPS like –
"scripts": {
"start": "HTTPS=true react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
Create your SSL certificate
In the project root folder, run:
openssl req -x509 -newkey rsa:2048 -keyout keytmp.pem -out cert.pem -days 365
run the
openssl rsa -in keytmp.pem -out key.pem
mkdir .cert
mv key.pem .cert/key.pem
mv cert.pem .cert/cert.pem
Enable your certificate (.perm) like –
"scripts": {
"start": "HTTPS=true SSL_CRT_FILE='./.cert/cert.pem' SSL_KEY_FILE='./.cert/key.pem' react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
now run with https://lochost:3000
Upvotes: 3
Reputation: 4918
Use mkcert to create the self-signed cert and install it. I tried other methods but they're error prone.
Example using macOS:
brew install mkcert
mkcert -install
mkcert localhost
Edit package.json:
"start": "HTTPS=true SSL_CRT_FILE=localhost.pem SSL_KEY_FILE=localhost-key.pem react-scripts start",
Upvotes: 1
Reputation: 1016
Here is the webpack config of react-scripts when using HTTPS=true
along side SSL_CRT_FILE
& SSL_CRT_FILE
. So you should just be able to add it to the env to set the paths to your cert.
Upvotes: 4
Reputation: 20189
Update: see Andi's answer below. In recent version you should set environment variable to configure the certificate
SSL_CRT_FILE=.cert/server.crt
SSL_KEY_FILE=.cert/server.key
Ejecting create-react-app
is not recommended since you won't be able to seamlessly upgrade it. Moreover, you can easily have valid SSL certificate without ejecting.
You will need to copy your certificate to node_modules/webpack-dev-server/ssl/server.pem
. The downside is that you need to manually copy the file. However, one way to make this seamless is to add a postinstall
script that creates a symlink.
Here is a script I created:
#!/bin/bash
# With create-react-app, a self signed (therefore invalid) certificate is generated.
# 1. Create some folder in the root of your project
# 2. Copy your valid development certificate to this folder
# 3. Copy this file to the same folder
# 4. In you package.json, under `scripts`, add `postinstall` script that runs this file.
# Every time a user runs npm install this script will make sure to copy the certificate to the
# correct location
TARGET_LOCATION="./node_modules/webpack-dev-server/ssl/server.pem"
SOURCE_LOCATION=$(pwd)/$(dirname "./local-certificate/server.pem")/server.pem
echo Linking ${TARGET_LOCATION} TO ${SOURCE_LOCATION}
rm -f ${TARGET_LOCATION} || true
ln -s ${SOURCE_LOCATION} ${TARGET_LOCATION}
chmod 400 ${TARGET_LOCATION} # after 30 days create-react-app tries to generate a new certificate and overwrites the existing one.
echo "Created server.pem symlink"
Your package.json
should look something like:
"scripts": {
...
"postinstall": "sh ./scripts/link-certificate.sh"
}
Upvotes: 35
Reputation: 15848
Your server that serves files from that port needs to be configured to use your SSL cert. I'm guessing you are using webpack-dev-server on that port (that's what npm start
does in create-react-app), and maybe a different server (apache, nginx, etc) on port 80?
You can either serve your compiled files using your already configured server, or configure webpack-dev-server to use your SSL cert.
To do this, you can use webpack-dev-server's --cert
option. See https://webpack.github.io/docs/webpack-dev-server.html
NOTE: you need an extra
--
to pass arguments through npm run to the underlying command, e.g.npm start -- --cert ...
.
If you want to do this using npm start, which calls a custom start script, you'll have to edit that start script. You may need to use the eject
command first, which dumps all the config code into your repo so you can change it.
Here is the source code of the start script: https://github.com/facebookincubator/create-react-app/blob/master/packages/react-scripts/scripts/start.js#L230
I should also note that webpack-dev-server isn't intended to be used in a production environment.
Have fun!
Upvotes: 9
Reputation: 3727
I was able to get a local certificate working without modifying the webpack-dev-server
files using react-scripts
3.4.1
(technically added in 3.4.0
but I had some—probably unrelated—issues). I added these two environment variables to my .env.development
:
SSL_CRT_FILE=.cert/server.crt
SSL_KEY_FILE=.cert/server.key
Notes:
.cert
is a folder I created in the root of my projectUpvotes: 55
Reputation: 4165
To expand on Elad's answer:
/cert/server.pem
)"start": "HTTPS=true react-scripts start",
"prestart": "rm ./node_modules/webpack-dev-server/ssl/server.pem && cp -f ./cert/server.pem ./node_modules/webpack-dev-server/ssl",
Upvotes: 17
Reputation: 8773
This is what I did:
bash <(wget -qO- https://gist.github.com/w35l3y/5bb7fe8508d576472136f35428019177/raw/local-cert-generator.sh)
Then I double clicked and imported: rootCA.pem
and server.pem
Then I modified package.json
:
"start": "HTTPS=true react-scripts start",
"prestart": "cp -f /path/to/server.pem ./node_modules/webpack-dev-server/ssl",
Very important sources:
Upvotes: 1