Guide to Create a Self Signed Certificate Openssl in 2026

Guide to Create a Self Signed Certificate Openssl in 2026

A service is ready to ship in development, the reverse proxy is listening on HTTPS, and the browser still throws a warning. API clients complain. Secure cookies don't behave the way they should. Internal callbacks fail because the certificate doesn't validate. That's the point where many developers search for how to create a self signed certificate with OpenSSL, copy a one-liner, and then find out that generating a certificate and generating a certificate that clients trust are two different jobs.

That distinction matters. A direct self-signed leaf certificate is fine for a solo laptop workflow. It's usually the wrong pattern for a shared development environment, a staging cluster, or any internal service that other machines need to trust without constant exception-clicking. The better pattern is a small internal CA, proper X.509 extensions, and leaf certificates that include SANs from the start. For a useful baseline on where self-signed certificates fit and where they don't, ARPHost's self-signed certificate overview is a solid companion read. Teams also dealing with broader hardening work usually benefit from keeping an eye on secure infrastructure guidance from Fivenines.

Table of Contents

Why Self-Signed Certificates Are Essential for Modern Development

Local development without HTTPS is getting less realistic. Browsers expect secure origins for more features, modern apps depend on cookies that behave differently under HTTPS, and internal APIs often need TLS long before anything reaches production. A plain http://localhost workflow still has its place, but it no longer reflects how many services behave in staging or in real user flows.

That's why teams keep returning to OpenSSL. It's still the tool most admins and DevOps engineers reach for when they need to create keys, CSRs, and certificates without adding another dependency chain. The question isn't whether a self-signed setup is useful. The question is which kind of self-signed setup fits the environment.

A direct self-signed leaf certificate is enough when one person wants a browser session to stop failing long enough to test a local service. A local CA is the right answer when multiple services, machines, containers, or teammates need predictable trust.

Practical rule: If users must click through browser warnings, the certificate workflow isn't finished.

Three situations come up constantly:

  • Single-machine testing: One developer needs HTTPS on a local endpoint right now.
  • Shared dev or staging: Several people and systems need the same internal trust model.
  • Internal production-like services: Reverse proxies, service meshes, and test environments need browser-compatible certificates that validate correctly.

The key difference is trust distribution. Generating a certificate is easy. Getting browsers, command-line tools, and applications to accept it consistently is where most guides stop too early.

The Quick One-Liner for Localhost Testing

For fast local testing, the one-liner still has value. OpenSSL commonly uses a command like openssl req -x509 -newkey rsa:4096 ... -days 365, which creates both the private key and the certificate in one step for quick local development, as shown in Joshua Tzucker's OpenSSL self-signed certificate notes.

The Quick One-Liner for Localhost Testing

A typical pattern looks like this:

openssl req -x509 -newkey rsa:4096 -keyout server.key -out server.crt -days 365 -sha256

That command is attractive for a reason. It collapses key generation and certificate creation into one step, avoids a separate CSR flow, and gets an HTTPS listener online quickly. For a developer trying to boot a local API or UI, that shortcut is often enough to move forward.

What this method does well

It's useful when the requirements are narrow.

  • Fast setup: One command creates the key and certificate together.
  • Good for throwaway environments: Labs, temporary containers, and isolated local runs don't need a full trust hierarchy.
  • Enough for manual acceptance: If the only client is the same machine and the warning can be tolerated, this is often fine.

That's why many engineers start here when they search for how to create a self signed certificate with OpenSSL.

Where the one-liner breaks down

The weaknesses show up as soon as the certificate has to behave like a real internal TLS asset.

  • Browsers won't trust it by default: The certificate signs itself, so there's no trusted root behind it.
  • Other machines can't validate it automatically: Every additional client becomes a manual trust exercise.
  • Shared environments become messy: Teams end up with multiple random self-signed leaf certs and no clear trust anchor.
  • Hostname validation often fails: A quick command is easy to generate incorrectly if the resulting certificate doesn't match the name clients use.

