给 Flask 项目启用 HTTPS

将Flask应用部署到 CentOS之后,我们可以为我们的 Flask 项目添加 HTTPS 支持。本文介绍如何给 Flask 项目添加 Let's Encrypt 的免费证书。

修改 nginx 配置文件

在《将Flask应用部署到 CentOS》一文中,该项目的 nginx 配置文件如下:

server {
    listen 80;
    server_name flasky.wrdll.com; # 改成你自己的域名

    location / {
                try_files $uri @flasky;
        }
        location @flasky {
                include /etc/nginx/uwsgi_params;
                uwsgi_pass unix:/var/www/flaksy/flasky.sock;
        }
}

我们需对其进行一次简单的修改:

server {
    listen 80;
    server_name flasky.wrdll.com; # 改成你自己的域名

    location ^~ /.well-known/acme-challenge/ {
       default_type "text/plain";
       root     /var/www/flasky-ssl;
    }

    location = /.well-known/acme-challenge/ {
       return 404;
    }

    location / {
        try_files $uri @flasky;
    }
    location @flasky {
        include /etc/nginx/uwsgi_params;
        uwsgi_pass unix:/var/www/flaksy/flasky.sock;
    }
}

在上面的修改中,添加了两条规则,这是用来验证网站所有权的。其中一条,我们指定了 root /var/www/flasky-ssl,所以,需要先创建这个目录:

mkdir -p /var/www/flasky-ssl
chown -R nginx:nginx /var/www/flasky-ssl

现在,重启 nginx ,使其生效:

nginx -t
nginx -s reload

使用 Certbot 获取并安装Let's Encrypt 的免费证书

你可以手动安装 Let's Encrypt 的免费证书,也可以使用 Certbot 等工具来自动安装。安装 Let's Encrypt 免费证书的工具很多,本文选用 Certbot——用 Python 开发的工具。

下载 Certbot

我们把 Certbot 下载到 /opt/soft 目录下:

mkdir -p /opt/soft
cd /opt/soft
wget https://dl.eff.org/certbot-auto # 如果没有 wget,请安装:yum install wget -y
chmod a+x ./certbot-auto

生成证书

certbot 生成证书的命令格式如下:

./certbot-auto certonly --webroot -w web路径 -d 域名1[,域名2,...域名n]
  • web路径:对于 Flask(和 Django)等 Python Web 项目而言,可以放置在其他目录;对于 PHP,可以放在 web 根目录。要保证和 nginx 里的 root 一致。
  • 域名:可以有多个域名,域名之间用逗号分割,比如:wrdll.com,www.wrdll.com

本例使用以下命令:(请将其中的 flasky.wrdll.com 换成你自己的域名)

./certbot-auto certonly --webroot -w /var/www/flasky-ssl -d flasky.wrdll.com

命令执行过程,需要输入你的 Email 地址。同时,会创建虚拟环境、安装所依赖的包,不用管他,耐心等待即可。

当看到 Congratulations 的提示时,表示证书生成成功,并告知证书放在 /etc/letsencrypt/live 目录下:

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at
   /etc/letsencrypt/live/flasky.wrdll.com/fullchain.pem. Your cert
   will expire on 2018-09-16. To obtain a new version of the
   certificate in the future, simply run Let's Encrypt again.

给 Flask 应用启用 HTTPS

证书生成成功后,我们需要修改 nginx 配置,以启用 HTTPS

修改 nginx 配置

server {
    listen 80;
    server_name flasky.wrdll.com; # 改成你自己的域名

    location ^~ /.well-known/acme-challenge/ {
       default_type "text/plain";
       root     /var/www/flasky-ssl;
    }

    location = /.well-known/acme-challenge/ {
       return 404;
    }

    location / {
        try_files $uri @flasky;
    }
    location @flasky {
        include /etc/nginx/uwsgi_params;
        uwsgi_pass unix:/var/www/flaksy/flasky.sock;
    }
}
server {
    listen 443 ssl;
    ssl on;
    server_name flasky.wrdll.com; # 改成你自己的域名

    ssl_certificate /etc/letsencrypt/live/flasky.wrdll.com/fullchain.pem; # 改成你自己的证书
    ssl_certificate_key /etc/letsencrypt/live/flasky.wrdll.com/privkey.pem; # 改成你自己的证书

    location / {
        try_files $uri @flasky;
    }
    location @flasky {
        include /etc/nginx/uwsgi_params;
        uwsgi_pass unix:/var/www/flaksy/flasky.sock;
    }
}

测试并重启 nginx

nginx -t
nginx -s reload

一切顺利的话,现在通过 http://flasky.wrdll.com 和 https://flasky.wrdll.com 都能访问我们的 Flask 项目了。

强制 HTTPS

既然开启了 HTTPS,安全性低的 HTTP 就没必要留了。我们应该把所有 HTTP 请求重定向到对应 HTTPS 请求里。为了能使用 Certbot 更新证书,.well-known 的两条规则还是保留的 HTTP 请求里。

server {
    listen 80;
    server_name flasky.wrdll.com; # 改成你自己的域名
    rewrite ^(.*)$  https://flasky.wrdll.com$1 permanent;

    location ^~ /.well-known/acme-challenge/ {
       default_type "text/plain";
       root     /var/www/flasky-ssl;
    }

    location = /.well-known/acme-challenge/ {
       return 404;
    }
}
server {
    listen 443 ssl;
    ssl on;
    server_name flasky.wrdll.com; # 改成你自己的域名

    ssl_certificate /etc/letsencrypt/live/flasky.wrdll.com/fullchain.pem; # 改成你自己的证书
    ssl_certificate_key /etc/letsencrypt/live/flasky.wrdll.com/privkey.pem; # 改成你自己的证书

    location / {
        try_files $uri @flasky;
    }
    location @flasky {
        include /etc/nginx/uwsgi_params;
        uwsgi_pass unix:/var/www/flaksy/flasky.sock;
    }
}

测试并重启 nginx:

nginx -t
nginx -s reload

至此,大功告成!

更新证书

Let's Encrypt 证书永久免费,但需要每隔 90 天更新一次证书。在证书需要更新时,Let's Encrypt 会发送一封邮件到你生成证书时输入的 Email 中提醒你进行更新。可以用下面的命令进行更新:

cd /opt/soft
./certbot-auto renew -v

更新完成后,重启一下 nginx:

nginx -s reload

你可以将以上命令写入一个脚本,然后通过 cron 定时执行,实现自动更新。

flask HTTPS Let's Encrypt Certbot 2018-06-18 16:15 4342861