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.
$ mkdir -p tls-local $ chmod 700 tls-local
$ umask 077
$ 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.
$ openssl pkey -in tls-local/localhost.key -noout -check Key is valid
$ 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.
$ chmod 600 tls-local/localhost.key $ chmod 644 tls-local/localhost.crt
$ 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
$ 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
$ 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
$ openssl verify -CAfile tls-local/localhost.crt tls-local/localhost.crt tls-local/localhost.crt: OK
$ openssl x509 -in tls-local/localhost.crt -pubkey -noout > tls-local/localhost.crt.pub
$ openssl pkey -in tls-local/localhost.key -pubout -out tls-local/localhost.key.pub
$ 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
$ rm tls-local/localhost.crt.pub tls-local/localhost.key.pub