Large-brand providers'SSL certificates are not cheap. They may not be much for large companies, but they are expensive for small companies and individuals. Now Let's Encrypt, a free SSL service provider, is definitely a good news for small companies or developers.
Prerequisite
- Have a domain name, such as mydemo.com (for domestic hosts, also need to be filed through ICP)
Create an A record in the domain name server pointing to the IP address of the cloud host. For example, demo.mydemo.com points to the IP address of xxx. xxx. xxx. XXXX until the newly created domain name resolution can be resolved on the public network.
It is said that domestic domain name providers support letsencrypt very poorly, but after experimentation, at least at this stage, the domain name resolved by dnspod has not encountered problems. - Docker and docker-compose have some foundation, and the nginx environment has been deployed with docker
Installation through certbot script
Without special circumstances, certbot scripting is preferred.
Since the validity of letsencrypt certificate is only 90 days, if it needs to be used for a long time, it is necessary to extend the application before it expires. With the certbot scripting tool, the script for deferred application can be written to a timed task to complete automatically, which is very convenient.
1. Install the certbot tool
yum install -y epel-release yum install -y certbot
2. Application for Certificate by certbot Order
# Usage: certbot certonly -- webroot-w [Web site directory] - d [site domain name] - m [contact email address] -- agree-tos
sudo certbot certonly --webroot -w /webser/www/blog -d mydemo.com -m li_xxxxx@163.com --agree-tos
Note: The contact email address should be true and valid. letsencrypt will send a notice email before the certificate expires. After successful application, the following Congratulations information will be displayed
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at
/etc/letsencrypt/live/mydemo.com/fullchain.pem. Your cert will
expire on 2017-03-20. To obtain a new or tweaked version of this
certificate in the future, simply run certbot again. To
non-interactively renew *all* of your certificates, run "certbot
renew"
- If you like Certbot, please consider supporting our work by:
Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le
The certificate is stored in:
ll /etc/letsencrypt/live/mydemo.com/
#User certificate
cert.pem -> ../../archive/mydemo.com/cert1.pem
#Intermediate certificate
chain.pem -> ../../archive/mydemo.com/chain1.pem
#Certificate chain.pem + cert.pem
fullchain.pem -> ../../archive/mydemo.com/fullchain1.pem
#Certificate private key
privkey.pem -> ../../archive/mydemo.com/privkey1.pem
3. Check the validity of the order
openssl x509 -noout -dates -in /etc/letsencrypt/live/mydemo.com/cert.pem
4. Setting Timing Tasks to Update Certificates Automatically
The letsencrypt certificate is valid for 90 days, but can be updated with scripts.
#Configure crontab, update certificate at 1:5 a month, and restart docker container
00 05 01 * * sudo /usr/bin/certbot renew --quiet && sudo docker restart nginx
Note: The website must be accessible when updating certificates
5. Generating Perfect Forward Security (PFS) Key Values
PFS (perfect forward secrecy), Chinese can be called full forward secrecy. A key is required to access only the data protected by it; the elements used to generate the key are replaced one after another, and no other keys can be generated; a key is cracked without affecting the security of other keys.
#Create directory
mkdir /etc/ssl/private/ -p
#Executive order
cd /etc/ssl/private/
openssl dhparam 2048 -out dhparam.pem
6. Mount the certificate directory into the nginx container
I use docker-compose to manage containers. Here's the nginx choreography information in my docker-compse.yml file
php-fpm:
build: docker.io/php:7.1.8-fpm
container_name: php-fpm
volumes:
- /webser/www:/var/www/html
- /etc/hosts:/etc/hosts
- /webser/etc/php:/usr/local/etc/php/conf.d
ports:
- "9000:9000"
nginx:
image: docker.io/nginx
container_name: nginx
ports:
- "80:80"
- "443:443"
volumes:
- /webser/www:/var/www/html
- /webser/etc/nginx:/etc/nginx/conf.d
- /webser/logs/nginx:/var/log/nginx
- /etc/ssl:/etc/ssl
- /etc/letsencrypt:/etc/letsencrypt
links:
- php-fpm
You can also mount containers with the docker command
docker run -d -v /etc/ssl:/etc/ssl -v /etc/letsencrypt:/etc/letsencrypt --name nginx docker.io/nginx
7. Configuration of nginx
server {
listen 443 ssl http2;
server_name fungli.top;
access_log /var/log/nginx/access-blog.log main;
error_log /var/log/nginx/error-blog.log warn;
root /var/www/html/blog/;
index index.html index.htm index.php;
# File generated by letsencrypt
ssl_certificate /etc/letsencrypt/live/mydemo.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mydemo.com/privkey.pem;
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets on;
ssl_dhparam /etc/ssl/private/dhparam.pem;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
# Generally recommended ssl_ciphers: https://wiki.mozilla.org/Security/Server_Side_TLS
ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128:AES256:AES:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK';
ssl_prefer_server_ciphers on;
location ~ \.php {
root /var/www/html/blog;
include fastcgi_params;
fastcgi_pass php-fpm:9000;
fastcgi_split_path_info ^(.+\.php)(.*)$;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
location ~* ^.+\.(jpg|jpeg|gif|png|bmp|css|js|swf)$ {
access_log off;
#break;
}
}