53


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 ?

mjarraya
  • 1,116
  • 1
  • 11
  • 18

11 Answers11

48

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:

Andi
  • 3,249
  • 1
  • 20
  • 12
  • Is the certificate generated by your script self signed or signed by a certificate authority? – Daly Jul 25 '20 at 18:26
  • It's self-signed. – Andi Jul 26 '20 at 04:34
  • 1
    The script doesn't work, it gets stucked on almost every openssl command (using windows 10) – SenTisso Aug 08 '20 at 10:44
  • if it gets stuck on openssl (generate rootCA.key), modify the script by add 'winpty' before any 'oppenssl' command. Found answer here https://stackoverflow.com/questions/34156938/openssl-hangs-during-pkcs12-export-with-loading-screen-into-random-state – viethieule Oct 31 '21 at 03:21
  • @viethieule is there any workaround for this for Ubuntu? – Imnotapotato Dec 27 '21 at 08:09
  • If the certificate is self-signed why do you need these steps instead of just adding https=true to your.env – Maf Jun 28 '22 at 07:09
35

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"
}
  • My solution is based on this thread
Elad
  • 19,079
  • 18
  • 62
  • 71
  • If I understand this correctly, one would move the three files to the `node_modules/webpack-dev-server/ssl/` dir and then execute `npm run build && serve -s build`. OR, `npm run postinstall && npm run build && serve -s build` ... is that correct? – player87 Jun 19 '18 at 19:10
  • Not exactly. You should create a folder in the root of your app (i.e. sibling of `node_modules`) that contains your `server.pem` and the script file. Then you add the `postinstall` script to your `package.json`. The script then runs automatically after each `npm install`, so no need to change your workflow. HTH. – Elad Jun 20 '18 at 19:45
  • Should I add `./local-certificate` to `.gitignore`? – InsOp Nov 18 '19 at 10:28
  • You usually don't want to commit certificates to Git, so yes. – Elad Nov 19 '19 at 08:25
  • Two things I had to work through. My server certificate is from Let's Encrypt and the private key is in a separate file. I had to add it to `fullchain.pem` and then rename it to `server.pem`. Also, because my dev user isn't root, I had to make sure my user is the owner/group of the new `server.pem`. – tim.rohrer Dec 10 '19 at 01:35
  • 2
    [As of `react-scripts@3.4.0`](https://github.com/facebook/create-react-app/blob/master/CHANGELOG.md#nail_care-enhancement-1) as stated in Andi's answer, the certificate can be provided via environment variable which is a modern, elegant and OS-independent approach as opposed to the proposed bash script workaround above. Because this is a highly upvoted and also the accepted answer, I believe it should be updated, at least stating that there is an out-of-the-box solution to the task for modern versions of React. – Snackoverflow May 12 '20 at 10:51
  • Where do you add the certificate chain so that your certificate can be recognized by all browsers? – Maf Jun 28 '22 at 07:05
17

To expand on Elad's answer:

    1. Create a self-signed certificate following the instructions linked to from https://github.com/webpack/webpack-dev-server/tree/master/examples/cli/https
    1. Save the pem file (containing both the certificate and private key) somewhere in your project (e.g. /cert/server.pem)
    1. Modify your package.json scripts:
      "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",
      
Nicolás Alarcón Rapela
  • 2,714
  • 1
  • 18
  • 29
senornestor
  • 4,075
  • 2
  • 33
  • 33
  • 1
    I ended up using devcert-cli (I just saw mkcert today which also looks good) to generate a signed certificate for localhost in `./cert`. I then add the following `prestart` script to my package.json: `cp -f ./cert/server.pem ./node_modules/webpack-dev-server/ssl`. The benefit of using devcert is that you get a signed certificate vs. self-signed and so you won't see any warning or errors in Chrome. – senornestor Jan 07 '19 at 20:54
  • 1
    What happens if we also need to add a key and a passphrase? – Filip Grebowski Jan 07 '19 at 21:39
  • 1
    Note the key to step #2 above is to concatenate the certificate and private key into a single file. In the case of a LetsEncrypt certificate we made, that's privkey.pem + fullchain.pem. – carl Mar 15 '19 at 21:51
  • 3
    If I have a cert.pem and key.pem, how do I create the server.pem? – Maverick May 23 '19 at 01:08
  • If the certificate is self-signed why do you need these steps instead of just adding https=true to your.env? – Maf Jun 28 '22 at 07:11
9

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!

Alex K
  • 14,893
  • 4
  • 31
  • 32
  • Life saver! Thank you so much. I configured webpack-dev-server after running eject and it works perfect. – mjarraya Dec 19 '16 at 14:48
  • Glad I was able to help! :) – Alex K Jan 04 '17 at 16:54
  • @MontasarJarraya maybe you can post your own solution step by step for beginners? – Mike.R Dec 08 '17 at 23:16
  • 1
    Please note that you do not absolutely need to eject in order to do this, if you use `react-app-rewired`—see https://github.com/timarney/react-app-rewired. I found that to get this to work I still needed to set the environment variable HTTPS to `true` – Nat Kuhn Dec 24 '17 at 22:41
  • 1
    That's awesome, @NatKuhn. I wasn't aware of that option. – Alex K Jan 21 '18 at 04:40
  • I can't get the `--cert` option working with `npm start`. Are the command-line arguments not passed through or something? – Snackoverflow Feb 20 '20 at 16:21
  • @anddero you need an extra -- to pass arguments through npm run to the underlying command. `npm start -- --cert` – Alex K May 11 '20 at 20:50
  • Where do you add the certificate chain so that your certificate can be recognized by all browsers? – Maf Jun 28 '22 at 07:08
  • @Maf You could use, for example, mkcert, which handles installing the generated cert into the local system trust store. https://github.com/FiloSottile/mkcert – Alex K Jul 14 '22 at 22:07
  • @AlexK, yes you could. Now what about configuring real certificates trusted everywhere? – Maf Jul 14 '22 at 22:20
  • @Maf You would buy one or use a service like Let's Encrypt and install it in your web server. Create react app has nothing to do with this. – Alex K Jul 15 '22 at 21:19
  • Yes, neither with mkcert. – Maf Jul 16 '22 at 07:23
  • You can do the same thing with a real cert. I gave some ideas above for how to get one. You shouldn't be using webpack-dev-server in production though so there's not really a good reason to use a real cert. The advantage of creating your own cert instead of using the built-in one is you can install it locally so all of your browsers accept it as a trusted cert, which is what you asked. – Alex K Aug 02 '22 at 21:12
