Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
How to create an HTTPS certificate for localhost domains

How to create an HTTPS certificate for localhost domains

This focuses on generating the certificates for loading local virtual hosts hosted on your computer, for development only.

Do not use self-signed certificates in production ! For online certificates, use Let's Encrypt instead (tutorial).

Certificate authority (CA)

Generate RootCA.pem, RootCA.key & RootCA.crt:

openssl req -x509 -nodes -new -sha256 -days 1024 -newkey rsa:2048 -keyout RootCA.key -out RootCA.pem -subj "/C=US/CN=Example-Root-CA"
openssl x509 -outform pem -in RootCA.pem -out RootCA.crt

Note that Example-Root-CA is an example, you can customize the name.

Domain name certificate

Let's say you have two domains fake1.local and fake2.local that are hosted on your local machine for development (using the hosts file to point them to 127.0.0.1).

First, create a file domains.ext that lists all your local domains:

authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names
[alt_names]
DNS.1 = localhost
DNS.2 = fake1.local
DNS.3 = fake2.local

Generate localhost.key, localhost.csr, and localhost.crt:

openssl req -new -nodes -newkey rsa:2048 -keyout localhost.key -out localhost.csr -subj "/C=US/ST=YourState/L=YourCity/O=Example-Certificates/CN=localhost.local"
openssl x509 -req -sha256 -days 1024 -in localhost.csr -CA RootCA.pem -CAkey RootCA.key -CAcreateserial -extfile domains.ext -out localhost.crt

Note that the country / state / city / name in the first command can be customized.

You can now configure your webserver, for example with Apache:

SSLEngine on
SSLCertificateFile "C:/example/localhost.crt"
SSLCertificateKeyFile "C:/example/localhost.key"

Trust the local CA

At this point, the site would load with a warning about self-signed certificates. In order to get a green lock, your new local CA has to be added to the trusted Root Certificate Authorities.

Windows 10: Chrome, IE11 & Edge

Windows 10 recognizes .crt files, so you can right-click on RootCA.crt > Install to open the import dialog.

Make sure to select "Trusted Root Certification Authorities" and confirm.

You should now get a green lock in Chrome, IE11 and Edge.

Windows 10: Firefox

There are two ways to get the CA trusted in Firefox.

The simplest is to make Firefox use the Windows trusted Root CAs by going to about:config, and setting security.enterprise_roots.enabled to true.

The other way is to import the certificate by going to about:preferences#privacy > Certificats > Import > RootCA.pem > Confirm for websites.

@ctcherry

This comment has been minimized.

Copy link

@ctcherry ctcherry commented Jun 20, 2018

I made a tool to help with some of this locally on OSX, it has some issues I would like to fix eventually such as needing to run with sudo, but its been working great for me so far. https://github.com/ctcherry/tlself

@AlexeyKot

This comment has been minimized.

Copy link

@AlexeyKot AlexeyKot commented Jan 31, 2019

Thank you so much! I finally made it work only after your tutorial.

@Dibbyo456

This comment has been minimized.

Copy link

@Dibbyo456 Dibbyo456 commented May 25, 2019

I've tried many tutorials none of them worked but this one finally did. 😍
Thank you so much. 🙏

@k-gun

This comment has been minimized.

Copy link

@k-gun k-gun commented Jun 21, 2019

On Chrome, importing via "Authorities" tab solving probs.
Thank you.

@temuri416

This comment has been minimized.

Copy link

@temuri416 temuri416 commented Jul 8, 2019

How do you install these certs for nginx? Thanks!

@k-gun

This comment has been minimized.

Copy link

@k-gun k-gun commented Jul 10, 2019

@temuri416, here is my local config stuff (for nginx version: 1.16.0);

