How to create a self-signed certificate using OpenSSL

A self-signed certificate is useful when a local service needs TLS before a public or internal certificate authority is involved. The risk is creating a certificate that clients cannot match to the service name, that accidentally carries CA privileges, or that cannot be paired with the private key installed beside it.

OpenSSL can create the private key with openssl genpkey and issue a self-signed X.509 certificate with openssl req -new -x509. The certificate in this page is for localhost and 127.0.0.1, includes Subject Alternative Name entries, and sets Basic Constraints to CA:FALSE so it is an end-entity server certificate rather than a local CA root.

Use this pattern for development, lab, or internal testing endpoints where client trust will be installed deliberately or certificate warnings are acceptable. Public browsers and clients will not trust the certificate automatically; create a local CA instead when several internal certificates need to share one reusable trust anchor.

Steps to create a self-signed certificate using OpenSSL:

  1. Create a restricted directory for the certificate and key.
    $ mkdir -p tls-local
    $ chmod 700 tls-local
  2. Set a restrictive file creation mask in the current shell.
    $ umask 077
  3. Generate an RSA private key for the local certificate.
    $ openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -quiet -out tls-local/localhost.key

    The private key is not encrypted. Keep the directory and key permissions restrictive, and use a passphrase-protected key when the target service and operating procedure can support one.

  4. Check that OpenSSL can read the private key.
    $ openssl pkey -in tls-local/localhost.key -noout -check
    Key is valid
  5. Create the self-signed certificate from the private key.
    $ openssl req -new -x509 -sha256 -days 365 \
      -key tls-local/localhost.key \
      -out tls-local/localhost.crt \
      -subj "/C=US/O=Example Corp/CN=localhost" \
      -addext "subjectAltName = DNS:localhost,IP:127.0.0.1" \
      -addext "basicConstraints = critical,CA:FALSE" \
      -addext "keyUsage = critical,digitalSignature,keyEncipherment" \
      -addext "extendedKeyUsage = serverAuth"

    Change the subject and Subject Alternative Name list before creating a certificate for a different host. Use DNS: entries for hostnames and IP: entries for literal IP addresses.

  6. Set explicit permissions on the private key and public certificate.
    $ chmod 600 tls-local/localhost.key
    $ chmod 644 tls-local/localhost.crt
  7. Check the certificate and key file permissions.
    $ ls -l tls-local
    total 8
    -rw-r--r-- 1 user user 1298 Jun  5 20:48 localhost.crt
    -rw------- 1 user user 1704 Jun  5 20:48 localhost.key
  8. Inspect the certificate subject, issuer, validity, and TLS server extensions.
    $ openssl x509 -in tls-local/localhost.crt -noout \
      -subject -issuer -dates \
      -ext subjectAltName,basicConstraints,keyUsage,extendedKeyUsage
    subject=C=US, O=Example Corp, CN=localhost
    issuer=C=US, O=Example Corp, CN=localhost
    notBefore=Jun  5 20:48:59 2026 GMT
    notAfter=Jun  5 20:48:59 2027 GMT
    X509v3 Subject Alternative Name:
        DNS:localhost, IP Address:127.0.0.1
    X509v3 Basic Constraints: critical
        CA:FALSE
    X509v3 Key Usage: critical
        Digital Signature, Key Encipherment
    X509v3 Extended Key Usage:
        TLS Web Server Authentication
  9. Confirm the certificate matches the hostname and IP address clients will use.
    $ openssl x509 -in tls-local/localhost.crt -noout -checkhost localhost -checkip 127.0.0.1
    Hostname localhost does match certificate
    IP 127.0.0.1 does match certificate
  10. Verify the self-signed certificate as its own trust anchor.
    $ openssl verify -CAfile tls-local/localhost.crt tls-local/localhost.crt
    tls-local/localhost.crt: OK
  11. Extract the public key from the certificate.
    $ openssl x509 -in tls-local/localhost.crt -pubkey -noout > tls-local/localhost.crt.pub
  12. Extract the public key from the private key.
    $ openssl pkey -in tls-local/localhost.key -pubout -out tls-local/localhost.key.pub
  13. Compare the public keys to prove the certificate and private key belong together.
    $ diff -s tls-local/localhost.key.pub tls-local/localhost.crt.pub
    Files tls-local/localhost.key.pub and tls-local/localhost.crt.pub are identical
  14. Remove the temporary public-key comparison files.
    $ rm tls-local/localhost.crt.pub tls-local/localhost.key.pub