A certificate that exists isn't the same thing as a certificate that validates.

That's the practical dividing line. For a personal localhost session, a one-liner is fine. For anything meant to feel stable across browsers, proxies, internal DNS names, or team workflows, it becomes technical debt almost immediately.

A lot of OpenSSL frustration starts here. The command succeeds, the files exist, and the system still behaves as if TLS is broken. Usually, TLS isn't broken. The trust model is.

Building a Local Certificate Authority for Team Trust

A local CA fixes the biggest flaw in the one-liner approach. Instead of handing every service its own isolated self-signed certificate, the team creates one trusted root and uses it to sign service certificates. That gives browsers and clients a chain they can validate after the root certificate is installed once.

Building a Local Certificate Authority for Team Trust

In internal PKI, a common pattern is a long-lived root CA at 3650 days and shorter leaf certificates at 365 days, which creates a stable trust anchor while keeping server credential rotation manageable, as shown in Tencent Cloud's internal CA workflow.

That split is the right operational model for most internal environments. The root should be rare, protected, and boring. Leaf certificates should be replaceable.

Create the root key and certificate

A practical OpenSSL workflow for a CA begins with a root key and root certificate. One documented example uses:

openssl genrsa -out rootCA.key 4096
openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 1024 -out rootCA.crt

This gives the environment a private signing authority. The exact subject fields can be customized for the team, but the behavior matters more than the labels. The rootCA.key file is the master secret. It should never be treated like another deployment artifact.

Protect the CA like a control plane secret

A local CA is simple, but it changes the security model. Once clients trust rootCA.crt, anything signed by the matching private key can become trusted internally.

That means the basic rules need to be strict:

  • Store the CA private key offline when possible: It shouldn't live casually on the same host used for app development.
  • Restrict access hard: Only the small set of operators who issue certificates should touch it.
  • Separate roles if needed: Some teams keep a root CA mostly dormant and issue from a subordinate authority later.
  • Document trust distribution: Every client that trusts the CA should be known and intentional.

The CA private key is not just another key file. It's the root of the environment's trust policy.

Why this works better than a directly self-signed server cert

A directly self-signed leaf certificate asks every client to trust each service one by one. A CA-signed internal leaf certificate asks each client to trust the CA once. That difference is what makes internal PKI scale.

This model also fits how teams work. New staging services come and go. Load balancers change. Service names evolve. With a local CA in place, those changes don't force every user to re-approve every endpoint manually.

The result is less friction and fewer bad shortcuts, such as shipping one long-lived self-signed server certificate everywhere and hoping nobody notices.

Issuing Server Certificates with SAN for Browser Compatibility

Most TLS failures in internal environments come from one missing detail: Subject Alternative Name, or SAN. Modern clients don't rely on the Common Name alone for hostname validation. For modern TLS compatibility, SAN entries supplied through an OpenSSL extension file are mandatory, as described in Baeldung's OpenSSL SAN certificate guide.

Issuing Server Certificates with SAN for Browser Compatibility

A lot of teams think they need help with OpenSSL syntax. More often, they need help matching certificate contents to how clients validate names. Anyone handling dynamic internal HTTPS patterns may also find this Caddy on-demand TLS guide useful when comparing internal certificate issuance models.

Generate the server key and CSR

Use a separate private key and CSR for the service:

openssl genrsa -out mydomain.com.key 2048
openssl req -new -key mydomain.com.key -out mydomain.com.csr

This split matters because it keeps the service key independent from the CA key and gives the signing step a clean input. It also makes reissuance easier when names or extensions change.

Create an extension file that clients accept

The extension file is where the certificate becomes useful instead of merely valid. A minimal example looks like this:

basicConstraints=CA:FALSE
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names

[alt_names]
DNS.1 = app.internal
DNS.2 = staging.internal
IP.1 = 10.0.0.15

