Description
The need for privacy (from prying eyes) and encrypting data to protect from those who seek to damage or destroy your business or livelihood is more necessary than ever. The reasons for encrypting data are many and is quickly becoming the web standard with several large companies such as Google, Apple, WordPress / Automattic and others going full SSL/TLS and recommending others do the same. The steps below will help you get your sites up and running with SSL/TLS quickly.
“Arguing that you don’t care about the right to privacy because you have nothing to hide is no different than saying you don’t care about free speech because you have nothing to say.”
– Edward Snowden
Purpose & Scope
Encrypting our data as a matter of habit is incumbent upon, and a responsibility of everyone in an age where true privacy and freedom are being assaulted from all angles, whether through deliberate malicious acts by hackers/crackers or the prying eyes and reach of governments who want complete unfettered access to all data in the form of backdoors written into software, which is completely unfeasible.
The latest (released in 2015), more streamlined Version TLS, version 1.3 (TLS is the newest generation of its better known predecessor, SSL) trims out unnecessary features and functions that ultimately could lead to buggy or compromised code. The goal of this release is a leaner yet strong encryption protocol that’s easier to implement and less likely to leave the door open to implementation flaws.
SSL / TLS or Secure Socket Layer / Transport Layer Security, is a way of sending and receiving web traffic in an an encrypted stream, from server to web browser and back again making eavsdropping or subversion of the stream impossible. Without strong encryption as the heart of all communications, anyone with the knowledge and equipment can listen, copy, alter or otherwise subvert unencrypted communications for their own benefit or nefarious purposes.
Most major technology companies such as: Google, Apple, Wikipedia, Automattic and many, many others support and encourage strong encryption not only on their own platforms, but everywhere on the web as a standard.
Getting Started
SSL Key file & CSR Generation
Apache httpd config
nginx config
Lighttpd SSL Wiki
Windows IIS config
Let’s Encrypt Certs
SSL Validation Tools
Further Reading
Note: These are example configs only and not meant to be copy/pasted directly. They are here to provide guidance and an example of a generic setup using the strongest encryption currently available.
In this example we’ll be using the domain “example.com” as per RFC.2606.
Get a free Level 1 SSL certificate valid for 3 months (renewable for free) from Let’s Encrypt
Get free SSL certificates at the Let’s Encrypt project, sponsored in part by Automattic and other companies.
Note: If your domain is selling products and is being used for commercial business, you may want to consider a Level 2 certification (EV) or higher. This may require a fee and recent scans of your passport and photo ID (front and back) as well as other qualifying information or direct contact.
Why should I generate my own certificate and not use a wizard offered through a provider?
One word, “control”. You should always control the certificate generation process on your own systems and understand it, relying on someone else’s tools obfuscates the process and removes some level of control from you.
No matter who the CA (Certificate Authority) is, always create the certificates and the CSR (Certificate Signing Request) first on your own systems. You’re only paying the Certificate Authority to sign it and verify that you are who you say you are or represent based on different verification levels, from automated to exhaustive / time consuming, the deeper the verification goes (Level 1, Level 2, EV, etc) will be reflected in the price.
Linux / OSX .key and .csr (Cerificate Signing Request) Generation Instructions
Note: Always store your keys in a safe place.
Purpose
To generate a 4096bit RSA certificate or Elliptical Curve key for use with the final certificate issued by the CA (Certificate Authority eg; StartSSL, Let’s Encrypt, Comodo, DigiCert, etc) and a signing request for the CA, which is a request to have a certificate issued for a specific domain (example.com), subdomain (secure.example.com) or wildcard (*.example.com).
- Make a new directory under /root/csr/$sitename for creating, storing and organizing your CSR’s for use with Certbot. (We’ll use this later below).
- Generate an RSA 4096bit or an Elliptical Curve key + CSR
- Generate a password protected version of the key.
- Generate a non-password protected version of the key.
- Generate the Certificate Signing Request.
- example.com.key
- example.com.nopass.key
- example.com.csr
- List available curves.
- Generate a non-password protected key.
- Generate a password protected key.
- Generate the CSR for the Certificate Authority.
- secure.example.org.key
- secure.example.org.nopass.key
- secure.example.org.csr
- Read the Let’s Encrypt FAQ
- Validate your domain confirming ownership using the key sent to the email of the domain owner
- Apply for a certificate using the .csr (Certificate Signing Request) file generated in Step 3 from “Generate an RSA 4096bit key + CSR” above.
- Login to your server and make yourself root using the following command:
su -
, make sure to include the dash, as this gives you root’s shell and $PATH. - Verify you’re in root’s home directory with the command:
pwd
if not, change to root’s home directory:cd /root
- Download Certbot to your server as root Choose your webserver and OS and follow the insrtructions to download Certbot
./certbot-auto certonly --csr /root/csr/example.com.csr
- You will need the following files for your webserver once the process is complete under the directory: /etc/lertsencrypt/live/example.com/
- cert.pem
- chain.pem
- fullchain.pem
- privkey.pem
mkdir -p /root/csr/example.com
Generate an RSA 4096bit key + CSR
openssl genrsa -des3 -out example.com.key 4096
Generating RSA private key, 4096 bit long modulus
………………………………….++
…………………………………………………………++
e is 65537 (0x10001)
Enter pass phrase for example.com.key:
Verifying – Enter pass phrase for example.com.key:
Note: This is so we don’t have to enter the password each time we restart the webserver, otherwise use the password-protected version.
openssl rsa -in example.com.key -out example.com.nopass.key
Enter pass phrase for example.com.key:
writing RSA key
openssl req -new -sha256 -key example.com.nopass.key -out example.com.csr
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter ‘.’, the field will be left blank.
– – – – –
Country Name (2 letter code) [XX]:
State or Province Name (full name) [ ]:
Locality Name (eg, city) [Default City]:
Organization Name (eg, company) [Default Company Ltd]:
Organizational Unit Name (eg, section) [ ]:
Common Name (eg, your name or your server’s hostname) [ ]:www.example.com
Email Address [ ]:admin@example.com
– – – – –
Please enter the following ‘extra’ attributes
to be sent with your certificate request
A challenge password [ ]:n3HVwyb#ewh^lMtv6td)ZR#H
An optional company name [ ]:
If you’ve done all these steps you’ll end up with the following files:
Generate an Elliptical Curve key + CSR
Note: Currently StartSSL does not support EC CSR’s.
openssl ecparam -list_curves
secp256k1 : SECG curve over a 256 bit prime field
secp384r1 : NIST/SECG curve over a 384 bit prime field
secp521r1 : NIST/SECG curve over a 521 bit prime field
prime256v1: X9.62/SECG curve over a 256 bit prime field
Note: This is so we don’t have to enter the password each time we restart the webserver, otherwise use the password-protected version.
openssl ecparam -out secure.example.org.nopass.key -name secp521r1 -genkey
openssl ec -in secure.example.org.nopass.key -des3 -out secure.example.org.key
openssl req -new -sha256 -key secure.example.org.nopass.key -nodes -out secure.example.org.csr
If you’ve done all these steps you’ll end up with the following files:
wget https://dl.eff.org/certbot-auto
Certbot Commands & Help
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | Certbot Commands: certbot-auto [SUBCOMMAND] [options] [-d DOMAIN] [-d DOMAIN] ... Certbot can obtain and install HTTPS/TLS/SSL certificates. By default, it will attempt to use a webserver both for obtaining and installing the cert. The most common SUBCOMMANDS and flags are: obtain, install, and renew certificates: (default) run Obtain & install a cert in your current webserver certonly Obtain or renew a cert, but do not install it renew Renew all previously obtained certs that are near expiry -d DOMAINS Comma-separated list of domains to obtain a cert for --apache Use the Apache plugin for authentication & installation --standalone Run a standalone webserver for authentication --nginx Use the Nginx plugin for authentication & installation --webroot Place files in a server's webroot folder for authentication --manual Obtain certs interactively, or using shell script hooks -n Run non-interactively --test-cert Obtain a test cert from a staging server --dry-run Test "renew" or "certonly" without saving any certs to disk manage certificates: certificates Display information about certs you have from Certbot revoke Revoke a certificate (supply --cert-path) delete Delete a certificate manage your account with Let's Encrypt: register Create a Let's Encrypt ACME account --agree-tos Agree to the ACME server's Subscriber Agreement -m EMAIL Email address for important account notifications More detailed help: -h, --help [TOPIC] print this message, or detailed help on a topic; the available TOPICS are: all, automation, commands, paths, security, testing, or any of the subcommands or plugins (certonly, renew, install, register, nginx, apache, standalone, webroot, etc.) |
Apache httpd Instructions / Configuration
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 | ########################## ### Apache httpd vhost ### ########################## <VirtualHost *:80> ## General setup for the default virtual host ## ServerAdmin root@localhost ServerName example.com ServerAlias www.example.com ## Log Files (not necessary, added for redundancy) ## ErrorLog logs/example.com-error_log CustomLog logs/example.com-access_log combined ## Permanent redirect to SSL, uncomment and use *one* of the following ## # Redirect permanent / https://example.com/ # RedirectMatch ^/(.*) https://example.org/$1 </VirtualHost> ############################## ### Apache httpd SSL vhost ### ############################## <VirtualHost *:443> ## General setup for the default SSL virtual host ## ServerAdmin root@localhost DocumentRoot /var/www/example.com ServerName example.com DirectoryIndex index.php FallbackResource /index.php ## Fallbackresource can be disabled in the directory context like this example: <directory /var/www/example.com/wp-admin/> FallbackResource disabled </Directory> ## Enable HSTS (if you have problems with this setting, remove `includeSubdomains;` below ## Header always set Strict-Transport-Security "max-age=63072000; includeSubdomains; preload" Header always set X-Frame-Options DENY Header always set X-Content-Type-Options nosniff ## Requires Apache >= 2.4 ## SSLCompression off SSLSessionTickets Off SSLUseStapling on SSLStaplingCache "shmcb:logs/stapling-cache(150000)" ## Log Files ## ErrorLog logs/example.com_ssl_error_log TransferLog logs/example.com_ssl_transfer_log CustomLog logs/example.com_ssl_access_log LogLevel warn ## Enable/Disable SSL ## SSLEngine On ## SSL Protocol support ## SSLProtocol All -SSLv2 -SSLv3 ## SSL Cipher Suite ## SSLHonorCipherOrder On SSLCipherSuite TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA384:EECDH+aRSA+SHA256:EECDH+aRSA+RC4:EECDH:EDH+aRSA:EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:kEDH+AESGCM:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-DSS-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:AES256:AES128:AES:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4 ## Server Certificate ## SSLCertificateFile /etc/pki/tls/certs/example.com.ssl.crt ## Server Private Key ## SSLCertificateKeyFile /etc/pki/tls/private/example.com.nopass.key ## Certificate Authority (CA) ## SSLCACertificateFile /etc/pki/tls/certs/start-ssl-ca-sha2.pem ## Server Certificate Chain ## SSLCertificateChainFile /etc/pki/tls/certs/sub.class1.server.ca.pem <Directory /var/www/example.com/> <Files ~ "\.(cgi|shtml|phtml|php3?)$"> SSLOptions +StdEnvVars </Files> </Directory> <Directory "/var/www/example.com/cgi-bin"> SSLOptions +StdEnvVars </Directory> ## Remove browser bugs from really old browsers ## <IfModule mod_headers.c> BrowserMatch ^Mozilla/4 gzip-only-text/html BrowserMatch ^Mozilla/4\.0[678] no-gzip BrowserMatch \bMSIE !no-gzip !gzip-only-text/html Header append Vary User-Agent </IfModule> ## Remove Browswer Entity Tags ## <IfModule mod_headers.c> <FilesMatch "\.(ico|pdf|flv|jpg|jpeg|png|gif|js|css|swf)(\.gz)?$"> Header set Expires "Thu, 30 Dec 2021 21:00:00 GMT" Header unset ETag FileETag None </FilesMatch> </IfModule> ## Compress HTML, CSS, JavaScript, Text, XML and fonts with mod_deflate ## <IfModule mod_deflate.c> # Force deflate for mangled headers developer.yahoo.com/blogs/ydn/posts/2010/12/pushing-beyond-gzipping/ <IfModule mod_setenvif.c> <IfModule mod_headers.c> SetEnvIfNoCase ^(Accept-EncodXng|X-cept-Encoding|X{15}|~{15}|-{15})$ ^((gzip|deflate)\s*,?\s*)+|[X~-]{4,13}$ HAVE_Accept-Encoding RequestHeader append Accept-Encoding "gzip,deflate" env=HAVE_Accept-Encoding </IfModule> </IfModule> <IfVersion < 2.4.4> <IfModule filter_module> # HTML, TXT, CSS, JavaScript, JSON, XML, HTC: FilterDeclare COMPRESS FilterProvider COMPRESS DEFLATE resp=Content-Type $text/html FilterProvider COMPRESS DEFLATE resp=Content-Type $text/css FilterProvider COMPRESS DEFLATE resp=Content-Type $text/plain FilterProvider COMPRESS DEFLATE resp=Content-Type $text/xml FilterProvider COMPRESS DEFLATE resp=Content-Type $text/x-component FilterProvider COMPRESS DEFLATE resp=Content-Type $application/javascript FilterProvider COMPRESS DEFLATE resp=Content-Type $application/json FilterProvider COMPRESS DEFLATE resp=Content-Type $application/xml FilterProvider COMPRESS DEFLATE resp=Content-Type $application/xhtml+xml FilterProvider COMPRESS DEFLATE resp=Content-Type $application/rss+xml FilterProvider COMPRESS DEFLATE resp=Content-Type $application/atom+xml FilterProvider COMPRESS DEFLATE resp=Content-Type $application/vnd.ms-fontobject FilterProvider COMPRESS DEFLATE resp=Content-Type $image/svg+xml FilterProvider COMPRESS DEFLATE resp=Content-Type $image/x-icon FilterProvider COMPRESS DEFLATE resp=Content-Type $application/x-font-ttf FilterProvider COMPRESS DEFLATE resp=Content-Type $font/opentype FilterChain COMPRESS FilterProtocol COMPRESS DEFLATE change=yes;byteranges=no </IfModule> </IfVersion> <IfVersion >= 2.4.4> <IfModule filter_module> FilterDeclare COMPRESS FilterProvider COMPRESS DEFLATE "%{Content_Type} = 'text/html'" FilterProvider COMPRESS DEFLATE "%{Content_Type} = 'text/css'" FilterProvider COMPRESS DEFLATE "%{Content_Type} = 'text/plain'" FilterProvider COMPRESS DEFLATE "%{Content_Type} = 'text/xml'" FilterProvider COMPRESS DEFLATE "%{Content_Type} = 'text/x-component'" FilterProvider COMPRESS DEFLATE "%{Content_Type} = 'application/javascript'" FilterProvider COMPRESS DEFLATE "%{Content_Type} = 'application/json'" FilterProvider COMPRESS DEFLATE "%{Content_Type} = 'application/xml'" FilterProvider COMPRESS DEFLATE "%{Content_Type} = 'application/xhtml+xml'" FilterProvider COMPRESS DEFLATE "%{Content_Type} = 'application/rss+xml'" FilterProvider COMPRESS DEFLATE "%{Content_Type} = 'application/atom+xml'" FilterProvider COMPRESS DEFLATE "%{Content_Type} = 'application/vnd.ms-fontobject'" FilterProvider COMPRESS DEFLATE "%{Content_Type} = 'image/svg+xml'" FilterProvider COMPRESS DEFLATE "%{Content_Type} = 'image/x-icon'" FilterProvider COMPRESS DEFLATE "%{Content_Type} = 'application/x-font-ttf'" FilterProvider COMPRESS DEFLATE "%{Content_Type} = 'font/opentype'" FilterChain COMPRESS FilterProtocol COMPRESS DEFLATE change=yes;byteranges=no </IfModule> </IfVersion> <IfModule !mod_filter.c> # Legacy versions of Apache AddOutputFilterByType DEFLATE text/html text/plain text/css application/json AddOutputFilterByType DEFLATE application/javascript AddOutputFilterByType DEFLATE text/xml application/xml text/x-component AddOutputFilterByType DEFLATE application/xhtml+xml application/rss+xml application/atom+xml AddOutputFilterByType DEFLATE image/x-icon image/svg+xml application/vnd.ms-fontobject application/x-font-ttf font/opentype </IfModule> </IfModule> ## Expires Defaults ## <IfModule mod_expires.c> ExpiresActive On # Set default expires to 2 days ExpiresDefault A172800 ExpiresByType text/css A31536000 ExpiresByType application/x-javascript A31536000 ExpiresByType text/x-component A31536000 ExpiresByType text/html A3600 ExpiresByType text/richtext A3600 ExpiresByType image/svg+xml A3600 ExpiresByType text/plain A3600 ExpiresByType text/xsd A3600 ExpiresByType text/xsl A3600 ExpiresByType text/xml A3600 ExpiresByType video/asf A31536000 ExpiresByType video/avi A31536000 ExpiresByType image/bmp A31536000 ExpiresByType application/java A31536000 ExpiresByType video/divx A31536000 ExpiresByType application/msword A31536000 ExpiresByType application/vnd.ms-fontobject A31536000 ExpiresByType application/x-msdownload A31536000 ExpiresByType image/gif A31536000 ExpiresByType application/x-gzip A31536000 ExpiresByType image/x-icon A31536000 ExpiresByType image/jpeg A31536000 ExpiresByType application/vnd.ms-access A31536000 ExpiresByType audio/midi A31536000 ExpiresByType video/quicktime A31536000 ExpiresByType audio/mpeg A31536000 ExpiresByType video/mp4 A31536000 ExpiresByType video/mpeg A31536000 ExpiresByType application/vnd.ms-project A31536000 ExpiresByType application/x-font-otf A31536000 ExpiresByType application/vnd.oasis.opendocument.database A31536000 ExpiresByType application/vnd.oasis.opendocument.chart A31536000 ExpiresByType application/vnd.oasis.opendocument.formula A31536000 ExpiresByType application/vnd.oasis.opendocument.graphics A31536000 ExpiresByType application/vnd.oasis.opendocument.presentation A31536000 ExpiresByType application/vnd.oasis.opendocument.spreadsheet A31536000 ExpiresByType application/vnd.oasis.opendocument.text A31536000 ExpiresByType audio/ogg A31536000 ExpiresByType application/pdf A31536000 ExpiresByType image/png A31536000 ExpiresByType application/vnd.ms-powerpoint A31536000 ExpiresByType audio/x-realaudio A31536000 ExpiresByType image/svg+xml A31536000 ExpiresByType application/x-shockwave-flash A31536000 ExpiresByType application/x-tar A31536000 ExpiresByType image/tiff A31536000 ExpiresByType application/x-font-ttf A31536000 ExpiresByType audio/wav A31536000 ExpiresByType audio/wma A31536000 ExpiresByType application/vnd.ms-write A31536000 ExpiresByType application/vnd.ms-excel A31536000 ExpiresByType application/zip A31536000 </IfModule> # No caching for dynamic files <filesMatch "\.(php|cgi|pl|htm)$"> ExpiresDefault A0 Header set Cache-Control "no-store, no-cache, must-revalidate, max-age=0" Header set Pragma "no-cache" </filesMatch> # 1 MIN <filesMatch "\.(html)$"> ExpiresDefault A60 Header set Cache-Control "max-age=60, must-revalidate" </filesMatch> # 2 DAYS <filesMatch "\.(xml|txt)$"> ExpiresDefault A172800 Header set Cache-Control "max-age=172800, must-revalidate" </filesMatch> # 1 WEEK <filesMatch "\.(jpg|jpeg|png|gif|swf|js|css)$"> ExpiresDefault A604800 Header set Cache-Control "max-age=604800, must-revalidate" </filesMatch> # 1 MONTH <filesMatch "\.(ico|pdf|flv)$"> ExpiresDefault A2419200 Header set Cache-Control "max-age=2419200, must-revalidate" </filesMatch> ######################### ## Additional Security ## ######################### ## Apache httpd 2.2 ## ## Disable access to xmlrpc.php ## <Directory /var/www/example.com/> <Files xmlrpc.php> Order allow,deny Deny from all </Files> ## Disable access to wp-config.php ## <Files wp-config.php> Order allow,deny Deny from all </Files> ## Prevent .htaccess files from being spidered or viewed via a web browser ## <FilesMatch "^\.ht"> Order allow,deny Deny from all satisfy all </FilesMatch> </Directory> ## Apache httpd 2.4 ## ## Disable access to xmlrpc.php ## <Directory /var/www/example.com/> <Files xmlrpc.php> Require all denied </Files> ## Disable access to wp-config.php ## <Files wp-config.php> Require all denied </Files> ## Prevent .htaccess files from being spidered or viewed via a web browser ## <Files ".ht*"> Require all denied </Files> </Directory> ## MSIE fix ## SetEnvIf User-Agent ".*MSIE.*" \ nokeepalive ssl-unclean-shutdown \ downgrade-1.0 force-response-1.0 ## Per-Server Logging ## CustomLog logs/ssl_request_log \ "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b" </VirtualHost> |
nginx Instructions / Configuration
Before we begin
- Download the certificate authority bundle here: https://www.startssl.com/certs/ca-sha2.crt
- Combine your new cert with the certificate authorities bundle:
cat example.com.ssl.crt ca-sha2.crt >> example.com.bundle.crt
- This will combine both files into a single file called
example.com.bundle.crt
which the nginx webserver will use. - Additional reading: http://nginx.org/en/docs/http/configuring_https_servers.html
Key Exchange Parameters
By default, Nginx will use the default DHE (Ephemeral Diffie-Hellman) parameters provided by openssl, this uses a weak key that gets lower scores. It’s better build your own 4096bit key.
Command:
openssl dhparam -out /etc/pki/tls/private/dhparam.pem 4096
nginx Config:
ssl_dhparam /etc/pki/tls/private/dhparam.pem;
Read about: nginx SSL/TLS termination
Read about: dhparam
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | ####################### ### nginx SSL vhost ### ####################### ## General setup for the default SSL virtual host ## server { listen 443; server_name .example.com; root /www/example.com/public; client_max_body_size 512M; ## SSL Configuration ## ssl on; ssl_certificate /etc/pki/tls/certs/example.com.ssl.crt; ssl_certificate_key /etc/pki/tls/private/example.com.nopass.key; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; ssl_ciphers TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA384:EECDH+aRSA+SHA256:EECDH+aRSA+RC4:EECDH:EDH+aRSA:EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:kEDH+AESGCM:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-DSS-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:AES256:AES128:AES:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4 ## Requires nginx >= 1.1.0 ssl_ecdh_curve secp384r1; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; ## Requires nginx >= 1.5.9 ssl_session_tickets off; ## Requires nginx >= 1.3.7 ssl_stapling on; ssl_stapling_verify on; resolver $DNS-IP-1 $DNS-IP-2 valid=300s; resolver_timeout 5s; ## dhparam ssl_dhparam ssl/dhparam.pem; ## Turn off promiscuous data ### add_header Strict-Transport-Security "max-age=31536000; includeSubdomains"; add_header X-Frame-Options DENY; add_header X-Content-Type-Options nosniff; ## Logs ## access_log /www/example.com/logs/example.com-access.log main; error_log /www/example.com/logs/example.com-error.log; ## Default location settings ## location / { index index.html index.htm index.php; try_files $uri $uri/ /index.php?$args; } ## Redirect server error pages to the static page /50x.html ## error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } error_page 404 /404.html; ## Pass the PHP scripts to FastCGI server (locally with unix: param to avoid network overhead) ## location ~ \.php$ { ## Prevent Zero-day exploit ## try_files $uri =404; ## NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini ## fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass unix:/var/run/php-fpm/example.com.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } ## Deny access to .htaccess files, if Apache's document root ## location ~ /\.ht { deny all; } ## Exclude favicon from the logs to avoid bloating when it's not available ## location /favicon.ico { log_not_found off; access_log off; } } |
nginx Reverse Proxy Caveats
If you use nginx as a reverse proxy in front of an Apache httpd server and terminate the SSL connection with nginx while proxying the connection to Apache httpd over HTTP, see the following:
wp-config.php
1 2 3 4 5 6 7 8 9 10 | define('FORCE_SSL_ADMIN', true); define('FORCE_SSL_LOGIN', true); if ($_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') { $_SERVER['HTTPS']='on'; } if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) { $_SERVER['HTTP_HOST'] = $_SERVER['HTTP_X_FORWARDED_HOST']; } |
This means $_SERVER[‘HTTPS’] will be ‘on’ and $_SERVER[‘HTTP_HOST’] will be ‘wp-root.org’ (in my case) and in turn is_ssl() will work and so will your site.
nginx configuration:
proxy_set_header X-Forwarded_Proto https;
or
proxy_set_header X-Forwarded-Proto $scheme;
Also see: WordPress Administration over SSL – Using a Reverse Proxy
Windows IIS Webserver Instructions
- Take
example.com.nopass.key
generated in Step 2, put it in the same directory as the new certificate file from StartSSL, which we’ll callexample.com.ssl.crt
and run the following to combine them:
Command: openssl pkcs12 -export -out example.com.pfx -inkey example.com.nopass.key -in example.com.ssl.crt
This will combine both files into a single file called example.com.pfx
which the IIS webserver will use.
Testing
Validate your setup once you feel it’s complete with these free tools.
Mozilla SSL Config Generator
Strong cipher examples
|[ SSL Validation Tools ]|
Mozilla SSL Config Ciper Strength Test
Qualys SSL Labs Server Test
SSL Shopper SSL Test
DigiCert SSL Tools
GeoCerts SSL Checker
Comodo SSL Analyzer
Further Reading
Additional Resource: see mod_md for Apache httpd for managing certs.
Description Summary
This module manages common properties of domains for one or more virtual hosts. Specifically it can use the ACME protocol (RFC Draft) to automate certificate provisioning. These will be configured for managed domains and their virtual hosts automatically. This includes renewal of certificates before they expire. The most famous Certificate Authority currently implementing the ACME protocol is Let’s Encrypt.
- SSL Labs “best Practices” document on setup and configuration of SSL TLS (PDF)(link)
- Official Apache httpd documentation, SSL/TLS howto.
- Read about: Securing Apache httpd
- Read about: nginx SSL/TLS termination
- Read about: nginx SSL Offloaders
- Read about: dhparam
- Read about: Strong Ciphers
- Read about: WordPress’ set_url_scheme function
- Read about: Google’s opinion on TLS enabled sites