5

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

Jay
  • 2,648
  • 4
  • 29
  • 58
  • 1
    A dot is missing in the start script SSL_KEY_FILE path before the word cert. Correct: SSL_KEY_FILE=./.cert/key.pem – criss_dev Sep 01 '22 at 16:36
  • This worked beautifully for localhost. Do you know how to get it working with the remote network IP? I tried this but although the keys are being generated, Chrome is displaying it as unsecure: `mkcert -key-file ./remotework/key.pem -cert-file ./remotework/cert.pem "http://192.168.20.115"` – D. Rattansingh Jun 16 '23 at 14:24
  • my friend, i am only a beginner students coding tutor. so, the basics is all i know. – Jay Jun 18 '23 at 05:57
3

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.

https config in react-scripts

Paul van Dyk
  • 868
  • 10
  • 8
  • Where do you add the certificate chain so that your certificate can be recognized by all browsers? – Maf Jun 28 '22 at 07:00
3

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,

  1. 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"
    },
    
  2. Create your SSL certificate

  3. In the project root folder, run:

    openssl req -x509 -newkey rsa:2048 -keyout keytmp.pem -out cert.pem -days 365
    
  4. run the

    openssl rsa -in keytmp.pem -out key.pem
    mkdir .cert
    mv key.pem .cert/key.pem
    mv cert.pem .cert/cert.pem
    
  5. 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"
     },
    
  6. now run with https://lochost:3000

wisemonkey
  • 13
  • 3
Rakesh
  • 2,732
  • 29
  • 28
  • Why all these steps for a self-signed certificate? – Maf Jun 28 '22 at 06:58
  • This one solved it for me, specifically the `"start": "HTTPS=true SSL_CRT_FILE='./.cert/cert.pem' SSL_KEY_FILE='./.cert/key.pem' react-scripts start"` line – Nick Feb 26 '23 at 15:12
2

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/.

  1. 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

  2. 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!

  3. 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).

Maf
  • 696
  • 1
  • 8
  • 23
  • 1
    Did you mean: SSL_CRT_FILE=.cert/your_domain.crt SSL_KEY_FILE=.cert/your_domain.key – gfjr Dec 05 '22 at 11:24
  • Exactly. Thanks for the catch. I'm updating now. – Maf Dec 05 '22 at 12:12
  • 2
    Someone might want to use self signed certs for their development environment though – Nick Feb 26 '23 at 15:13
  • You can use the same method with self-signed certs, you just need to do an extra step and trust them in your browser when you hit the page. – Matt K Mar 16 '23 at 22:52
1

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:

w35l3y
  • 8,613
  • 3
  • 39
  • 51
  • Perfect! Thank you so much! – Nicolae Olariu Dec 17 '19 at 13:36
  • Is the certificate not self-signed? – Maf Jun 28 '22 at 07:12
  • I explained a way to copy a certificate to the right folder, as he already have the certificate. The bash command is just an example to generate the certificate. His question is "How can I use my own SSL certificate" and I explained how... copying the certificate to that folder. – w35l3y Jun 28 '22 at 19:24
1

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

enter image description here

Rohit Parte
  • 3,365
  • 26
  • 26
-1

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",
Jay Douglass
  • 4,828
  • 2
  • 27
  • 19
  • Why all these steps for a self-signed certificate? Why not just adding https=true in .env? – Maf Jun 28 '22 at 06:59