The exact names should match the hostnames and addresses clients use. If a browser reaches the service at one name and the certificate only contains another, hostname validation will fail even if the CA is trusted.

Key lines in that file matter for different reasons:

  • basicConstraints=CA:FALSE prevents the leaf certificate from being treated like a certificate authority.
  • keyUsage restricts the allowed cryptographic purpose.
  • extendedKeyUsage=serverAuth tells clients the certificate is intended for server authentication.
  • subjectAltName defines the DNS names or IP entries clients must match against.

Many broken internal certificates are missing one or more of those extensions. The files look fine in a directory listing. Browsers still reject them.

This walkthrough helps to visualize the full issuance path:

Sign the CSR with the local CA

Once the CSR and extension file are ready, sign the request with the CA:

openssl x509 -req -in domain.csr -CA rootCA.crt -CAkey rootCA.key -out domain.crt -days 365 -CAcreateserial -extfile domain.ext

That command is where the SANs and other extensions become part of the issued server certificate. Without the -extfile step, the result often looks fine at first glance and then fails in the browser.

Operational takeaway: If a certificate must work in a browser, reverse proxy, container, or API client, SANs are not optional.

A reliable check after issuance is to inspect the certificate and confirm the SAN extension is present and matches reality:

openssl x509 -in domain.crt -noout -text

The most common mistake isn't OpenSSL itself. It's issuing a technically formed certificate that doesn't describe the endpoint clients are connecting to.

Deployment and Trusting Your Local CA

Certificate files sitting in a working directory don't solve anything. They have to be deployed in the right place, referenced correctly by the server, and backed by a CA that clients trust. A complete workflow includes generating the CA, creating a server CSR, signing it with openssl x509 -req, and then deploying rootCA.crt to client trust stores on Windows, Ubuntu, or Fedora/CentOS so signed certificates become trusted by default, as described in Armin Reiter's OpenSSL CA workflow.

Point the web server at the right files

For Nginx, the basic shape is straightforward:

server {
    listen 443 ssl;
    server_name app.internal;

    ssl_certificate /etc/ssl/certs/domain.crt;
    ssl_certificate_key /etc/ssl/private/domain.key;
}

For Apache, the same principle applies:

SSLCertificateFile /etc/pki/tls/certs/server.crt
SSLCertificateKeyFile /etc/pki/tls/private/server.key

The server needs the leaf certificate and the matching private key. It does not use the CA private key. That key should stay out of web servers entirely.

Teams standardizing internal HTTPS on a lightweight reverse proxy may also want a practical deployment reference like this guide to deploying and configuring Caddy web server.

Trust the CA and not the leaf certificate

This is the point many tutorials blur. The certificate that belongs in client trust stores is the CA certificate, usually rootCA.crt. Installing the server certificate itself into a trust store is the wrong mental model and creates unnecessary cleanup later.

A clean trust flow works like this:

  1. Install rootCA.crt on the client machine
  2. Deploy the signed leaf certificate on the server
  3. Connect to the service using a hostname or address present in the SAN list
  4. Let the client build the trust chain automatically

That's why a local CA is so much better for team environments. Once the root is trusted, newly issued internal service certificates can validate without repeating the trust dance service by service.

Platform trust work is part of the job

Trust doesn't become real when OpenSSL writes a .crt file. It becomes real when the target systems import the CA into their trust stores and applications use those stores.

A practical checklist helps:

  • Windows clients: Import the root CA certificate into the trusted root store.
  • Ubuntu systems: Add the root CA into the system trust path and refresh the trust database.
  • Fedora or CentOS systems: Install the CA certificate in the OS trust mechanism used by the platform.
  • Browsers and tools: Confirm they rely on the OS trust store or document exceptions if they don't.

If a server is configured correctly and clients still reject the certificate, the missing step is often trust-store installation and not certificate generation.

The final test should be boring. Open the site. Run the API client. Hit the reverse proxy. If everything was issued and trusted correctly, there should be no warning banners and no manual exceptions.

