CentOS 7 Nginx配置Let's Encrypt SSL证书

5,863 阅读8分钟
原文链接: www.biaodianfu.com

去年购买的阿里云到期了,由于阿里云续费比新买贵很多,所以重现买了一台虚拟机,迁移过程中需要重新配置Let’s Encrypt证书,在执行过程中发现了一些问题,经过几个小时的摸索,终于搞定。

安装Let’s Encrypt证书一般的流程

yum install epel-release -y
yum install certbot -y

然后执行:

certbot certonly --webroot -w /home/www/www.biaodianfu.com -d www.biaodianfu.com -m biaodianfu@email.com --agree-tos

相关参数含义:

  • –webroot是运行模式
    • standalone模式:需要停止当前的 web server 服务,让出 80 端口,由客户端内置的 web server 启动与Let’ s Encrypt通信。
    • webroot模式:不需要停止当前 web server,但需要在域名根目录下创建一个临时目录,并要保证外网通过域名可以访问这个目录。
  • -w 指定网站所在目录
  • -d 指定网站域名
  • -m 指定联系邮箱,填写真实有效的,letsencrypt会在证书在过期以前发送预告的通知邮件
  • –agree-tos 表示接受相关协议

使用webroot模式,Certbot在验证服务器域名的时候,会生成一个随机文件,然后Certbot的服务器会通过HTTP访问你的这个文件,因此要确保你的 Nginx 配置好,以便可以访问到这个文件。

因为默认LNMP的虚拟主机里是禁止 . 开头的隐藏文件及目录的,所以访问http://www.biaodianfu.com/.well-known/acme-challenge/**** 这个链接的话返回403错误,所以必须在nginx配置的server节点下添加

location ~ /.well-known {
    allow all;
}

最终的配置文件如下:

server {
    listen       80;
    server_name  biaodainfu.com www.biaodianfu.com;
    index index.html index.htm index.php;
    charset utf-8;
 
    root   /home/www/www.biaodianfu.com;
    
    location / {
        try_files $uri $uri/ =404;
    }
    error_page 404 /404.html;
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
        root /usr/share/nginx/html;
    }
 
    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_pass php-fpm;
        #fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
    
    location ~ .*.(gif|jpg|jpeg|png|bmp|swf|flv|mp3|wma)$
    {
        expires      30d;
    }
    
    location ~ .*.(js|css)$
    {
        expires      12h;
    }
	
    location ~ /.well-known {
        allow all;
    }
}

重新nginx后执行申请证书的操作,正常情况下可以看到如下的显示内容:

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at
   /etc/letsencrypt/live/www.biaodianfu.com/fullchain.pem. Your cert will
   expire on 2018-02-25. 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 lose your account credentials, you can recover through
   e-mails sent to biaodianfu@email.com.
 - Your account credentials have been saved in your Certbot
   configuration directory at /etc/letsencrypt. You should make a
   secure backup of this folder now. This configuration directory will
   also contain certificates and private keys obtained by Certbot so
   making regular backups of this folder is ideal.
 - 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

完成后,再配置nginx服务器,将服务器配置成支持https的访问。

server {
  listen 80;
  server_name biaodianfu.com www.biaodianfu.com;
  return 301 https://www.biaodianfu.com$request_uri;
}
 
server {
    listen 443 ssl http2;
    server_name  biaodainfu.com www.biaodianfu.com;
    index index.html index.htm index.php;
    charset utf-8;
 
    root   /home/www/www.biaodianfu.com;
 
    ssl_certificate /etc/letsencrypt/live/www.biaodianfu.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/www.biaodianfu.com/privkey.pem;
 
    location / {
        try_files $uri $uri/ /index.php?$args;
    }
 
    error_page 404 /404.html;
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
        root /usr/share/nginx/html;
    }
 
    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_pass php-fpm;
        #fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
    
    location ~ .*.(gif|jpg|jpeg|png|bmp|swf|flv|mp3|wma)$
    {
        expires      30d;
    }
    
    location ~ .*.(js|css)$
    {
        expires      12h;
    }
    
    location = /favicon.ico {
	log_not_found off;
	access_log off;
    }
    
    location ~ /.well-known {
        allow all;
    }
}

 

以上为一般的步骤与过程,现在在执行centos 7.2时并没有遇到什么问题,这次使用的是centos 7.4却发生了问题。

解决证书安装中的问题

问题一:ImportError: No module named ‘requests.packages.urllib3’

原因是系统自带的requests的版本太低,参照这个地址上的临时解决方案:

pip install requests urllib3 pyOpenSSL --force --upgrade

执行完引发第二个问题:ImportError: ‘pyOpenSSL’ module missing required functionality. Try upgrading to v0.14 or newer.

主要原因是RHEL/CentOS的官方源和epel源的pyOpenSSL版本太旧了,新版的certbot依赖于高版本的pyOpenSSL库,从而失败。

解决方案,卸载epel中的certbot和PyOpenSSL,使用pip进行安装certbot。

pip search certbot
yum remove certbot pyOpenSSL
pip install certbot

pip install certbot。 如果碰到了Python.h或者pyconfig.h找不到的错误,可以安装Python的devel包: yum install -y python-devel;再次运行命令,提示找不到opensslv.h头文件,再安装OpenSSL的devel包: yum install -y openssl-devel;再次运行pip install certbot命令,成功安装certbot。

