Let’s Encrypt + Nginx + Tornado 开启 HTTPS

2,157 阅读2分钟

1. Let's Encrypt

需要开放 443 端口:

git clone https://github.com/letsencrypt/letsencrypt
cd letsencrypt
./letsencrypt-auto certonly -d pyhub.cc -d www.pyhub.cc

2. Nginx

# 重定向 HTTP
server {
    listen 80;
    server_name www.pyhub.cc pyhub.cc;
    rewrite ^(.*)$ https://$host$1 permanent;
}
# Tornado proxy
upstream pycc{
    server 127.0.0.1:8080;
}
server {
    listen 443;
    server_name pyhub.cc www.pyhub.cc;
    ssl on;
    ssl_certificate /etc/letsencrypt/live/pyhub.cc/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/pyhub.cc/privkey.pem;
    location / {
            proxy_pass_header Server;
            proxy_set_header Host $http_host;
            proxy_redirect off;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Scheme $scheme;
            proxy_pass http://pycc;
        }
}

Tornado

def main():
    # 设定 xheaders = True
    http_server = tornado.httpserver.HTTPServer(Application(), xheaders=True)
    http_server.listen(options.port)
    tornado.ioloop.IOLoop.current().start()

if __name__ == '__main__':
    main()

优化ssl配置

参考:Guide to Deploying Diffie-Hellman for TLS

执行:

openssl dhparam -out dhparams.pem 2048

经过相当长一段时间后生成 dhparams.pem,修改 Nginx 配置:

ssl on;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
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-EC
DSA-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:AES1
28-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
ssl_dhparam /etc/nginx/conf.d/dhparams.pem;

ssl_certificate /etc/letsencrypt/live/pyhub.cc/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/pyhub.cc/privkey.pem;

自动更新

官方给出了自动更新证书的脚本 https_renew.sh

#!/bin/sh
nginx -s stop  # or whatever your webserver is
/opt/letsencrypt/letsencrypt-auto renew -nvv --standalone --force-renewal > /var/log/letsencrypt/renew.log 2>&1
LE_STATUS=$?
nginx # or whatever your webserver is
if [ "$LE_STATUS" != 0 ]; then
    echo Automated renewal failed:
    cat /var/log/letsencrypt/renew.log
    exit 1
fi

加入 crontab

crontab -u root -e
* * */90 * * /path/to/https_renew.sh

2016-04-16 3 44 21

注意

页面中采用 http 的 CDN 服务会导致(Chrome)如下警告:
1 pic

One More Thing…

GitHub Webhook:

添加 Webhook 并监听 Push 事件,推送到服务器之后可以自动执行 git pull

# Application 设置开启 autoreload=True

class WebHookHandler(BaseHandler):
    def post(self, *args, **kwargs):
        if self.request.headers.get('X-GitHub-Event') == 'push':
            print("Execute git pull github master")
            subprocess.call("git pull github master", shell=True)