# file: /etc/nginx/sites-available/default.conf
server {
  listen 80;
  listen 443 default ssl;

  #ssl on; ###[warn] the "ssl" directive is deprecated, use the "listen ... ssl" directive instead in ...
  ssl_certificate      /home/kerem/.ssl/localhost.crt;
  ssl_certificate_key  /home/kerem/.ssl/localhost.key;
  ...


# file: /etc/nginx/sites-available/mysite.local.conf
server {
  listen 80;
  server_name mysite.local;
  return 301 https://mysite.local$request_uri;
}
server {
  listen 443 ssl http2;
  
  ###[warn] the "ssl" directive is deprecated, use the "listen ... ssl" directive instead in ...
  #ssl on;
  ssl_certificate      /home/kerem/.ssl/localhost.crt;
  ssl_certificate_key  /home/kerem/.ssl/localhost.key;
  ...

Remember to check after saving config files with nginx -t.

@temuri416

This comment has been minimized.

Copy link

@temuri416 temuri416 commented Jul 11, 2019

@k-gun

I tried that. I cannot make it work following the steps. When did it work for you last?

@monoteos

This comment has been minimized.

Copy link

@monoteos monoteos commented Aug 8, 2019

Best tutorial on internet on how to make it work on localhost, thanks!

@Shaftoe62

This comment has been minimized.

Copy link

@Shaftoe62 Shaftoe62 commented Aug 9, 2019

With this I FINALLY got it working! Thanks a 1.000.000

@sushmitpalrishi

This comment has been minimized.

Copy link

@sushmitpalrishi sushmitpalrishi commented Aug 18, 2019

out of all the tutorials only this worked till now, after Facebook's march update. Thanks a lot for this

@alecos71

This comment has been minimized.

Copy link

@alecos71 alecos71 commented Oct 8, 2019

The only working guide!!! Fantastic! I have all browsers with green padlock, thanks!

@gallam600

This comment has been minimized.

Copy link

@gallam600 gallam600 commented Oct 29, 2019

Simply brilliant. I tried a very large number of alternatives, none of which worked.

Thanks.

@rainhard

This comment has been minimized.

Copy link

@rainhard rainhard commented Nov 15, 2019

Excellent! this works finally! thanks!

@tekbyts

This comment has been minimized.

Copy link

@tekbyts tekbyts commented Nov 20, 2019

performed steps until Generate localhost.key, localhost.csr, and localhost.crt:

Then performed steps for Trust the local CA.

When i browse the website, i still get an exclamation (!) icon on the address bar.

I am using windows 10, chrome & IE edge. Running asp.net core on IISExpress. Is there any configuration that i need to do for IISExpress in order for the certificate to work?

Moreover, while install the .crt file, i don't see this option: Trusted Root Certification Authorities

Am i missing something? why it is not working for me?

@dol

This comment has been minimized.

Copy link

@dol dol commented Nov 22, 2019

Need an easy solution: https://github.com/FiloSottile/mkcert

@tschombe

This comment has been minimized.

Copy link

@tschombe tschombe commented Nov 25, 2019

Hi,

thanks for your tutorial, but it only worked for me if i
created .pfx format, otherwise the certificate could not be registered with a
custom webserver using
netsh http add sslcert

@pcl392578

This comment has been minimized.

Copy link

@pcl392578 pcl392578 commented Dec 5, 2019

i want to create ssl certificate for local host 9000 port please advise all commands and process thanks its very critical

@alecos71

This comment has been minimized.

Copy link

@alecos71 alecos71 commented Dec 8, 2019

@pcl392578: i want to create ssl certificate for local host 9000 port please advise all commands and process thanks its very critical

I think that you should look into your httpd.conf and change your VirtualHost config from port 443 to 9000 like below:

Listen 80
Listen 9000

No SSL for port 80

<VirtualHost localhost:80>
  ServerName localhost:80
  ServerAlias localhost
  ErrorLog "${SRVROOT}/logs/localhost-error.log"
  TransferLog "${SRVROOT}/logs/localhost-access.log"
  DocumentRoot "D:/Web/www"
    <Directory "D:/Web/www">
      Require all granted
      Options Indexes FollowSymLinks Includes ExecCGI
      AcceptPathInfo Off
      AllowOverride All
    </Directory>
</VirtualHost>

SSL for port 9000

<VirtualHost localhost:9000>
  ServerName localhost:9000
  ServerAlias localhost
  SSLEngine on
  SSLCertificateFile "${SRVROOT}/key/localhost.crt"
  SSLCertificateKeyFile "${SRVROOT}/key/localhost.key"
  <FilesMatch "\.(cgi|shtml|phtml|php)$">
    SSLOptions +StdEnvVars
  </FilesMatch>
  ErrorLog "${SRVROOT}/logs/localhost-error.log"
  TransferLog "${SRVROOT}/logs/localhost-access.log"
  CustomLog "${SRVROOT}/logs/localhost-ssl-request.log" \
  "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"
  DocumentRoot "D:/Web/www"
    <Directory "D:/Web/www">
      SSLOptions +StdEnvVars
      Require all granted
      Options Indexes FollowSymLinks Includes ExecCGI
      AcceptPathInfo Off
      AllowOverride All
    </Directory>
    BrowserMatch "MSIE [2-5]" \
    nokeepalive ssl-unclean-shutdown \
    downgrade-1.0 force-response-1.0
</VirtualHost>

@majidlahmidi

This comment has been minimized.

Copy link

@majidlahmidi majidlahmidi commented Dec 13, 2019

hello,
Perfect, it works !
Thks

@CharlesOkwuagwu

This comment has been minimized.

Copy link

@CharlesOkwuagwu CharlesOkwuagwu commented Jan 17, 2020

Note to future self ... close browser and re-open, to see changes after updating localhost certificate

@superfein

This comment has been minimized.

Copy link

@superfein superfein commented Feb 8, 2020

Tried running this in Git Bash in Windows 10. Got this error:

openssl req -x509 -nodes -new -sha256 -days 1024 -newkey rsa:2048 -keyout RootCA.key -out RootCA.pem -subj "/C=US/CN=Superfein-Root-CA"
Generating a RSA private key
.............................................................................................................+++++
.........................+++++
writing new private key to 'RootCA.key'

name is expected to be in the format /type0=value0/type1=value1/type2=... where characters may be escaped by . This name is not in that format: 'C:/Program Files/Git/C=US/CN=Superfein-Root-CA'
problems making Certificate Request

I have Open SSL v1.1.0L 64bit installed. Any ideas why this is giving this error message?

@CharlesOkwuagwu

This comment has been minimized.

Copy link

@CharlesOkwuagwu CharlesOkwuagwu commented Feb 9, 2020

@superfein maybe 'C:/Program Files/Git/C=US/CN=Superfein-Root-CA' should read '/C=US/CN=Superfein-Root-CA'

@alecos71

This comment has been minimized.

Copy link

@alecos71 alecos71 commented Feb 9, 2020

I created 3 .bat files to do the job inside the folder:

C:\Program Files\OpenSSL-Win64\bin

my 1° .bat file is RootCA.bat
my 2° .bat file is localhost.bat
my 3° .bat file is localhost-test.bat

Running these files with the command openssl did the trick...

https://slproweb.com/download/Win64OpenSSL-1_1_1d.exe

You don't need Git but openssl which is located in C:\Program Files\OpenSSL-Win64\bin...

Your RootCA.bat file should be like this:

openssl req -x509 -nodes -new -sha256 -days 1024 -newkey rsa:2048 -keyout RootCA.key -out RootCA.pem -subj "/C=US/CN=Example-Root-CA"
openssl x509 -outform pem -in RootCA.pem -out RootCA.crt

Hope this helps.

@bayupermadi

This comment has been minimized.

Copy link

@bayupermadi bayupermadi commented Feb 13, 2020

@k-gun

I tried that. I cannot make it work following the steps. When did it work for you last?

I just tried that steps and its still work

@nsrau

This comment has been minimized.

Copy link

@nsrau nsrau commented Mar 21, 2020

to install certificates on ubuntu
sudo update-ca-certificates

@cyasam

This comment has been minimized.

Copy link

@cyasam cyasam commented May 10, 2020

Your tutorial is best and easy to follow. Thank you so much.

@chrisk314

This comment has been minimized.

Copy link

@chrisk314 chrisk314 commented May 25, 2020

Thanks! This works like a charm adding the generated RootCA.crt file to Chrome in the Authorities tab at chrome://settings/certificates.

@johnpbaldwin

This comment has been minimized.

Copy link

@johnpbaldwin johnpbaldwin commented Sep 3, 2020

This was extremely helpful. Thanks. I created a custom CA cert, trusted that on my Mac (using Keychain access), and generated a new cert with all the SANs, and now Safari can visit my local dev sites without balking (or flat-out refusing).

@ErikVerheul

This comment has been minimized.

Copy link

@ErikVerheul ErikVerheul commented Sep 7, 2020

Chrome requires that your domains are named in the SAN.
To check the generated certificate, test with:
openssl x509 -noout -text -in localhost.crt | grep DNS:
Your domains should be listed.

@stefan-reich

This comment has been minimized.

Copy link

@stefan-reich stefan-reich commented Oct 31, 2020

Why has it gotten so hard to simply run a https webserver on localhost? This used to work without certificates at all. I don't see the security problem eitehr.

@BraxtonI

This comment has been minimized.

Copy link

@BraxtonI BraxtonI commented Nov 27, 2020

I followed a few other tutorials which just gave me errors, and this one finally worked out, and I got my localhost certificate, but I did not have https on my localhost. I decided to delete everything I created and follow this tutorial start to finish again, and I'm getting the following error when I try to generate the localhost.key, etc:

problem creating object tsa_policy1=1.2.3.4.1
13632:error:08064066:object identifier routines:OBJ_create:oid exists:crypto\objects\obj_dat.c:698:
@matteogll

This comment has been minimized.

Copy link

@matteogll matteogll commented Nov 30, 2020

@superfein: it's an issue related to Git Bash on Windows.
Try with adding MSYS_NO_PATHCONV=1 in order to disable PATH conversion:
MSYS_NO_PATHCONV=1 openssl req -x509 -nodes -new -sha256 -days 1024 -newkey rsa:2048 -keyout RootCA.key -out RootCA.pem -subj "/C=US/CN=Example-Root-CA" Generating a RSA private key

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.