Node.js

create a trusted self-signed SSL cert for localhost for use with ExpressNode

27 September 2026 · 8 min read

create a trusted self-signed SSL cert for localhost for use with ExpressNode

Developing modern web applications often requires features that are exclusively available over a secure connection, even during local development. If you’ve ever found yourself facing browser warnings like “Your connection is not private” or struggling to implement APIs such as Service Workers, Geolocation, or WebAuthn on http://localhost, you understand the frustration. The solution lies in setting up HTTPS, and for local development, the most practical approach is to create a trusted self-signed SSL cert for localhost. This allows your browser to trust your local environment, mimicking production conditions and unlocking critical features without the hassle of untrusted connection warnings, streamlining your development workflow significantly.

Why You Need HTTPS on Localhost for Development

In today’s web landscape, security is paramount, and browsers are increasingly enforcing it. Many modern browser features and APIs are designed with a “secure contexts only” policy, meaning they will only function when served over HTTPS. This isn’t just a recommendation; it’s a fundamental requirement for powerful features that could potentially expose user data or system resources if not properly secured. For instance, technologies like Web Push Notifications, WebRTC, and Progressive Web App (PWA) capabilities, which rely heavily on Service Workers, simply won’t work on an insecure HTTP connection.

Beyond API access, developing with HTTPS on localhost provides a more accurate representation of your production environment. Discrepancies between development and production can lead to subtle bugs that are hard to diagnose. By ensuring your local setup uses HTTPS, you can catch these issues early, ensuring a smoother transition when deploying your Node.js or Express.js application. This practice is crucial for any developer aiming for robust, production-ready code. It also helps in debugging mixed-content warnings or insecure resource loading issues that might only appear when your application is served over a secure protocol.

Furthermore, many third-party integrations or authentication flows (like OAuth) often require a secure callback URL. Attempting to use http://localhost for these can lead to errors or security warnings from the external service. By configuring your local environment to use HTTPS with a trusted certificate, you avoid these roadblocks, making the integration process much smoother. This proactive approach to secure localhost development saves valuable time and prevents headaches down the line, ultimately enhancing your overall development efficiency and the reliability of your applications.

Understanding Self-Signed Certificates and Trust

A self-signed certificate is, at its core, an X.509 digital certificate that is signed by its own creator, rather than by a recognized Certificate Authority (CA). In the context of local development, this means you are effectively acting as your own CA for your development server. While this offers immense flexibility and cost-effectiveness for internal use, browsers do not inherently trust these certificates. When you visit a site using a self-signed certificate that isn’t explicitly trusted, your browser will display a security warning, indicating that the connection is not private and potentially unsafe. This is because the browser cannot verify the identity of the server through a chain of trust back to a pre-installed root CA.

To overcome this browser warning, the self-signed certificate needs to be explicitly trusted by your operating system’s or browser’s certificate store. By adding your self-signed certificate to this trust store, you tell your system that you vouch for the authenticity of any connection secured by that specific certificate. This effectively elevates your self-signed certificate to the status of a trusted root certificate, similar to how commercial CAs operate. For development purposes, this is perfectly acceptable and secure, as you control both ends of the connection and are aware of its origin.

The process of making a self-signed certificate trusted involves generating a root Certificate Authority (CA) certificate, and then using this CA to sign your actual localhost certificate. This creates a mini “chain of trust” within your local system. When your browser encounters your localhost certificate, it will then trace its signature back to your locally installed root CA, find it in the trusted store, and consequently establish a secure connection without warnings. This method is the cornerstone for how to create a trusted self-signed SSL cert for localhost, enabling a seamless HTTPS development environment. According to the OpenSSL documentation, managing certificates involves understanding their hierarchy and trust chains.

Step-by-Step: Create a Trusted Self-Signed SSL Cert for Localhost

Creating a trusted self-signed SSL certificate for your localhost environment, especially for use with Node.js and Express, typically involves using OpenSSL. This powerful command-line tool allows you to generate both your root Certificate Authority (CA) and the specific certificate for your localhost domain. The key is to generate a CA that your operating system can trust, then use that CA to sign your actual server certificate. This process ensures that your browser will accept the certificate without displaying security warnings, providing a smooth HTTPS development environment.

To create a trusted self-signed SSL cert for localhost, you’ll first generate a root CA certificate and key, then use that CA to sign a certificate for your local domain. This will prevent browser warnings and enable secure context features. The following steps outline the process:

  1. Generate a Root CA Key: Open your terminal and run openssl genrsa -des3 -out rootCA.key 2048. This creates a private key for your root CA. You’ll be prompted for a passphrase; remember it.
  2. Generate a Root CA Certificate: Next, create the root CA certificate using openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 1024 -out rootCA.pem. Fill in the required information, paying close attention to the “Common Name” (e.g., “My Local Development CA”).
  3. Create a Key for Localhost: Generate a private key for your localhost server: openssl genrsa -out localhost.key 2048.
  4. Create a Certificate Signing Request (CSR) for Localhost: Now, create a CSR for your localhost certificate: openssl req -new -key localhost.key -out localhost.csr. For the “Common Name,” enter localhost.
  5. Create a Configuration File (localhost.ext): This file is crucial for specifying Subject Alternative Names (SANs), which modern browsers require. Create a file named localhost.ext with the following content: ``` authorityKeyIdentifier=keyid,issuer basicConstraints=CA:FALSE keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment subjectAltName = @alt_names [alt_names] DNS.1 = localhost IP.1 = 127.0.0.1
  6. Sign the Localhost Certificate with Your Root CA: Finally, sign your localhost certificate using your newly created root CA: openssl x509 -req -in localhost.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out localhost.crt -days 500 -sha256 -extfile localhost.ext. This generates localhost.crt, your actual server certificate.
  7. Trust the Root CA: The final and most critical step is to trust your rootCA.pem file on your operating system.
    • macOS: Open “Keychain Access,” go to “System” or “Login” keychains, then “Certificates.” Drag rootCA.pem into this section. Double-click the imported certificate, expand “Trust,” and set “When using this certificate Question & Answer :
      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:

      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.

      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. enter image description here

      Step 7. go to Details panel, click Copy File, then when the Certificate Export Wizard appears, click Next as below:

      go to details - copy file - next on export wizard

      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.

      choose manage certificates

      Step 10. Go to Trusted Root Certification Authorities panel, and click import.

      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.

      confirm security exception

      Step 12. close everything, and restart chrome. Then, when going to https://localhost:3000 you should see: gotta love the green