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