Self-Signed SSL Certificates: When to Use Them
What self-signed SSL certificates are, when they're appropriate, and when they'll cause problems. Development, testing, and internal use cases.
A self-signed SSL certificate is one you create and sign yourself, without a Certificate Authority involved. There's no third-party verification. No chain of trust. Just you saying "this certificate is valid" and hoping the other end agrees. In the right context, that's perfectly fine. In the wrong context, it's a security warning that drives away every visitor.
Here's when self-signed certificates make sense, when they don't, and how to create one when you need it.
What "Self-Signed" Actually Means
Normal SSL certificates work through a chain of trust. A Certificate Authority (CA) like Let's Encrypt or DigiCert verifies that you control a domain, then issues a certificate signed with their trusted key. Browsers and operating systems ship with a list of trusted CAs, so when they see a certificate signed by one of these authorities, they trust it automatically.
A self-signed certificate skips all of that. You generate a key pair, create a certificate, and sign it with your own key. You are your own CA. The problem is that nobody else's browser or system knows to trust your CA, so they'll show a security warning.
The trust issue
Self-signed certificates provide the same encryption as CA-signed certificates. The encryption is identical. The difference is trust -- there's no independent third party confirming the server is who it claims to be.
When Self-Signed Certificates Are Appropriate
Local Development
This is the most common and most legitimate use case. You're building a web application on your laptop and need HTTPS to work. Maybe your app uses secure cookies, service workers, or APIs that require a secure context.
A self-signed certificate (or a tool like mkcert that creates locally-trusted certificates) solves this perfectly. The only user is you, on your own machine.
Internal Tools and Services
If you have internal applications that are only accessible within your corporate network or VPN, self-signed certificates can work. You control the client machines and can install your custom CA certificate on all of them.
Common examples:
- Internal dashboards and admin panels
- Development and staging environments
- CI/CD tools (Jenkins, GitLab runners)
- Internal APIs that only your services consume
Testing Environments
Automated tests that need HTTPS connections often use self-signed certificates. The test framework trusts the certificate explicitly, so there's no browser warning to deal with.
IoT and Embedded Devices
Devices on a private network (security cameras, industrial controllers, smart home hubs) sometimes use self-signed certificates for their management interfaces. The device communicates only with known clients, and the overhead of a CA-signed certificate isn't justified.
When Self-Signed Certificates Are a Problem
Public-Facing Websites
Never use a self-signed certificate for a website that anyone outside your organization visits. Every browser will show a full-page security warning. In Chrome, users see "Your connection is not private" with NET::ERR_CERT_AUTHORITY_INVALID. Most visitors will leave immediately.
Even if you add instructions to "click Advanced and proceed anyway," you're training users to ignore security warnings. That's worse than the warning itself.
Public APIs
If other companies or developers consume your API, a self-signed certificate means every client needs custom configuration to trust your certificate. Most HTTP libraries reject self-signed certificates by default. You'll spend more time on support requests than the certificate costs.
E-commerce or Any Site Handling Sensitive Data
Beyond the browser warning, self-signed certificates provide no identity verification. A visitor has no assurance they're actually talking to your server and not an attacker. For any site handling passwords, payment information, or personal data, this is unacceptable.
Monitor all your certificates -- even internal ones
Self-signed certificates expire too. Get alerts before they do.
How to Create a Self-Signed Certificate
Using OpenSSL
The most common method. This creates a certificate valid for one year:
# Generate a private key and self-signed certificate in one command
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -sha256 -days 365 -nodes \
-subj "/C=US/ST=State/L=City/O=MyOrg/CN=localhost"
Breaking down the flags:
-x509: Create a self-signed certificate (not a CSR)-newkey rsa:4096: Generate a new 4096-bit RSA key-keyout key.pem: Save the private key here-out cert.pem: Save the certificate here-sha256: Use SHA-256 signing algorithm-days 365: Valid for one year-nodes: Don't encrypt the private key with a passphrase-subj: Set the certificate subject fields inline
To include Subject Alternative Names (required by modern browsers even for localhost):
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -sha256 -days 365 -nodes \
-subj "/CN=localhost" \
-addext "subjectAltName=DNS:localhost,IP:127.0.0.1"
Using mkcert (Recommended for Local Development)
mkcert is a tool that creates locally-trusted certificates. It installs a local CA in your system trust store, then uses that CA to sign certificates. Your browser trusts them without warnings -- no manual certificate installation needed.
# Install mkcert
brew install mkcert # macOS
choco install mkcert # Windows
# Or download from GitHub releases for Linux
# Install the local CA (one-time setup)
mkcert -install
# Create a certificate for localhost
mkcert localhost 127.0.0.1 ::1
This creates localhost+2.pem (certificate) and localhost+2-key.pem (key) that your browser will trust automatically. No security warnings, no manual trust steps.
mkcert is the modern answer
For local development, mkcert is almost always the right choice. It gives you the convenience of self-signed certificates with the trust of a CA-signed certificate, limited to your machine.
How to Trust a Self-Signed Certificate
If you need to use a self-signed certificate beyond mkcert (for internal services, for example), you'll need to install it in the trust store of each client machine.
macOS:
sudo security add-trusted-cert -d -r trustRoot \
-k /Library/Keychains/System.keychain cert.pem
Linux (Ubuntu/Debian):
sudo cp cert.pem /usr/local/share/ca-certificates/my-cert.crt
sudo update-ca-certificates
Windows:
Import-Certificate -FilePath cert.pem -CertStoreLocation Cert:\LocalMachine\Root
Node.js (for development/testing):
export NODE_EXTRA_CA_CERTS=/path/to/cert.pem
For internal services at scale, you're essentially running your own CA. At that point, consider using a proper internal CA tool like step-ca or HashiCorp Vault's PKI secrets engine instead of manually managing self-signed certificates.
Why Let's Encrypt Made Self-Signed Certificates Mostly Unnecessary
Before Let's Encrypt launched in 2015, SSL certificates cost money. The cheapest DV certificates were $10-50 per year. If you had a low-traffic internal tool or a side project, paying for a certificate felt wasteful. Self-signed certificates were the free alternative.
Let's Encrypt changed that equation entirely:
- Free certificates for any domain you control
- Automated issuance via ACME protocol
- 90-day validity with automated renewal
- Wildcard support for covering all subdomains
For any server accessible from the internet, there's no reason to use a self-signed certificate anymore. Let's Encrypt gives you a trusted certificate for free, and tools like Certbot automate the entire process.
Self-signed certificates still make sense for:
- Local development (where your machine isn't internet-accessible)
- Air-gapped or private networks
- Testing and CI environments
- Situations where DNS-based validation isn't possible
For everything else, get a real certificate. It's free.
Self-Signed Certificates Still Expire
One thing people forget: self-signed certificates have expiry dates too. That -days 365 flag in the OpenSSL command means you'll get a certificate error a year from now. And because self-signed certificates aren't tracked by any CA, there's no renewal reminder coming.
Internal tools running on self-signed certificates are some of the most common sources of surprise expiry. The certificate was created two years ago by someone who's since left the team. Nobody remembers it exists until the monitoring dashboard stops loading.
If you use self-signed certificates for internal services, add them to your certificate monitoring. They deserve the same attention as your production certificates.
Related Articles
Self-signed certificates are fine for development. For production, get a real cert -- it's free.
Never miss an SSL certificate expiry
Monitor your certificates and get alerts before they expire. Free for up to 3 certificates.