Python Tornado 建站流程:使用 Let’s Encrypt + Nginx 开启 HTTPS,结合 GitHub Webhook 实现自动部署。
1. Let’s Encrypt
需要开放 443 端口:
Python
git clone https://github.com/letsencrypt/letsencrypt
cd letsencrypt
./letsencrypt-auto certonly -d pyhub.cc -d www.pyhub.cc
1
2
3
git clone https://github.com/letsencrypt/letsencrypt
cd letsencrypt
./letsencrypt-auto certonly -d pyhub.cc -d www.pyhub.cc
2. Nginx
Python
# 重定向 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;
}
}
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
# 重定向 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
Python
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()
1
2
3
4
5
6
7
8
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
执行:
Python
openssl dhparam -out dhparams.pem 2048
1
openssl dhparam -out dhparams.pem 2048
经过相当长一段时间后生成 dhparams.pem,修改 Nginx 配置:
Python
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;
1
2
3
4
5
6
7
8
9
10
11
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:
Python
#!/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
1
2
3
4
5
6
7
8
9
10
#!/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:
Python
crontab -u root -e
* * */90 * * /path/to/https_renew.sh
1
2
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:
Python
# 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)
1
2
3
4
5
6
7
# 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)