完成后执行

certbot certificates
  进行验证。输出正常,说明pip安装了最新版的certbot,并且能正确运行。

证书的自动更新

由于这个证书的时效只有 90 天,我们需要设置自动更新的功能,帮我们自动更新证书的时效。首先先在命令行模拟证书更新:

certbot renew --dry-run

模拟更新成功的效果如下:

[root@iZuf64dhkm7u57qfwrrhw6Z ~]# certbot renew --dry-run
Saving debug log to /var/log/letsencrypt/letsencrypt.log
 
-------------------------------------------------------------------------------
Processing /etc/letsencrypt/renewal/www.biaodianfu.com.conf
-------------------------------------------------------------------------------
Cert not due for renewal, but simulating renewal for dry run
Plugins selected: Authenticator webroot, Installer None
Renewing an existing certificate
Performing the following challenges:
http-01 challenge for www.biaodianfu.com
Waiting for verification...
Cleaning up challenges
 
-------------------------------------------------------------------------------
new certificate deployed without reload, fullchain is
/etc/letsencrypt/live/www.biaodianfu.com/fullchain.pem
-------------------------------------------------------------------------------
 
-------------------------------------------------------------------------------
** DRY RUN: simulating 'certbot renew' close to cert expiry
**          (The test certificates below have not been saved.)
 
Congratulations, all renewals succeeded. The following certs have been renewed:
  /etc/letsencrypt/live/www.biaodianfu.com/fullchain.pem (success)
** DRY RUN: simulating 'certbot renew' close to cert expiry
**          (The test certificates above have not been saved.)
-------------------------------------------------------------------------------
 
IMPORTANT NOTES:
 - Your account credentials have been saved in your Certbot
   configuration directory at /etc/letsencrypt. You should make a
   secure backup of this folder now. This configuration directory will
   also contain certificates and private keys obtained by Certbot so
   making regular backups of this folder is ideal.
[root@iZuf64dhkm7u57qfwrrhw6Z ~]#

在无法确认你的 nginx 配置是否正确时,一定要运行模拟更新命令,确保certbot和服务器通讯正常。使用 crontab -e 的命令来启用自动任务,命令行:

crontab -e

添加配置:(每隔两个月凌晨2:30自动执行证书更新操作)后保存退出。

30 2 * */2 * /usr/bin/certbot renew --quiet && /bin/systemctl restart nginx

查看证书有效期的命令:

openssl x509 -noout -dates -in /etc/letsencrypt/live/www.biaodianfu.com/cert.pem

测试服务器 SSL 安全性

Qualys SSL Labs 提供了全面的 SSL 安全性测试,填写你的网站域名,给自己的 HTTPS 配置打个分。理想情况下得分是A+,如果你和我一样获得的是A-那么还有很多的改善空间。另外又扑云也有一个测试https的工具:www.upyun.com/https

相关改进:

1、生成Perfect Forward Security(PFS)键值

mkdir /etc/ssl/private/ -p
cd /etc/ssl/private/
openssl dhparam 2048 -out dhparam.pem

Perfect Forward Security(PFS),中文翻译成完美前向保密,2014年时候,由于心血漏洞(存在服务器私钥泄漏的可能),没有使用前向保密的站点,加密通信的数据可以通过私钥来解密,导致信息泄漏,这使得前向保密被重视起来。总的来说会更加安全,不能获得A+的评分主要原因也是因为它。(生成的时间有点长)

2、更新配置文件

# https://mozilla.github.io/server-side-tls/ssl-config-generator/
server {
    listen 80;
    server_name biaodianfu.com www.biaodianfu.com;
    return 301 https://www.biaodianfu.com$request_uri;
}
server {
    listen 443 ssl http2;
    server_name  biaodainfu.com www.biaodianfu.com;
    index index.html index.htm index.php;
    charset utf-8;
	
    add_header X-Frame-Options DENY;
    add_header X-Content-Type-Options nosniff;
 
    root   /home/www/www.biaodianfu.com;
 
    ssl_certificate /etc/letsencrypt/live/www.biaodianfu.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/www.biaodianfu.com/privkey.pem;
	
	ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;
    ssl_session_tickets off;
 
	# Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits
    ssl_dhparam /etc/ssl/private/dhparam.pem;
 
	# intermediate configuration. tweak to your needs.
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    # 一般推荐使用的ssl_ciphers值: https://wiki.mozilla.org/Security/Server_Side_TLS
    ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
    ssl_prefer_server_ciphers on;
	
    # HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months)
    add_header Strict-Transport-Security max-age=15768000;
	
    location / {
        try_files $uri $uri/ /index.php?$args;
    }
 
    error_page 404 /404.html;
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
        root /usr/share/nginx/html;
    }
 
    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_pass php-fpm;
        #fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
    
    location ~ .*.(gif|jpg|jpeg|png|bmp|swf|flv|mp3|wma)$
    {
        expires      30d;
    }
    
    location ~ .*.(js|css)$
    {
        expires      12h;
    }
    
    location = /favicon.ico {
	    log_not_found off;
	    access_log off;
    }
    
    location ~ /.well-known {
        allow all;
    }
}

其他参考:

打赏作者