A+ rating on Qualys SSL Labs 100-100-100-100


[spoiler title=’strong security with Simp_le and nginx’ style=’default’ collapse_link=’true’]

Enabling SSL

server {
listen 443;
server_name www.yourdomain.de;
# Turn on SSL; Specify certificate & keys
ssl on;
ssl_certificate /path/to/ssl/yourdomain.com/fullchain.pem;
ssl_certificate_key /path/to/ssl/yourdomain.com/key.pem;

SSL Protocols

ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
ssl_protocols TLSv1.2;

SSL Ciphers and Cipher Orders

ssl_ecdh_curve secp384r1; # 384 bit prime modulus curve efficiently supports ECDHE ssl_ciphers up to a SHA384 hash
ssl_prefer_server_ciphers on;

SSL Optimisations

ssl_session_timeout 5m;
ssl_session_cache builtin:1000 shared:SSL:10m;

OCSP stapling

ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /path/to/ssl/yourdomain.com/fullchain.pem;
resolver valid=300s;
resolver_timeout 5s;

Strict Transport Security

add_header Strict-Transport-Security "max-age=31536000; includeSubdomains";
add_header Cache-Control "public";
add_header X-Content-Type-Options "nosniff";
add_header X-Frame-Options "DENY";

Forward Secrecy & Diffie Hellman Ephemeral Parameters

ssl_dhparam /etc/ssl/certs/dhparam.pem;

Qualys SSL Labs – SSL Report – dksi.de
testssl.sh: Testing TLS/SSL encryption
OpenSSL manpage ciphers
Check optional preload token
Module ngx_http_ssl_module

solved – 504 Gateway Time-out nginx

change in /etc/php5/fpm/php.ini the point

max_execution_time = 300

change in /etc/php5/fpm/pool.d/www.conf

request_terminate_timeout = 300

insert in your nginx config file in the virtual host configuration

fastcgi_read_timeout 300;

[spoiler]then it seems like this

location ~ ^(.+?\.php)(/.*)?$ {
try_files $1 = 404;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$1;
fastcgi_param PATH_INFO $2;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_read_timeout 300;
fastcgi_index index.php;

reload the config files

root@dunedin:~# service nginx restart
root@dunedin:~# service php5-fpm restart



solved – generating new letsencrypt certificates failed


the simp_le script reports:

2016-05-15 16:06:16,375:ERROR:simp_le:1271: CA marked some of the authorizations as invalid, which likely means it could not access http://example.com/.well-known/acme-challenge/X. Did you set correct path in -d example.com:path or --default_root? Is there a warning log entry about unsuccessful self-verification? Are all your domains accessible from the internet? Failing authorizations: https://acme-v01.api.letsencrypt.org/acme/authz/l8LLl8JdKN2L33QHrVlaIuh4dRftEweGhBFVoPwn78V0
Challenge validation has failed, see error log.

Debugging tips: -v improves output verbosity. Help is available under –help.


Looks like I’m redirecting to HTTPS but the challenge files serving over HTTP only.

insert this into your nginx enabled config file

# Do not use a /tmp folder or other users can obtain certificates.
location ‘/.well-known/acme-challenge’ {
default_type “text/plain”;
root        /tmp/letsencrypt/$server_name;
location / {
rewrite ^/(.*) https://$server_name/$1 permanent;

after setting the server declaration. Then it looks like this

server {
client_max_body_size    500M;
fastcgi_buffers 64 64K;
listen   80;
server_name yourdomain.de www.yourdomain.de;
# Do not use a /tmp folder or other users can obtain certificates.
location ‘/.well-known/acme-challenge’ {
default_type “text/plain”;
root        /tmp/letsencrypt/$server_name;
location / {
rewrite ^/(.*) https://$server_name/$1 permanent;

to safe my certificates I added rm -r /tmp/letsencrypt/*; in the certrenew script before

chmod -R 400 /etc/nginx/ssl/${DOMAIN}/*;
service nginx restart;

Now it looks like

for i in “${DOMAINS[@]}”
echo “Checking Domain ${i}.”
cd /etc/nginx/ssl/${i};
chmod -R 600 /etc/nginx/ssl/${DOMAIN}/*;
simp_le -d ${i}:/tmp/letsencrypt/${DOMAIN} -f account_key.json -f key.pem -f cert.pem -f fullchain.pem && service nginx reload;
rm -r /tmp/letsencrypt/*;
chmod -R 400 /etc/nginx/ssl/${DOMAIN}/*;
service nginx restart;

the result should seems like

2016-05-16 08:31:21,254:INFO:requests.packages.urllib3.connectionpool:788: Starting new HTTPS connection (1): acme-v01.api.letsencrypt.org
2016-05-16 08:31:23,615:INFO:simp_le:391: Saving account_key.json
2016-05-16 08:31:23,634:INFO:simp_le:391: Saving key.pem
2016-05-16 08:31:23,639:INFO:simp_le:391: Saving cert.pem
2016-05-16 08:31:23,655:INFO:simp_le:391: Saving fullchain.pem


2016-05-16 09:14:54,718:INFO:simp_le:1383: Certificates already exist and renewal is not necessary, exiting with status code 1.


Update phpmyadmin4.2 to phpmyadmin4.6

find your phpmyadmin directory

copy the config.inc.php file outside of your phpmyadmin directory

download the newest version from https://www.phpmyadmin.net/downloads/

root@dunedin:~# wget https://files.phpmyadmin.net/phpMyAdmin/4.6.1/phpMyAdmin-4.6.1-all-languages.tar.gz

and extract it

root@dunedin:~# tar xvfz phpMyAdmin-4.6.1-all-languages.tar.gz

move the phpmyadmin folder to a saved version like phpmyadmin_safe
move the extracted folder into the root of your phpmyadmin_safe folder

root@dunedin:~# mv phpMyAdmin-4.6.1-all-languages/ /var/www/phpmyadmin

insert the saved config.ing.php into the new phpmyadmin folder.

nginx bind problem resolved


Starting nginx: nginx: [emerg] bind() to failed (98: Address already in use)
nginx: [emerg] bind() to failed (98: Address already in use)
nginx: [emerg] bind() to failed (98: Address already in use)
nginx: [emerg] bind() to failed (98: Address already in use)
nginx: [emerg] bind() to failed (98: Address already in use)
nginx: [emerg] still could not bind()


sudo fuser -k 80/tcp
service nginx start
Starting nginx: nginx.

compiling and installing nginx latest version

The lastest version of NGINX you’ll find here: http://nginx.org/

wget http://nginx.org/download/nginx-$VERSION.tar.gz | tar zxvf -
cd nginx-$VERSION

./configure --sbin-path=/usr/sbin/nginx \
--conf-path=/etc/nginx/nginx.conf \
--pid-path=/var/run/nginx.pid \
--error-log-path=/var/log/nginx/error.log \
--http-log-path=/var/log/nginx/access.log \
--with-http_ssl_module \
--with-http_v2_module \

make install
service nginx start
nginx -v

http://nginx.org/en/docs/http/ngx_http_spdy_module.html This module was superseded by the ngx_http_v2_module module in 1.9.5.

Restricting Access to a part of your site

you can restrict the access to a part or a complete vhost of your site.
Insert into the nginx-server config file. This protect the access to the path root.

location /auth/ {
auth_basic "Restricted Area";
auth_basic_user_file /etc/nginx/path-to-your-htpasswd;

The following folder is publicy available.

location /public/ {
auth_basic off;

Create a new user to grant access to your restricted area.

htpasswd -c /etc/nginx/path-to-your-htpasswd check

Now you can try the look and feel at my server for the above stated folder.
Click here to start: https://blog.dksi.de/auth/, username: check, pass: check.


Using simp_le with Let’s Encrypt for free SSL Certificates with NGINX

install simp_le client, a third party client as an alternative to the letsencrypt client

sudo git clone https://github.com/kuba/simp_le /opt/simp_le
cd /opt/simp_le
sudo ./bootstrap.sh
sudo ./venv.sh
sudo ln -s $(pwd)/venv/bin/simp_le /usr/local/sbin/simp_le

to fix the following issue:

Checking Domain blog.dksi.de
2017-01-27 14:48:34,271:INFO:requests.packages.urllib3.connectionpool:788: Starting new HTTPS connection (1): acme-v01.api.letsencrypt.org
Traceback (most recent call last):
File “/opt/simp_le/simp_le.py”, line 1401, in main
return main_with_exceptions(cli_args)
File “/opt/simp_le/simp_le.py”, line 1386, in main_with_exceptions
persist_new_data(args, existing_data)
File “/opt/simp_le/simp_le.py”, line 1282, in persist_new_data
client = registered_client(args, existing_data.account_key)
File “/opt/simp_le/simp_le.py”, line 1224, in registered_client
client = acme_client.Client(directory=args.server, key=key, net=net)
File “/opt/simp_le/venv/lib/python2.7/site-packages/acme/client.py”, line 63, in __init__
File “/opt/simp_le/venv/lib/python2.7/site-packages/acme/messages.py”, line 169, in from_json
raise jose.DeserializationError(str(error))
DeserializationError: Deserialization error: Wrong directory fields

Unhandled error has happened, traceback is above

Debugging tips: -v improves output verbosity. Help is available under –help.

I found the solution on


sudo mv /opt/simp_le /opt/simp_le_safe

sudo git clone https://github.com/zenhack/simp_le /opt/simp_le
cd /opt/simp_le
sudo ./bootstrap.sh
export PATH=$PWD/venv/bin:$PATH

and it works again

make the nginx snippet

this allows simp_le to validate your domain, this could easily be put in a vhost directly, but including the snippet is cleaner approach.
sudo mkdir /etc/nginx/snippets;
sudo sh -c 'echo "location /.well-known/acme-challenge { \n alias /tmp/letsencrypt/$server_name.well-known/acme-challenge; \n}\n" > /etc/nginx/snippets/letsencrypt.conf';


include this in each of your vhosts at the bottom

put this inside of the server block, just before the closing tag.

include /etc/nginx/snippets/letsencrypt.conf;

edit your nginx config

Since nginx doesn’t check configs until reload, we can make the config changes before the certificate is generated.
This allows us to create the ssl and reload nginx in one command below.

ssl_stapling on;
ssl_stapling_verify on;
ssl_certificate /path/to/ssl/yourdomain.com/fullchain.pem;
ssl_certificate_key /path/to/ssl/yourdomain.com/key.pem;
ssl_trusted_certificate /path/to/ssl/yourdomain.com/fullchain.pem;

request a new Domain

sudo mkdir /etc/nginx/ssl/${DOMAIN};
sudo chmod 700 /etc/nginx/ssl/${DOMAIN};
cd /etc/nginx/ssl/${DOMAIN};
sudo simp_le -d ${DOMAIN}:/tmp/letsencrypt/${DOMAIN} -f account_key.json -f key.pem -f cert.pem -f fullchain.pem --default_root /path/to/your/webroot/ && sudo service nginx reload;
sudo chmod -R 400 /etc/nginx/ssl/${DOMAIN}/*;

create the renewal script in /usr/local/sbin/certrenew

I don’t know, if it works fine, Letsencrypt rate limits for certificate issuance. Certificates/Domain you could run into through repeated re-issuance. This limit measures certificates issued for a given combination of Public Suffix + Domain (a “registered domain”).
Let’t Encrypt has rate limits for certificate issuance.
sudo touch /usr/local/sbin/certrenew;
sudo nano /usr/local/sbin/certrenew;

insert into the script

DOMAINS=( “$@” )

for i in “${DOMAINS[@]}”
echo “Checking Domain ${i}.”
cd /etc/nginx/ssl/${i};
chmod -R 600 /etc/nginx/ssl/${DOMAIN}/*;
simp_le -d ${i}:/tmp/letsencrypt -f account_key.json -f key.pem -f cert.pem -f fullchain.pem && rm -rf /tmp/letsencrypt/* && service nginx reload;
chmod -R 400 /etc/nginx/ssl/${DOMAIN}/*;

disable writing to the script, so no one can make changes.
sudo chmod 500 /usr/local/sbin/certrenew;
You can test the above script by running this command and piping in your domains seperated by spaces.
sudo /usr/local/sbin/certrenew yourdomain1.com yourdomain2.com yourdomain3.com

insert the crontab

to check nightly at 1am
sudo crontab -e

00 1 * * * /usr/local/sbin/certrenew yourdomain1.com yourdomain2.com yourdomain3.com || true

testssl.sh: Testing TLS/SSL encryption