Applies to: OpenSSL 3.5.5 (Ubuntu 26.04), OpenSSL 3.5.8 (AlmaLinux 10) and OpenSSL 3.0.13 (Ubuntu 24.04), with Nginx 1.28 and curl; Windows Server PowerShell according to Microsoft
To create a self-signed SSL certificate on Linux, run one OpenSSL command. It makes a new private key and a certificate valid for one year, with your domain names in the Subject Alternative Name (SAN) field:
openssl req -x509 -newkey rsa:2048 -noenc \ -keyout example.com.key -out example.com.crt -days 365 \ -subj "/CN=example.com" \ -addext "subjectAltName=DNS:example.com,DNS:www.example.com,IP:192.0.2.10"
OpenSSL prints a line of dots and plus signs while it generates the key, then writes two files: example.com.key (the private key, created with permissions -rw-------) and example.com.crt (the certificate). Replace the names and the IP address with your own, or drop the IP: entry if you don’t need it.
A self-signed certificate encrypts the connection, but no browser trusts it, because no certificate authority vouched for it. Use it for testing, internal tools, staging sites and connections between your own servers. For a public website, use a trusted certificate (see the end of this article).
What each option does
req -x509: create a finished certificate instead of a certificate request.-newkey rsa:2048: generate a new 2048-bit RSA key at the same time.-noenc: don’t put a passphrase on the key, so a web server can start without asking for one. Older guides use-nodes; it still works, but the help text of OpenSSL 3.5 marks it “deprecated”.-days 365: validity. Without it, OpenSSL makes the certificate valid for only 30 days (in our test, Oct 10 to Nov 9).-subj "/CN=example.com": the subject, so OpenSSL doesn’t ask questions.-addext "subjectAltName=...": the names the certificate is valid for. This part matters most. Browsers and tools check the SAN list, not the Common Name: RFC 9525 says the Common Name must not be used to identify a service.
Check the certificate
$ openssl x509 -in example.com.crt -noout -subject -issuer -dates -ext subjectAltName,basicConstraints
subject=CN=example.com
issuer=CN=example.com
notBefore=Oct 10 05:05:46 2026 GMT
notAfter=Oct 10 05:05:46 2027 GMT
X509v3 Basic Constraints: critical
CA:TRUE
X509v3 Subject Alternative Name:
DNS:example.com, DNS:www.example.com, IP Address:192.0.2.10
Subject and issuer are the same: that is what “self-signed” means. openssl x509 -in example.com.crt -noout -text shows every field.
Other variants
- Answer the questions instead of using -subj: leave out
-subjand OpenSSL asks for Country Name (2 letter code), State or Province Name, Locality Name, Organization Name, Organizational Unit Name, Common Name (eg server FQDN or YOUR name) and Email Address. Press Enter to skip a field. You still need-addextfor the SAN. - An ECDSA key (much shorter than an RSA key): replace
-newkey rsa:2048with-newkey ec -pkeyopt ec_paramgen_curve:prime256v1. The certificate then showsecdsa-with-SHA256andprime256v1. - A wildcard certificate:
-subj "/CN=*.example.com" -addext "subjectAltName=DNS:*.example.com,DNS:example.com". The wildcard covers one level: in our curl test,www.example.comandshop.example.commatched, butexample.comanda.b.example.comdid not. That is whyexample.comis listed separately.
Generate a CSR (certificate signing request)
If you are going to buy a certificate or get one from your company’s certificate authority, you need a CSR instead. Drop -x509 and -days:
openssl req -new -newkey rsa:2048 -noenc \ -keyout shop.example.com.key -out shop.example.com.csr \ -subj "/C=IN/ST=Kerala/L=Kollam/O=Example Ltd/CN=shop.example.com" \ -addext "subjectAltName=DNS:shop.example.com,DNS:www.shop.example.com"
Check it before you send it:
$ openssl req -in shop.example.com.csr -noout -verify -subject Certificate request self-signature verify OK subject=C=IN, ST=Kerala, L=Kollam, O=Example Ltd, CN=shop.example.com
Send only the .csr file (it starts with -----BEGIN CERTIFICATE REQUEST-----). Keep the .key file on the server; the certificate you receive only works with that key. On cPanel servers you can generate the CSR in cPanel or in WHM instead.
You can also sign your own CSR to get a self-signed certificate. -copy_extensions copy keeps the SAN names from the request:
$ openssl x509 -req -in shop.example.com.csr -key shop.example.com.key \ -days 365 -copy_extensions copy -out shop.example.com.crt Certificate request self-signature ok subject=C=IN, ST=Kerala, L=Kollam, O=Example Ltd, CN=shop.example.com
Check that the key and certificate belong together
Both commands must print the same hash:
$ openssl x509 -in example.com.crt -noout -pubkey | sha256sum 877f97bfb19bb943797492d2992f960d41bf176c5478de249e4a9861e723c1a1 - $ openssl pkey -in example.com.key -pubout | sha256sum 877f97bfb19bb943797492d2992f960d41bf176c5478de249e4a9861e723c1a1 -
Use it in Nginx
- Copy both files to a folder such as
/etc/ssl/example.com/and protect the key:chmod 600 /etc/ssl/example.com/example.com.key - Point the server block at them:
server { listen 443 ssl; server_name example.com www.example.com; ssl_certificate /etc/ssl/example.com/example.com.crt; ssl_certificate_key /etc/ssl/example.com/example.com.key; root /var/www/html; } - Test the configuration with
sudo nginx -t, then reload withsudo systemctl reload nginx.
If the key doesn’t match the certificate, nginx -t stops with SSL_CTX_use_PrivateKey(...) failed (SSL: error:05800074:x509 certificate routines::key values mismatch). For Apache, see how to enable SSL for Apache with your own certificate; for a Windows server that needs a .pfx file, convert the certificate to PFX.
Why clients reject it, and how to trust it
We served the certificate with OpenSSL on a test machine and connected with curl (pointing example.com at the test machine with curl’s --resolve option). Without trust, curl refuses:
$ curl https://example.com:8443/ curl: (60) SSL certificate OpenSSL verify result: self-signed certificate (18)
Connecting by a name or IP address that is not in the SAN list fails even when the certificate is trusted:
curl: (60) SSL: no alternative certificate subject name matches target hostname 'wrong.example.net'
To trust the certificate on a Linux machine that connects to this server, add it to the system trust store:
# Ubuntu and Debian sudo cp example.com.crt /usr/local/share/ca-certificates/example.com.crt sudo update-ca-certificates 1 added, 0 removed; done. # AlmaLinux sudo cp example.com.crt /etc/pki/ca-trust/source/anchors/ sudo update-ca-trust
After that, openssl verify example.com.crt prints example.com.crt: OK, and curl connects. For a single command you can also use curl --cacert example.com.crt. Avoid curl -k outside quick tests: it accepts any certificate, including a fake one.
Create a self-signed certificate on Windows
You can install OpenSSL on Windows (see our guide) and use the commands above. Windows Server also has a built-in PowerShell cmdlet. According to Microsoft, this creates a certificate for both names in the computer’s Personal store, valid for one year, with the first name as subject and issuer:
$cert = New-SelfSignedCertificate -DnsName "example.com","www.example.com" -CertStoreLocation "Cert:\LocalMachine\My"
To copy it, with its private key, to another program or server, export a password-protected PFX file (choose your own password):
$mypwd = ConvertTo-SecureString -String 'ChooseAPassword' -Force -AsPlainText Export-PfxCertificate -Cert "Cert:\LocalMachine\My\$($cert.Thumbprint)" -FilePath C:\example.com.pfx -Password $mypwd
Add -NotAfter (Get-Date).AddYears(2) to New-SelfSignedCertificate for a longer validity. We did not run these PowerShell commands in our lab; they come from Microsoft’s documentation.
When to use a trusted certificate instead
Visitors to a public site see a security warning with a self-signed certificate, so use a certificate from a trusted authority there: a free Let’s Encrypt certificate, or a DV, OV or wildcard certificate from our SSL certificates page, which includes free installation help. If a browser still reports an untrusted certificate after you install one, see SSL certificate not trusted: causes and fixes.
Official documentation: openssl-req, RFC 9525 and New-SelfSignedCertificate.