create a trusted self-signed SSL cert for localhost (for use with Express/Node)
Solution 1
The answers above were partial. I've spent so much time getting this working, it's insane. Note to my future self, here is what you need to do:
I'm working on Windows 10, with Chrome 65. Firefox is behaving nicely - just confirm localhost as a security exception and it will work. Chrome doesn't:
Step 1. in your backend, create a folder called security
. we will work inside it.
Step 2. create a request config file named req.cnf
with the following content (credit goes to: @Anshul)
req.cnf :
[req]
distinguished_name = req_distinguished_name
x509_extensions = v3_req
prompt = no
[req_distinguished_name]
C = Country initials like US, RO, GE
ST = State
L = Location
O = Organization Name
OU = Organizational Unit
CN = www.localhost.com
[v3_req]
keyUsage = critical, digitalSignature, keyAgreement
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = www.localhost.com
DNS.2 = localhost.com
DNS.3 = localhost
An explanation of this fields is here.
Step 3. navigate to the security folder in the terminal and type the following command :
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout cert.key -out cert.pem -config req.cnf -sha256
Step 4. then outside of security
folder, in your express app do something like this: (credit goes to @Diego Mello)
backend
/security
/server.js
server.js:
const express = require('express')
const app = express()
const https = require('https')
const fs = require('fs')
const port = 3000
app.get('/', (req, res) => {
res.send("IT'S WORKING!")
})
const httpsOptions = {
key: fs.readFileSync('./security/cert.key'),
cert: fs.readFileSync('./security/cert.pem')
}
const server = https.createServer(httpsOptions, app)
.listen(port, () => {
console.log('server running at ' + port)
})
Step 5. start the server, node server.js
, and go to https://localhost:3000.
At this point we have the server setup. But the browser should show a warning message.
We need to register our self-signed certificate, as a CA trusted Certificate Authority, in the chrome/windows certificates store. (chrome also saves this in windows,)
Step 6. open Dev Tools in chrome, go to Security panel, then click on View Certificate.
Step 7. go to Details panel, click Copy File, then when the Certificate Export Wizard appears, click Next as below:
Step 8. leave DER encoding, click next, choose Browse
, put it on a easy to access folder like Desktop, and name the certificate localhost.cer, then click Save and then Finish.
. You should be able to see your certificate on Desktop.
Step 9. Open chrome://settings/
by inserting it in the url box. Down below, click on Advanced / Advanced Options
, then scroll down to find Manage Certificates
.
Step 10. Go to Trusted Root Certification Authorities panel, and click import.
We will import the localhost.cer
certificate we just finished exporting in step 8.
Step 11. click browse, find the localhost.cer
, leave the default values click next a bunch of times - until this warning appears, click yes.
Step 12. close everything, and restart chrome. Then, when going to https://localhost:3000
you should see:
Solution 2
Shortest way. Tested on MacOS, but may work similarly on other OS.
Generate pem
> openssl req -x509 -newkey rsa:2048 -keyout keytmp.pem -out cert.pem -days 365
> openssl rsa -in keytmp.pem -out key.pem
Your express server
const express = require('express')
const app = express()
const https = require('https')
const fs = require('fs')
const port = 3000
app.get('/', (req, res) => {
res.send('WORKING!')
})
const httpsOptions = {
key: fs.readFileSync('./key.pem'),
cert: fs.readFileSync('./cert.pem')
}
const server = https.createServer(httpsOptions, app).listen(port, () => {
console.log('server running at ' + port)
})
- Open
https://localhost:3000
in Google Chrome and you'll see that it's not secure. Yet! - In Developer Tools > Security > View Certificate: Drag image to your desktop and double click it.
- Click 'Add'
- Find it in Keychain Access and double click it
- Expand 'Trust' and change 'When using this certificate' to 'Always trust'.
- You may be prompted to authenticate.
- Restart your server.
- Refresh your browser.
- Enjoy! :)
Solution 3
You can try openSSL to generate certificates. Take a look at this.
You are going to need a .key and .crt file to add HTTPS to node JS express server. Once you generate this, use this code to add HTTPS to server.
var https = require('https');
var fs = require('fs');
var express = require('express');
var options = {
key: fs.readFileSync('/etc/apache2/ssl/server.key'),
cert: fs.readFileSync('/etc/apache2/ssl/server.crt'),
requestCert: false,
rejectUnauthorized: false
};
var app = express();
var server = https.createServer(options, app).listen(3000, function(){
console.log("server started at port 3000");
});
This is working fine in my local machine as well as the server where I have deployed this. The one I have in server was bought from goDaddy but localhost had a self signed certificate.
However, every browser threw an error saying connection is not trusted, do you want to continue. After I click continue, it worked fine.
If anyone has ever bypassed this error with self signed certificate, please enlighten.
Solution 4
Mkcert from @FiloSottile makes this process infinitely simpler:
- Install mkcert, there are instructions for macOS/Windows/Linux
-
mkcert -install
to create a local CA -
mkcert localhost 127.0.0.1 ::1
to create a trusted cert for localhost in the current directory - You're using node (which doesn't use the system root store), so you need to specify the CA explicitly in an environment variable, e.g:
export NODE_EXTRA_CA_CERTS="$(mkcert -CAROOT)/rootCA.pem"
- Finally run your express server using the setup described in various other answers (e.g. below)
- boom. localhost's swimming in green.
Basic node setup:
const https = require('https');
const fs = require('fs');
const express = require('express');
const app = express();
const server = https.createServer({
key: fs.readFileSync('/XXX/localhost+2-key.pem'), // where's me key?
cert: fs.readFileSync('/XXX/localhost+2.pem'), // where's me cert?
requestCert: false,
rejectUnauthorized: false,
}, app).listen(10443); // get creative
Solution 5
How to generate an SSL certificate for localhost: link
openssl genrsa -des3 -out server.key 1024
you need to enter a password here which you need to retype in the following steps
openssl req -new -key server.key -out server.csr
when asked "Common Name" type in: localhost
openssl x509 -req -days 1024 -in server.csr -signkey server.key -out server.crt
Related videos on Youtube
JasonS
I wrote (and am writing) a SaaS to help extract data from javascript websites: http://PhantomJsCloud.com, for screen-scraping too I guess!
Updated on March 16, 2022Comments
-
JasonS about 2 years
Trying to follow various instructions on creating a self-signed cert for use with localhost, Most of the instructions seem to be for IIS, but I'm trying to use Nodejs/Express. None of them work properly because while the cert gets installed, it is not trusted. here's what I've tried that fails:
- How can I create a self-signed cert for localhost?
- https://www.digitalocean.com/community/articles/how-to-create-a-ssl-certificate-on-nginx-for-ubuntu-12-04/
- http://blogs.developerforce.com/developer-relations/2011/05/generating-valid-self-signed-certificates.html
- http://www.robbagby.com/iis/self-signed-certificates-on-iis-7-the-easy-way-and-the-most-effective-way/
Can someone offer a workflow that can do this? I can get a cert installed, but I can't get the cert to be trusted in either chrome (v32) or IE (v10).
EDIT: it was suggested in comments that the problem is no trusted cert-root. I installed the cert via IE but it's still not being trusted.
-
Admin over 10 yearsNone of the self signed certificates can be made trusted for web browsers. They are not signed by trusted signing authorities.
-
JasonS over 10 yearsthat's not true: you can install a root certificate to get your self-signed cert trusted. however I can't seem to do this properly. I read that you can install the cert chain in IE (not in chrome), so I tried that but it's still not being recognized. I don't know if it's because localhost is special or if the self-signed cert is just not correct.
-
JasonS almost 8 yearsI never got a self-signed cert working with browsers like Chrome. Here is my workaround: I created a DNS entry for local.MYDOMAIN.com pointing to 127.0.0.1 (localhost) and then just use my production cert. This has the added benefit of making sure there are no problems with your production cert chain, etc.
-
JasonS over 10 yearsYour certificate is still not trusted, so you have the same problem I'm describing. I need it to be trusted to test/debug a webservice properly.
-
Admin over 10 yearsSo you want this certificate to be trusted only in your local machine and not in the network?
-
JasonS over 10 yearsyeah, my dev environment is running on a single machine, and of course the "localhost" domain is only available locally :)
-
JasonS about 10 yearsHi Troy, thanks for sharing this. Someone else will have to comment on if this works or not. My workaround: I ended up adding dev.phantomjscloud.com to my hosts file, and then using my production cert. That is only useful if you want your production keys available on your dev box though, so I think your solution could still be valid, if someone else can please verify
-
TroyWorks about 10 yearsIt works for me and my team, in a combination of ways, secure local to local server to secure local to production server.
-
Binvention over 8 yearsdoes it still give the warning if you add the certificate to the browsers certificate list?
-
steampowered almost 8 yearsthe link at the top of the answer recomends 1024 bit 3DES encryption, which is way outdated. Better to use
openssl genrsa -out key.pem 2048
for a better key. -
2-bits over 7 yearsHe mentions IE, which means he is using Windows.
-
Diego Mello over 7 yearsYour certificate is still not trusted.
-
e_m0ney about 7 yearsAs far as getting a certificate goes - this is probably better than using some untrusted self signed cert (and equally as free) letsencrypt.org
-
Jason Goemaat about 7 yearsFor Windows, the git bash console works great using openssl commands from here. Just have to install the root certificate and you can create multiple site-specific certificates signed by it if you want.
-
Laurent Debricon over 6 yearsThen, in Chrome, go to chrome://flags and activate "Allow invalid certificates for resources loaded from localhost."
-
Jose A over 6 yearsBeautiful! This worked! I'd like to addition: Install OpenSSL from here: indy.fulgan.com/SSL/?C=M;O=A. Get the .cnf file from here: and then, configure it from here: gist.githubusercontent.com/pandurang90/dbe6a67339747ef5bacf/raw/… and configure openSSL from here: stackoverflow.com/questions/7360602/…
-
Jose A over 6 yearsI'd like to add that for Chrome 58+, you're going to receive an error "Subject Alternative Name missing".stackoverflow.com/a/42917227/1057052. Check the answers below for more help: stackoverflow.com/a/43666288/1057052, stackoverflow.com/a/44398368/1057052
-
AIon over 6 years
Drag image to your desktop and double click it
-> i can't drag anything to my desktop, is not draggable.. Whatimage
are you talking about ore exactly? -
Jos over 6 yearsThis should not be the accepted answer (yet). Note that some things require a green bar. E.g. if your website is also a progressive web ap (pwa), TLS is mandatory. For chrome 58+ to trust the certificate properly, you also need to become/create a CA (Certificate Authority). I found this resource quite usefull: ram.k0a1a.net/self-signed_https_cert_after_chrome_58
-
Michael Litvin over 6 yearsTo overcome "Subject Alternative Name missing" in Chrome, you could do
openssl req -newkey rsa:2048 -x509 -nodes -keyout keytmp.pem -new -out cert.pem -subj /CN=localhost -reqexts SAN -extensions SAN -config <(cat /System/Library/OpenSSL/openssl.cnf <(printf '[SAN]\nsubjectAltName=DNS:localhost')) -sha256 -days 3650
instead of the first line you suggested. And also this one will ask less questions in the process... -
Michael Litvin over 6 years@AIon, this is only for MacOS, on Windows it's probably much more complicated ;)
-
Belfield almost 6 yearsAmazing, thanks!!! You'll also need to add to the
httpsOptions
passphrase: 'XXXX'
-
Salyangoz over 5 yearsThis is the solution ive scoured the internet for over the past 2 hours. For anyone in ubuntu move the
cp server.crt /usr/local/share/ca-certificates/.
and runsudo update-ca-certificates
Then localhost https requests work under NodeJS 8+. Id also increase1024 to 2048
-
co.zohar over 5 yearsHi, when I finish all the steps I open
https://localhost:3000
and Chrome is stuck on loading. Anyone can tell what might be the reason? -
AIon over 5 years@co.zohar any message in the console? Press
crl+shift+i
orF12
to open the console. -
roskelld over 5 yearsIf you're doing this for an address on a network I found that setting up the certificate DNS to a hostname such as:
DNS.1 = server.local
Then on the connecting machine update the HOSTS file to point the server IP address to the hostname, for example:192.168.0.50 server.local
This will allow the certificate and the address to match up and validate the certificate. -
co.zohar over 5 years@AIon the console doesn't show anything. The page just shows: "Waiting for localhost...". Did you configure anything in the hosts file?
-
AIon over 5 years@co.zohar "Waiting for localhost..." indeed seems like an DNS resolution problem. I have an uncomented line in the hosts file:
127.0.0.1 localhost #transitCalculator
Not sure who put it here.#
means a commented line. The line i have typed here is uncomented. Please check you have aprox the same configuration there. -
co.zohar over 5 years@AIon Hi, I didn't have to have any row in the hosts file. Your initial solution worked perfectly. I didn't include the "app.get('/') and that's why it was waiting for localhost forever. Thank you
-
som over 5 yearsthe express code above works, utilising github.com/FiloSottile/mkcert (instead of openSSL) to create a local CA / trusted cert. Green bars all the way.
-
markreyes about 5 yearsI tried this exact exercise on Windows 10 OS and it worked. Thanks!
-
TKoL about 5 years@Alon it's unclear which of the fields in req.cnf need to be changed
-
TKoL about 5 years@Alon nevermind I think I got it. But what if we want it, instead of being localhost, to be an ip on the network? For example if I was running my node server on 192.168.1.10 and wanted other computers on the network to access it via https, how could i change your advice and have it still work?
-
TKoL about 5 yearsI found a semi-answer to my own question: if you change CN and DNS.1 to something like "local.com" for example, and in each computer that needs access to the server, change the etc/hosts file to point local.com to the ip of the server, this works.
-
zaheer almost 5 yearsWorks greatly! With this approach we don't need to register our self-signed certificate, as a CA trusted Certificate Authority, in the chrome/windows certificates store. As mentioned in other answers.
-
clusterBuddy about 4 yearsYou just got the same http page but only the UI showing https, this is not correct, unsecure and still not working, can't understand why so many upvotes from people not checking thoroughly and (I guess) forget to remove their upvote only so people wont get confused thinking this is a viable answer,
-
rx2347 almost 4 yearsthis only works for safari and chrome, firefox still won't play.
-
Hermenpreet Singh almost 4 yearsStep 2 is creating issue in window. 14148:error:0D07A097:asn1 encoding routines:ASN1_mbstring_ncopy:string too long:.\crypto\asn1\a_mbstr.c:158:maxsize=2
-
AIon almost 4 years@Hermenpreet Singh not sure what you mean. step 2 is only about creating that file and pasting that content inside it. Is not about validating that file content. But check this for what looks like a simmilar issue: github.com/certbot/certbot/issues/1915
-
sme over 3 years@HermenpreetSingh Its a problem with the country initials, you probably just didn't change the line in the req.cnf
C = Country initials like US, RO, GE
, it should just be something likeC = US
-
Ibra about 2 yearsCan I run this on pipelines ? here is a reference for my question stackoverflow.com/questions/71850480/…
-
som about 2 years@Ibra there seems to be some discussion around pipelines usage on the mkcert github repo so assume it's possible .. but keep in mind mkcert isn't intended for production use
-
Ren almost 2 yearsfor anyone looking to what cryptic drag and drop means find an answer here stackoverflow.com/questions/25940396/…