I am using CRA (Create React App) and am binding it to local.example.com:443
using the following .env
file:
HOST=local.example.com
PORT=443
HTTPS=true
This ensures that when I run the CRA scaffold, it attempts to bind to local.example.com:443
and a self-signed certificate is issued. I can accept the self-signed in the browser and have an HTTPS-enabled local site. HTTPS is a necessity for some things, such as Secure
cookies etc., so I need it for local development as well as the remote deployment. Also, proxy
can be set to example.com
so that the local frontend uses the remote backend in testing, which is another motivation for this setup.
This works when the host name (example.com
) doesn't have HSTS, but when it does, the un-accepted self-signed certificate which CRA creates, is rejected. The certificate gets created for localhost
, that's the first problem, because example.com
's HSTS needs the certificate to be issued for example.com
to be valid. Firefox:
Firefox does not trust this site because it uses a certificate that is not valid for local.example.com. The certificate is only valid for the following names: localhost, localhost.localdomain, lvh.me, *.lvh.me, [::1], 127.0.0.1, fe80::1
But on top of it, since it is a self-signed certificate, the browser will reject it unless the user accepts it first, which is possible to do without HSTS, because the warning page about a self-signed certificate allows one to do it, but with HSTS, a different warning page is shown (the one showing the error quoted above), which says HSTS won't allow the navigation to go through and you're toast.
In Chrome, it is possible to ignore HSTS
by typing letmein
on the HSTS warning page, which works, but it is not a solution in Firefox and I wonder if there is a better way.
Can CRA issue the certificate so that it appears as if it was issued for example.com
so that example.com
's HSTS accepts it? I assume there would still be a problem with it being self-signed, but if this is possible, maybe the warning page about self-signed certificate will be shown instead nad the user will be able to accept the certificate and carry on?
To "bypass" HSTS locally, you have to generate a valid certificate for your local domain.
The minimal setup would be to generate a self-signed certificate with correct CN and SAN.
You can achieve this even for a website you don't own. The first website that I found that has HSTS with includeSubDomains directive is www.amazon.com.
So I tested a CRA running on local.www.amazon.com.
For that I generated a private key and certificate with the following command:
openssl req \
-x509 \
-newkey rsa:4096 \
-sha256 \
-days 90 \
-nodes \
-keyout noca.local.www.amazon.com.key \
-out noca.local.www.amazon.com.crt \
-subj '/CN=local.www.amazon.com' \
-extensions san \
-config <( \
echo '[req]'; \
echo 'distinguished_name=req'; \
echo '[san]'; \
echo 'subjectAltName=DNS:local.www.amazon.com')
My .env file looks like this:
HOST=local.www.amazon.com
PORT=5000
HTTPS=true
SSL_CRT_FILE=noca.local.www.amazon.com.crt
SSL_KEY_FILE=noca.local.www.amazon.com.key
I open the crt file with the Keychain (I'm on Mac) and trusted it. You can do that differently on other platforms.
You will also have to edit the hosts file (/etc/hosts
for me) and add the following line:
127.0.0.1 local.www.amazon.com
And here is the result:
EDIT 1:
If you have to do this for multiple websites you might want to create a local CA that you self-sign.
And then you will generate all your certificates with that CA.
The benefit will be that you will just have to trust the CA certificate once (in the keychain or in Chrome CA certificates or whatever is used to trust the certificates)