介绍
在本指南中,您将使用 Ubuntu 20.04 上的 Flask 微框架构建一个 Python 应用程序。本文的大部分内容将是如何设置 Gunicorn 应用程序服务器以及如何启动应用程序并配置 Nginx作为前端反向代理。
前提条件
在开始本指南之前,你应该:
- 安装了 Ubuntu 20.04 的服务器和具有 sudo 特权的非 root 用户。 遵循我们的 初始服务器设置指南以获取指导。
- Nginx 安装,遵循 How To Install Nginx on Ubuntu 20.04 的步骤 1 和 2)。 配置的域名以指向您的服务器。 您可以在 Namecheap上购买一个或在 Freenom上免费获得一个。 您可以通过遵循相关的 Domain 和 DNS 文档来学习如何将域名指向 DigitalOcean。 您的服务器的公共 IP 地址指向您的 DNS 记录: _M
步骤 1 – 从 Ubuntu 存储库中安装组件
我们的第一步将是从Ubuntu存储库中安装我们需要的所有部件,这包括Python包管理器pip
,它将管理我们的Python组件,我们还将获得构建一些Gunicorn组件所需的Python开发文件。
首先,让我们更新本地包索引并安装允许我们构建我们的Python环境的包,这些包将包括python3-pip
,以及一些对强大的编程环境所必需的包和开发工具:
1sudo apt update
2sudo apt install python3-pip python3-dev build-essential libssl-dev libffi-dev python3-setuptools
有了这些包,让我们继续为我们的项目创造一个虚拟环境。
第2步:创建一个Python虚拟环境
接下来,我们将设置一个虚拟环境,以便将我们的Flask应用程序与系统上的其他Python文件隔离。
开始安装python3-venv
包,该包将安装venv
模块:
1sudo apt install python3-venv
接下来,让我们为我们的 Flask 项目创建一个家长目录,然后在您创建后移动到目录中:
1mkdir ~/myproject
2cd ~/myproject
创建一个虚拟环境来存储您的 Flask 项目的 Python 要求,键入:
1python3 -m venv myprojectenv
这将安装Python的本地副本和pip
到项目目录中的名为myprojectenv
的目录中。
在在虚拟环境中安装应用程序之前,您需要激活它。
1source myprojectenv/bin/activate
您的提示将更改,表示您现在在虚拟环境中运行,它将看起来像这样: (myprojectenv)user@host:~/myproject$
。
步骤 3 – 设置一个Flask应用程序
现在你已经在你的虚拟环境中,你可以安装Flask和Gunicorn,并开始设计你的应用程序。
首先,让我们用pip
的本地实例安装轮子
,以确保我们的包即使它们缺少轮子档案,也会安装:
1pip install wheel
<$>[注]
[标签注]
无论您正在使用哪个版本的 Python,当虚拟环境被激活时,您应该使用pip
命令(而不是pip3
)。
接下来,让我们安装Flask和Gunicorn:
1pip install gunicorn flask
创建样本应用程序
现在你有Flask可用,你可以创建一个简单的应用程序. Flask是一个微框架. 它不包括更多的功能框架可能的许多工具,并且主要是作为一个模块,你可以导入到你的项目,以帮助你初始化一个Web应用程序。
虽然您的应用程序可能更复杂,但我们将创建我们的 Flask 应用程序在一个文件中,称为 myproject.py
:
1nano ~/myproject/myproject.py
应用程序代码将生活在这个文件中. 它将导入Flask并实例化Flask对象. 您可以使用此功能来定义需要执行特定路径时的函数:
1[label ~/myproject/myproject.py]
2from flask import Flask
3app = Flask(__name__)
4
5@app.route("/")
6def hello():
7 return "<h1 style='color:blue'>Hello There!</h1>"
8
9if __name__ == "__main__":
10 app.run(host='0.0.0.0')
这基本上定义了在访问根域时要呈现的内容。
如果您遵循初始服务器设置指南,则应启用 UFW 防火墙. 要测试该应用程序,您需要允许访问端口 5000
:
1sudo ufw allow 5000
现在你可以通过键入测试你的Flask应用程序:
1python myproject.py
您将看到如下输出,包括一个有用的警告,提醒您不要在生产中使用此服务器设置:
1[secondary_label Output]
2* Serving Flask app "myproject" (lazy loading)
3 * Environment: production
4 WARNING: Do not use the development server in a production environment.
5 Use a production WSGI server instead.
6 * Debug mode: off
7 * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
请访问您的服务器的 IP 地址,然后在您的 Web 浏览器中:5000
:
1http://your_server_ip:5000
你应该看到这样的东西:
当你完成时,在终端窗口中按CTRL-C
,停止Flask开发服务器。
创建 WSGI 入口点
接下来,让我们创建一个文件,它将作为我们的应用程序的入口点. 这将告诉我们的Gunicorn服务器如何与应用程序进行交互。
让我们把文件叫做wsgi.py:
1nano ~/myproject/wsgi.py
在此文件中,让我们从我们的应用程序中导入Flask实例,然后运行它:
1[label ~/myproject/wsgi.py]
2from myproject import app
3
4if __name__ == "__main__":
5 app.run()
保存并关闭文件,当你完成。
步骤 4 – 配置 Gunicorn
您的应用程序现在已经创建了一个入口点,我们现在可以继续配置Gunicorn。
在继续前,我们应该检查 Gunicorn 是否能够正确地服务应用程序。
我们可以这样做,简单地传递我们的入口点的名称,这是构建为模块的名称(减.py
扩展),加上应用程序内可呼叫的名称,在我们的情况下,这是wsgi:app
。
我们还将指定接口和端口,以便应用程序在公开可用的接口上启动:
1cd ~/myproject
2gunicorn --bind 0.0.0.0:5000 wsgi:app
你应该看到的输出如下:
1[secondary_label Output]
2[2020-05-20 14:13:00 +0000] [46419] [INFO] Starting gunicorn 20.0.4
3[2020-05-20 14:13:00 +0000] [46419] [INFO] Listening at: http://0.0.0.0:5000 (46419)
4[2020-05-20 14:13:00 +0000] [46419] [INFO] Using worker: sync
5[2020-05-20 14:13:00 +0000] [46421] [INFO] Booting worker with pid: 46421
再次访问您的服务器的 IP 地址,在您的 Web 浏览器的末端附加:5000
:
1http://your_server_ip:5000
您应该看到您的应用程序的输出:
当您确认它正常工作时,请在终端窗口中按CTRL-C
。
我们现在已经完成了我们的虚拟环境,所以我们可以禁用它:
1deactivate
任何 Python 命令现在都将再次使用系统的 Python 环境。
创建一个 systemd 单元文件将允许 Ubuntu 的 init 系统自动启动 Gunicorn 并在服务器启动时为 Flask 应用程序提供服务。
在/etc/systemd/system
目录中创建一个终止在.service
的单元文件,开始:
1sudo nano /etc/systemd/system/myproject.service
内部,我们将从[单位]
部分开始,该部分用于指定元数据和依赖性,让我们在这里列出我们的服务的描述,并告诉 init 系统在实现网络目标后才启动:
1[label /etc/systemd/system/myproject.service]
2[Unit]
3Description=Gunicorn instance to serve myproject
4After=network.target
接下来,让我们打开[服务]
部分。这将指定我们希望该过程运行的用户和组。让我们给我们的常规用户帐户拥有这个过程,因为它拥有所有相关的文件。让我们还给www-data
组一个组所有权,这样 Nginx 就可以轻松地与 Gunicorn 流程进行通信。 请记住,在这里用你的用户名更换用户名:
1[label /etc/systemd/system/myproject.service]
2[Unit]
3Description=Gunicorn instance to serve myproject
4After=network.target
5
6[Service]
7User=sammy
8Group=www-data
接下来,让我们绘制工作目录并设置PATH
环境变量,以便 init 系统知道该过程的可执行程序位于我们的虚拟环境中。
- 启动 3 个工人进程(虽然你应该根据需要调整)
- 在我们的项目目录中创建并将其绑定到一个 Unix 接口文件,
myproject.sock
. 我们将设置一个 umask 值为007
,以便创建接口文件,为所有者和组提供访问,同时限制其他访问 - 指定 WSGI 入口点文件名,以及该文件中的 Python 可调用(
wsgi:app
)
Systemd 要求我们为 Gunicorn 执行程序提供完整的路径,该路径安装在我们的虚拟环境中。
请记住用自己的信息替换用户名和项目路径:
1[label /etc/systemd/system/myproject.service]
2[Unit]
3Description=Gunicorn instance to serve myproject
4After=network.target
5
6[Service]
7User=sammy
8Group=www-data
9WorkingDirectory=/home/sammy/myproject
10Environment="PATH=/home/sammy/myproject/myprojectenv/bin"
11ExecStart=/home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app
最后,让我们添加一个[安装]
部分,这将告诉系统d如果我们允许该服务在启动时启动,该服务将连接到什么。
1[label /etc/systemd/system/myproject.service]
2[Unit]
3Description=Gunicorn instance to serve myproject
4After=network.target
5
6[Service]
7User=sammy
8Group=www-data
9WorkingDirectory=/home/sammy/myproject
10Environment="PATH=/home/sammy/myproject/myprojectenv/bin"
11ExecStart=/home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app
12
13[Install]
14WantedBy=multi-user.target
这样,我们的 systemd 服务文件就完成了. 现在保存并关闭它。
我们现在可以启动我们创建的Gunicorn服务,并启用它,以便它在启动时开始:
1sudo systemctl start myproject
2sudo systemctl enable myproject
让我们来看看状态:
1sudo systemctl status myproject
你应该看到这样的输出:
1[secondary_label Output]
2● myproject.service - Gunicorn instance to serve myproject
3 Loaded: loaded (/etc/systemd/system/myproject.service; enabled; vendor preset: enabled)
4 Active: active (running) since Wed 2020-05-20 14:15:18 UTC; 1s ago
5 Main PID: 46430 (gunicorn)
6 Tasks: 4 (limit: 2344)
7 Memory: 51.3M
8 CGroup: /system.slice/myproject.service
9 ├─46430 /home/sammy/myproject/myprojectenv/bin/python3 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app
10 ├─46449 /home/sammy/myproject/myprojectenv/bin/python3 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app
11 ├─46450 /home/sammy/myproject/myprojectenv/bin/python3 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app
12 └─46451 /home/sammy/myproject/myprojectenv/bin/python3 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app
如果您看到任何错误,请确保在继续使用教程之前解决它们。
步骤 5 — 将 Nginx 配置为代理请求
我们的 Gunicorn 应用程序服务器现在应该运行,在项目目录中等待接口文件上的请求。
首先,在 Nginx 的可用网站
目录中创建一个新的服务器封锁配置文件,让我们把这个文件称为myproject
,以保持与其他指南相符:
1sudo nano /etc/nginx/sites-available/myproject
打开一个服务器块,并告诉 Nginx 倾听默认端口 80。
1[label /etc/nginx/sites-available/myproject]
2server {
3 listen 80;
4 server_name your_domain www.your_domain;
5}
接下来,让我们添加一个匹配每个请求的位置块。在这个块中,我们将包括指定一些需要设置的一般代理参数的 proxy_params
文件。
1[label /etc/nginx/sites-available/myproject]
2server {
3 listen 80;
4 server_name your_domain www.your_domain;
5
6 location / {
7 include proxy_params;
8 proxy_pass http://unix:/home/sammy/myproject/myproject.sock;
9 }
10}
保存并关闭文件,当你完成。
要启用您刚刚创建的 Nginx 服务器封锁配置,请将文件链接到网站启用
目录:
1sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled
使用该目录中的文件,您可以测试语法错误:
1sudo nginx -t
如果返回不表示任何问题,请重新启动 Nginx 流程以阅读新配置:
1sudo systemctl restart nginx
最后,让我们重新调整防火墙,我们不再需要通过端口5000
访问,所以我们可以删除这个规则,然后我们可以允许完全访问 Nginx 服务器:
1sudo ufw delete allow 5000
2sudo ufw allow 'Nginx Full'
您现在应该能够在您的 Web 浏览器中导航到您的服务器的域名:
1http://your_domain
您应该看到您的应用程序的输出:
如果您遇到任何错误,请尝试检查以下情况:
sudo less /var/log/nginx/error.log
:检查 Nginx 错误日志.sudo less /var/log/nginx/access.log
:检查 Nginx 访问日志.sudo journalctl -u nginx
:检查 Nginx 进程日志.sudo journalctl -u myproject
:检查您的 Flask 应用程序的 Gunicorn 日志.
步骤 6 – 确保应用程序
要确保到您的服务器的流量保持安全,让我们为您的域获得一个SSL证书。有几种方法可以做到这一点,包括从 Let's Encrypt获得免费证书, 生成自签证书,或 从其他提供商购买一个并通过遵循步骤2到6的如何在Ubuntu 20.04中创建自签 SSL证书来配置 Nginx使用它。
安装 Certbot 的 Nginx 包,使用apt
:
1sudo apt install python3-certbot-nginx
Certbot 提供了通过插件获取 SSL 证书的多种方式。 Nginx 插件将负责重新配置 Nginx 并在必要时重新加载配置。
1sudo certbot --nginx -d your_domain -d www.your_domain
这将运行certbot
与--nginx
插件,使用-d
来指定我们希望证书有效的名称。
如果这是你第一次运行certbot
,你将被要求输入电子邮件地址并同意服务条款. 这样做后,certbot
将与 Let’s Encrypt 服务器进行通信,然后运行一个挑战,以验证你控制的域,你正在请求证书。
如果成功,certbot 会问你想如何配置你的 HTTPS 设置:
1[secondary_label Output]
2Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
3-------------------------------------------------------------------------------
41: No redirect - Make no further changes to the webserver configuration.
52: Redirect - Make all requests redirect to secure HTTPS access. Choose this for
6new sites, or if you're confident your site works on HTTPS. You can undo this
7change by editing your web server's configuration.
8-------------------------------------------------------------------------------
9Select the appropriate number [1-2] then [enter] (press 'c' to cancel):
选择你的选择,然后点击ENTER
。配置将被更新,Nginx将重新加载以获取新的设置。
1[secondary_label Output]
2IMPORTANT NOTES:
3 - Congratulations! Your certificate and chain have been saved at:
4 /etc/letsencrypt/live/your_domain/fullchain.pem
5 Your key file has been saved at:
6 /etc/letsencrypt/live/your_domain/privkey.pem
7 Your cert will expire on 2020-08-18. To obtain a new or tweaked
8 version of this certificate in the future, simply run certbot again
9 with the "certonly" option. To non-interactively renew *all* of
10 your certificates, run "certbot renew"
11 - Your account credentials have been saved in your Certbot
12 configuration directory at /etc/letsencrypt. You should make a
13 secure backup of this folder now. This configuration directory will
14 also contain certificates and private keys obtained by Certbot so
15 making regular backups of this folder is ideal.
16 - If you like Certbot, please consider supporting our work by:
17
18 Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
19 Donating to EFF: https://eff.org/donate-le
如果您在前提条件中遵循了 Nginx 安装说明,您将不再需要多余的 HTTP 配置文件许可:
1sudo ufw delete allow 'Nginx HTTP'
要验证配置,请再次导航到您的域名,使用 https://
:
1https://your_domain
您应该再次看到您的应用程序输出,以及浏览器的安全指标,这应该表明该网站是安全的。
结论
在本指南中,您创建并在Python虚拟环境中保护了一个简单的Flask应用程序。您创建了一个WSGI入口点,以便任何具有WSGI能力的应用程序服务器可以与其进行交互,然后配置了Gunicorn应用程序服务器以提供此功能。
Flask 是一个非常简单但非常灵活的框架,旨在为您的应用提供功能,而不会过于限制结构和设计。