SSL configuration on a web server

Many websites describe how to correctly set up a SSL/TLS web server with a secure configuration. Here is a list of some that I’ve found:

Here are example configurations for host with a certificate signed by StartSSL ( or Let’s encrypt ( or AlwaysOnSSL (


<IfModule mod_ssl.c>
<VirtualHost *:443>
    SSLEngine on
    SSLCertificateFile /etc/ssl/
    SSLCertificateKeyFile /etc/ssl/
    SSLCertificateChainFile /etc/ssl/intermediate.pem
    SSLCACertificateFile /etc/ssl/certs
    SSLProtocol ALL -SSLv2 -SSLv3
    SSLHonorCipherOrder On
    SSLCompression Off

    # Enable this if your want HSTS (recommended, but be careful)
    # Header add Strict-Transport-Security "max-age=15768000"

    # OCSP Stapling, only in httpd 2.3.3 and later
    SSLUseStapling On
    SSLStaplingResponderTimeout 5
    SSLStaplingReturnResponderErrors off
    SSLStaplingCache shmcb:/var/run/ocsp(128000)


server {
    listen 443;
    ssl on;
    # certs sent to the client in SERVER HELLO are concatenated
    ssl_certificate /etc/ssl/ssl.example.com_and_intermediates.pem;
    ssl_certificate_key /etc/ssl/;
    ssl_dhparam /etc/ssl/dhparam.pem;
    ssl_session_timeout 10m;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;

    # Enable this if your want HSTS (recommended, but be careful)
    # add_header Strict-Transport-Security max-age=15768000;

    # OCSP Stapling
    # fetch OCSP records from URL in ssl_certificate and cache them
    ssl_stapling on;
    ssl_stapling_verify on;
    # verify chain of trust of OCSP response using Root CA and Intermediate certs
    ssl_trusted_certificate /path/to/root_CA_cert_plus_intermediates;
    # IP address of the DNS resolver to be used to obtain the IP address of
    # the OCSP responder

To generate the Diffie-Hellman parameters for DHE ciphersuites, use:

openssl dhparam -out /etc/ssl/dhparam.pem 4096

Testing configuration

Here are several commands to be used to check a running HTTPS web server.

Establish an TLS (or SSL) connection:

openssl s_client -connect -servername -showcerts

Use a web service, like Qualys’ SSL Server Test:

This web page helps displays what your browser supports:

Using Let’s Encrypt

The official Let’s Encrypt client ( needs to run as root on the server which will use the certificate. Thankfully there exists other ways of signing certificates:

These methods rely on some openssl commands to use an account key.

  • To create an account key and print the associated public key:

    openssl genrsa 4096 > account.key
    openssl rsa -in account.key -pubout
  • To sign what needs to be signed:

    echo -n 'Content' | openssl dgst -sha256 -hex -sign account.key

To generate a Certificate Signing Request (CSR) for a domain with X509v3 Subject Alternative Name (SAN), these commands can be used:

openssl genrsa 4096 >
openssl req -new -sha256 -key -subj "/" \
    -reqexts SAN -config <(cat /etc/ssl/openssl.cnf
    <(printf "[SAN]\,"))

On some systems the OpenSSL configuration file lie elsewhere, for example in /etc/pki/tls/openssl.cnf or in /System/Library/OpenSSL/openssl.cnf (Mac OS).

In order to validate the ownership of a domain, a generated file needs to be served over HTTP (not HTTPS), which may for example give:

$ curl

To do this on a live (production system), a possible way consists in serving /.well-known/acme-challenge from a specific directory, where an administrator will put the needed files. With nginx, a configuration can be:

server {
    listen [::1]:80;

    # Let's encrypt
    location /.well-known/acme-challenge {
        alias /var/acme-challenge/;
    location / {
        rewrite ^(.*)$1 permanent;

Then an admin can put the files needed for Let’s Encrypt to verify domain ownership in directory /var/acme-challenge/