How can I provide a SSL certificate with create-react-app?

84,013

Solution 1

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:

Solution 2

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

Solution 3

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",
      

Solution 4

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!

Solution 5

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

Share:
84,013
mjarraya
Author by

mjarraya

JS enthusiast

Updated on July 09, 2022

Comments

  • mjarraya
    mjarraya almost 2 years


    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
    mjarraya over 7 years
    Life saver! Thank you so much. I configured webpack-dev-server after running eject and it works perfect.
  • Alex K
    Alex K over 7 years
    Glad I was able to help! :)
  • Mike.R
    Mike.R over 6 years
    @MontasarJarraya maybe you can post your own solution step by step for beginners?
  • Nat Kuhn
    Nat Kuhn over 6 years
    Please note that you do not absolutely need to eject in order to do this, if you use react-app-rewired—see 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
  • Alex K
    Alex K over 6 years
    That's awesome, @NatKuhn. I wasn't aware of that option.
  • player87
    player87 almost 6 years
    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?
  • Elad
    Elad almost 6 years
    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.
  • senornestor
    senornestor over 5 years
    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.
  • Filip Grebowski
    Filip Grebowski over 5 years
    What happens if we also need to add a key and a passphrase?
  • carl
    carl about 5 years
    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.
  • Maverick
    Maverick almost 5 years
    If I have a cert.pem and key.pem, how do I create the server.pem?
  • InsOp
    InsOp over 4 years
    Should I add ./local-certificate to .gitignore?
  • Elad
    Elad over 4 years
    You usually don't want to commit certificates to Git, so yes.
  • tim.rohrer
    tim.rohrer over 4 years
    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.
  • Nicolae Olariu
    Nicolae Olariu over 4 years
    Perfect! Thank you so much!
  • Snackoverflow
    Snackoverflow about 4 years
    I can't get the --cert option working with npm start. Are the command-line arguments not passed through or something?
  • Alex K
    Alex K almost 4 years
    @anddero you need an extra -- to pass arguments through npm run to the underlying command. npm start -- --cert
  • Snackoverflow
    Snackoverflow almost 4 years
    As of [email protected] 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.
  • Daly
    Daly almost 4 years
    Is the certificate generated by your script self signed or signed by a certificate authority?
  • Andi
    Andi almost 4 years
    It's self-signed.
  • SenTisso
    SenTisso almost 4 years
    The script doesn't work, it gets stucked on almost every openssl command (using windows 10)
  • viethieule
    viethieule over 2 years
    if it gets stuck on openssl (generate rootCA.key), modify the script by add 'winpty' before any 'oppenssl' command. Found answer here stackoverflow.com/questions/34156938/…
  • Imnotapotato
    Imnotapotato over 2 years
    @viethieule is there any workaround for this for Ubuntu?
  • Maf
    Maf almost 2 years
    Why all these steps for a self-signed certificate?
  • Maf
    Maf almost 2 years
    Why all these steps for a self-signed certificate?
  • Maf
    Maf almost 2 years
    Why all these steps for a self-signed certificate? Why not just adding https=true in .env?
  • Maf
    Maf almost 2 years
    Where do you add the certificate chain so that your certificate can be recognized by all browsers?
  • Maf
    Maf almost 2 years
    Where do you add the certificate chain so that your certificate can be recognized by all browsers?
  • Maf
    Maf almost 2 years
    Where do you add the certificate chain so that your certificate can be recognized by all browsers?
  • Maf
    Maf almost 2 years
    If the certificate is self-signed why do you need these steps instead of just adding https=true to your.env
  • Maf
    Maf almost 2 years
    If the certificate is self-signed why do you need these steps instead of just adding https=true to your.env?
  • Maf
    Maf almost 2 years
    Is the certificate not self-signed?
  • w35l3y
    w35l3y almost 2 years
    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.