Advanced Topics and Common Error Troubleshooting

The tricky part of internal TLS isn't generating files. It's making choices that won't become cleanup work later. Many guides also skip the point that trusted certificates need correct X.509 extensions such as basicConstraints=CA:FALSE, keyUsage, and especially subjectAltName, and newer guidance increasingly includes ECDSA/P-256 alongside RSA-4096, as noted in OneUptime's OpenSSL certificate guidance.

RSA and ECDSA choice for internal TLS

RSA remains the default many teams choose because compatibility is familiar and operational behavior is well understood. ECDSA is increasingly attractive for internal services that want modern key types and smaller certificates.

Attribute RSA (e.g., 4096-bit) ECDSA (e.g., nistp256)
Compatibility Broadly familiar across older and mixed environments Strong fit for modern environments, but worth validating in heterogeneous fleets
Certificate size Larger Smaller
Operational familiarity Common in older OpenSSL examples and internal runbooks Increasingly present in newer guidance
When teams choose it Conservative compatibility-first setups Modern internal platforms that want leaner certificates
Main caution More overhead in file size and key size Validate client and platform support before standardizing

The right choice depends less on theory and more on the fleet. If there are legacy appliances, older middleware, or hard-to-audit clients, RSA is usually the safer default. If the environment is modern and controlled, ECDSA may be a cleaner long-term standard.

Certificate handling that avoids operational pain

A certificate workflow ages badly when file handling is inconsistent. The operational mistakes tend to be mundane.

  • Keep names predictable: Store CA files, leaf certificates, keys, and extension profiles in a directory layout that makes ownership obvious.
  • Inspect what was issued: Use openssl x509 -in domain.crt -noout -text before deployment instead of assuming the extensions were embedded correctly.
  • Verify against the CA: openssl verify -CAfile rootCA.crt domain.crt catches trust-chain mistakes early.
  • Automate renewal sensibly: Even in internal environments, repeatable issuance beats manual recreation under time pressure.

Teams that manage a lot of internal endpoints should also think beyond issuance. Internal certificates still expire, services still restart with stale file paths, and private keys still end up with bad permissions. Visibility into that broader risk surface matters, which is why many operators pair certificate hygiene with tooling such as vulnerability scanning workflows.

Troubleshooting table for the failures teams hit most

Problem Likely cause Fix
Browser says the certificate is invalid for the site name SAN is missing or doesn't include the actual hostname used by the client Reissue the certificate with a correct subjectAltName entry
Client reports unknown CA or untrusted issuer rootCA.crt was not installed in the client trust store Import the CA certificate into the proper OS or browser trust store
OpenSSL command succeeded but browser still warns The certificate was created, but the right X.509 extensions were not added Reissue with basicConstraints, keyUsage, extendedKeyUsage, and SAN included
Service won't start with the certificate files File paths or permissions are wrong, or the key doesn't match the certificate Check server config paths and confirm the key and cert belong together
Certificate validates on one machine and fails on another Trust was installed on one client but not distributed consistently Standardize trust-store installation across the environment
Team keeps generating one-off leaf certificates No internal CA process exists, so every service becomes a separate trust exception Create a local CA and issue leaf certificates from it consistently

One more practical distinction helps. If the goal is only to make a browser stop complaining on one laptop, the quick self-signed one-liner is enough. If the goal is to create a self signed certificate with OpenSSL in a way that works properly across a team, the winning pattern is almost never a directly self-signed leaf. It's a local CA, a proper CSR flow, SAN-aware issuance, and client trust-store installation.

That's the line between “certificate created” and “TLS working.”


Fivenines helps teams keep internal infrastructure observable after TLS is in place. For operators managing reverse proxies, Linux hosts, containers, websites, and scheduled jobs, Fivenines provides monitoring, uptime checks, alerting, and automation in one platform so certificate-backed services are easier to watch and faster to troubleshoot when something breaks.