Self-Signed Certificate Generator
Make a certificate and key for local HTTPS and tests. For testing only: nobody trusts it until you install it.
Runs in your browser. Your input is not sent anywhere.
What this tool does
A TLS certificate binds a public key to names such as localhost or dev.example.test. Normally a certificate authority signs it after checking that you control the names. A self-signed certificate is signed with its own key instead, so nothing vouches for it: browsers and other clients accept it only after you tell them to trust it.
That is exactly what you want for a development server, an internal test system or a test of TLS code. The tool creates a new key pair and a certificate in your browser with the Web Crypto API and gives you both as PEM text. The private key is never sent anywhere, and it is not kept after you leave the page.
Do not use a self-signed certificate for a public website. Visitors would see a warning that they cannot sensibly check, and teaching people to click through such warnings helps attackers. Public sites should use a certificate from a public certificate authority; several issue them free of charge.
How to use it
- Enter the common name, usually the main host name, for example localhost.
- Add more host names and IP addresses if the server is reached under several names, for example 127.0.0.1 and ::1 for local tests.
- Choose the key type and how many days the certificate is valid.
- Select “Generate certificate”. Creating an RSA key can take a moment.
- Download the certificate and the private key, and configure your server with both files.
- To avoid the browser warning on your own machine, add the certificate to the trust store of your operating system or browser. Remove it again when you no longer need it.
A minimal HTTPS server in Node.js that uses the two downloaded files:
import { readFileSync } from 'node:fs';
import { createServer } from 'node:https';
createServer(
{
key: readFileSync('private-key.pem'),
cert: readFileSync('certificate.pem'),
},
(request, response) => response.end('hello over TLS\n'),
).listen(8443);How the certificate is made
Your browser generates the key pair with crypto.subtle.generateKey: an ECDSA key on the curve P-256 or an RSA key with a 2048-bit modulus and the public exponent 65537. The tool then assembles an X.509 version 3 certificate in the DER encoding that RFC 5280 describes, lets Web Crypto sign it with the private key (ECDSA with SHA-256 or RSASSA-PKCS1-v1_5 with SHA-256), and writes the certificate and the PKCS #8 private key as PEM text.
Issuer and subject are the same name, CN= followed by your common name. The serial number is 16 random bytes. Validity starts one minute before you generate the certificate, so a client whose clock is slightly behind still accepts it, and lasts exactly the number of days you entered: the last second of validity is one second before that many days have passed, because RFC 5280 counts both ends.
The certificate carries the extensions that browsers and operating systems expect of a server certificate: basic constraints saying it is not a certificate authority, key usage for digital signatures (and key encipherment for RSA), extended key usage for TLS servers and clients, and the subject alternative names. Browsers read host names only from the subject alternative names, not from the common name, so a common name that is a host name or an IP address is added to that list automatically.
Worked example
Common name localhost, more names 127.0.0.1 and ::1, ECDSA P-256, 365 days. OpenSSL shows the result like this (serial number, dates and keys differ every time):
Version: 3 (0x2)
Signature Algorithm: ecdsa-with-SHA256
Issuer: CN=localhost
Subject: CN=localhost
Public Key Algorithm: id-ecPublicKey
ASN1 OID: prime256v1
X509v3 Basic Constraints: critical
CA:FALSE
X509v3 Key Usage: critical
Digital Signature
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
X509v3 Subject Alternative Name:
DNS:localhost, IP Address:127.0.0.1, IP Address:0:0:0:0:0:0:0:1The same certificate is accepted for https://localhost:8443, https://127.0.0.1:8443 and https://[::1]:8443 once it is trusted, and for no other name.
Reference: what goes into the certificate
| Part | Value | Why |
|---|---|---|
| Version | 3 | Needed for extensions. |
| Serial number | 16 bytes, 126 of their bits random | Must be unique per issuer; random values avoid collisions. |
| Signature | ECDSA or RSA with SHA-256 | SHA-1 signatures are no longer trusted. |
| Issuer, subject | CN=your common name | Identical, because the certificate signs itself. |
| Validity | Now minus one minute, plus the number of days | Apple platforms reject more than 825 days. |
| Basic constraints | CA:FALSE, critical | The certificate cannot sign other certificates. |
| Key usage | Digital signature (RSA: also key encipherment), critical | Limits what the key may do: sign, and for RSA also encrypt session keys. |
| Extended key usage | Server and client authentication | Limits use to TLS servers and clients; Apple platforms require the server purpose. |
| Subject alternative names | DNS names and IP addresses | The only place browsers look for host names. |
| Key type | Certificate size | Notes |
|---|---|---|
| ECDSA P-256 | About 400 bytes (600 as PEM) | Fast and small; supported by practically all current TLS software. |
| RSA 2048 | About 800 bytes (1,150 as PEM) | For old clients and devices that do not support ECDSA. |
Common mistakes
- Relying on the common name. Browsers ignore it for host name checks; a certificate without subject alternative names is rejected. The tool warns when the list is empty.
- Choosing a very long validity. Apple requires 825 days or fewer for every TLS server certificate issued after July 1, 2019, and in practice this includes self-signed certificates that you trust.
- Expecting a wildcard to cover the parent name. *.example.test matches api.example.test but not example.test itself and not a.b.example.test; add the parent name separately.
- Committing the private key. Keep it out of version control, or anyone with access to the repository can pose as your server.
- Leaving a test certificate trusted forever. Remove it from the trust store when the project ends.
If you often need trusted certificates on your own machines, a small local certificate authority is more convenient than trusting many self-signed certificates one by one. Tools such as mkcert install such an authority and issue certificates from it.
Sources
Frequently asked questions
- Is the private key sent to a server?
- No. The key pair is generated by your browser, the certificate is signed in the page, and nothing is transmitted. The key exists in the page, in the files you download and on your clipboard if you copy it; the page forgets it when you close or reload it. This page shows no ads, so no third-party script runs next to the key.
- Why does my browser still show a warning?
- Nobody vouches for a self-signed certificate, so browsers warn until you add it to a trust store. Even then the address must match one of the subject alternative names, and the certificate must be within its validity period.
- Can I use it on a public website?
- No. Visitors cannot tell your self-signed certificate from an attacker’s. Use a certificate from a public certificate authority for anything that other people visit.
- Is the private key encrypted?
- No. It is an unencrypted PKCS #8 key, which is what development servers usually read. Protect the file like a password, or encrypt it with a tool such as OpenSSL if you store it.
- Should I choose ECDSA or RSA?
- Choose ECDSA P-256 unless something you test only supports RSA. Both are signed with SHA-256 and accepted by current browsers.
Last updated: September 29, 2026