如何在Ubuntu18.04上使用Gunicorn和Nginx提供Flask应用程序

来自菜鸟教程
跳转至:导航、​搜索

介绍

在本指南中,您将在 Ubuntu 18.04 上使用 Flask 微框架构建 Python 应用程序。 本文的大部分内容将介绍如何设置 Gunicorn 应用程序服务器 以及如何启动应用程序并配置 Nginx 作为前端反向代理。

先决条件

要完成本教程,您需要:

  • 安装了 Ubuntu 18.04 的服务器,具有 sudo 权限的非 root 用户,并启用了防火墙。 请按照我们的 初始服务器设置指南 获取指导。
  • 按照 如何在 Ubuntu 18.04 上安装 Nginx 的 步骤 1 和 2 安装 Nginx。
  • 配置为指向您的服务器的域名。 您可以在 Namecheap 上购买一个或在 Freenom 上免费获得一个。 您可以通过遵循有关域和 DNS 的相关 文档来了解如何将域指向 DigitalOcean。 请务必创建以下 DNS 记录:
    • 带有 your_domain 的 A 记录指向您服务器的公共 IP 地址。
    • 带有 www.your_domain 的 A 记录指向您服务器的公共 IP 地址。
  • 熟悉 WSGI 规范,Gunicorn 服务器将使用该规范与您的 Flask 应用程序进行通信。 这个讨论更详细地介绍了WSGI。

第 1 步 — 从 Ubuntu 存储库安装组件

第一步是从默认的 Ubuntu 存储库中安装所有必需的软件包。 这包括 Python 包管理器 pip,它将管理您的 Python 组件。 您还将获得构建某些 Gunicorn 组件所需的 Python 开发文件。

首先,更新本地包:

sudo apt update

然后安装允许您构建 Python 环境的软件包。 其中包括 python3-pip,以及其他一些强大的编程环境所需的包和开发工具:

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.6 -m venv myprojectenv

这会将 Python 和 pip 的本地副本安装到项目目录中名为 myprojectenv 的目录中。

在虚拟环境中安装应用程序之前,您需要通过运行以下命令来激活它:

source myprojectenv/bin/activate

您的提示将更改以指示您现在正在虚拟环境中操作。 它将如下所示:

(myprojectenv)\ssammy@host:~/myproject$

第 3 步 — 设置 Flask 应用程序

现在您已进入虚拟环境,您可以安装 Flask 和 Gunicorn 并开始设计您的应用程序。

首先,将 wheelpip 的本地实例一起安装,以确保即使您的软件包缺少车轮档案也能安装:

pip install wheel

注意:无论你使用的是哪个版本的Python,在激活虚拟环境时,都应该使用pip命令(不是pip3)。


接下来,安装 Flask 和 Gunicorn:

pip install gunicorn flask

现在您有了可用的 Flask,您可以在下一步中创建一个基本应用程序。

创建示例应用程序

由于 Flask 是一个微框架,它不包含功能更全的框架可能提供的许多工具。 Flask 主要作为一个模块存在,您可以将其导入到您的项目中以帮助初始化 Web 应用程序。

虽然您的应用程序可能更复杂,但我们将在一个名为 myproject.py 的文件中创建我们的 Flask 应用程序。 使用您喜欢的文本编辑器创建此文件; 这里我们将使用 nano

nano ~/myproject/myproject.py

应用程序代码将存在于该文件中。 它将导入 Flask 并实例化一个 Flask 对象。 您可以使用它来定义在请求特定路由时应运行的函数:

~/myproject/myproject.py

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')

这定义了访问根域时要呈现的内容。 完成后保存并关闭文件。 如果您使用的是 nano,您可以通过按 CTRL + X 然后按 YENTER 来执行此操作。

如果您遵循先决条件中的初始服务器设置指南,则应该启用 UFW 防火墙。 要测试应用程序,首先需要允许访问端口 5000

sudo ufw allow 5000

然后您可以通过运行以下命令来测试您的 Flask 应用程序:

python myproject.py

您将收到如下输出,包括一个有用的警告,提醒您不要在生产中使用此服务器设置:

Output * Serving Flask app 'myproject' (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on all addresses.
   WARNING: This is a development server. Do not use it in a production deployment.
 * Running on http://your_server_ip:5000/ (Press CTRL+C to quit)

在 Web 浏览器中访问服务器的 IP 地址,然后访问 :5000

http://your_server_ip:5000

您应该会收到如下内容:

完成后,在终端窗口中点击 CTRL + C 以停止 Flask 开发服务器。

创建 WSGI 入口点

接下来,创建一个文件作为应用程序的入口点。 这将告诉您的 Gunicorn 服务器如何与应用程序交互。

使用您喜欢的文本编辑器创建一个新文件并为其命名。 在这里,我们将调用文件 wsgi.py

nano ~/myproject/wsgi.py

在此文件中,从您的应用程序中导入 Flask 实例,然后运行它:

~/myproject/wsgi.py

from myproject import app

if __name__ == "__main__":
    app.run()

完成后保存并关闭文件。

第 4 步 — 配置 Gunicorn

您的应用程序现在已编写并建立了入口点,您可以继续配置 Gunicorn。

但首先,切换到适当的目录:

cd ~/myproject

接下来,您可以通过将入口点的名称传递给 Gunicorn 来检查 Gunicorn 是否可以正确地为应用程序提供服务。 这被构造为模块的名称(减去 .py 扩展名),加上应用程序中可调用的名称。 在我们的例子中,这被写为 wsgi:app

您还将指定要绑定的接口和端口,以便应用程序将在公开可用的接口上启动:

gunicorn --bind 0.0.0.0:5000 wsgi:app

您将收到如下输出:

Output[2021-11-19 23:07:57 +0000] [8760] [INFO] Starting gunicorn 20.1.0
[2021-11-19 23:07:57 +0000] [8760] [INFO] Listening at: http://0.0.0.0:5000 (8760)
[2021-11-19 23:07:57 +0000] [8760] [INFO] Using worker: sync
[2021-11-19 23:07:57 +0000] [8763] [INFO] Booting worker with pid: 8763
[2021-11-19 23:08:11 +0000] [8760] [INFO] Handling signal: int
[2021-11-19 23:08:11 +0000] [8760] [INFO] Shutting down: Master

再次在 Web 浏览器的末尾添加 :5000 访问服务器的 IP 地址:

http://your_server_ip:5000

您的应用程序的输出将生成以下内容:

当您确认它运行正常后,在您的终端窗口中按 CTRL + C

既然您已经完成了虚拟环境,请停用它:

deactivate

任何 Python 命令现在都将再次使用系统的 Python 环境。

接下来,创建 systemd 服务单元文件。 创建一个 systemd 单元文件将允许 Ubuntu 的 init 系统在服务器启动时自动启动 Gunicorn 并为 Flask 应用程序提供服务。

/etc/systemd/system目录下创建一个以.service结尾的单元文件开始:

sudo nano /etc/systemd/system/myproject.service

在里面,从 [Unit] 部分开始,它用于指定元数据和依赖项。 在此处添加对您的服务的描述,并告诉 init 系统仅在达到网络目标后才启动它:

/etc/systemd/system/myproject.service

[Unit]
Description=Gunicorn instance to serve myproject
After=network.target

接下来,创建一个 [Service] 部分。 这将指定您希望进程在其下运行的用户和组。 提供您对该进程的常规用户帐户所有权,因为它拥有所有相关文件。 此外,将组所有权授予 www-data 组,以便 Nginx 可以与 Gunicorn 进程通信。 请记住将此处的用户名替换为您的用户名:

/etc/systemd/system/myproject.service

[Unit]
Description=Gunicorn instance to serve myproject
After=network.target

[Service]
User=sammy
Group=www-data

接下来,绘制工作目录并设置 PATH 环境变量,以便 init 系统知道该进程的可执行文件位于您的虚拟环境中。 此外,指定启动服务的命令。 该命令将执行以下操作:

  • 启动 3 个工作进程(尽管您应该根据需要进行调整)
  • 在项目目录中创建并绑定到 Unix 套接字文件 myproject.sock
  • 设置 007 的 umask 值,以便创建套接字文件以授予所有者和组访问权限,同时限制其他访问权限
  • 指定 WSGI 入口点文件名,以及该文件中可调用的 Python (wsgi:app)

Systemd 要求您提供 Gunicorn 可执行文件的完整路径,该可执行文件安装在您的虚拟环境中。

请记住用您自己的信息替换用户名和项目路径:

/etc/systemd/system/myproject.service

[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 将该服务链接到什么。 您希望在常规多用户系统启动并运行时启动此服务:

/etc/systemd/system/myproject.service

[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
   Active: active (running) since Fri 2021-11-19 23:08:44 UTC; 6s ago
 Main PID: 8770 (gunicorn)
    Tasks: 4 (limit: 1151)
   CGroup: /system.slice/myproject.service
        ├─9291 /home/sammy/myproject/myprojectenv/bin/python3.6 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app
        ├─9309 /home/sammy/myproject/myprojectenv/bin/python3.6 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app
        ├─9310 /home/sammy/myproject/myprojectenv/bin/python3.6 /home/sammy/myproject/myprojectenv/bin/gunicorn --workers 3 --bind unix:myproject.sock -m 007 wsgi:app
        └─9311 /home/sammy/myproject/myprojectenv/bin/python3.6 /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。 另外,告诉它使用这个块来请求你的服务器域名:

/etc/nginx/sites-available/myproject

server {
    listen 80;
    server_name your_domain www.your_domain;
}

接下来,添加一个匹配每个请求的位置块。 在此块中,包含 proxy_params 文件,该文件指定了一些需要设置的通用代理参数。 然后将请求传递给您使用 proxy_pass 指令定义的套接字:

/etc/nginx/sites-available/myproject

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 目录。 您可以通过运行 ln 命令和 -s 标志来创建符号链接或 链接,而不是 硬链接

sudo ln -s /etc/nginx/sites-available/myproject /etc/nginx/sites-enabled

使用该目录中的链接,您可以测试语法错误:

sudo nginx -t

如果返回没有任何问题,请重新启动 Nginx 进程以读取新配置:

sudo systemctl restart nginx

最后,再次调整防火墙。 由于您不再需要通过端口 5000 访问,请删除该规则:

sudo ufw delete allow 5000

然后允许完全访问 Nginx 服务器:

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 获取免费证书、 生成自签名证书从另一个提供商处购买 并配置Nginx 按照 How to Create a Self-signed SSL Certificate for Nginx in Ubuntu 18.04 的步骤 2 到 6 来使用它。 为方便起见,我们将选择选项一。

首先,使用 snap 安装 Certbot:

sudo snap install --classic certbot

您的输出将显示 Certbot 的当前版本并指示安装成功:

Outputcertbot 1.21.0 from Certbot Project (certbot-eff✓) installed

接下来,从 /usr/bin/ 目录创建指向新安装的 /snap/bin/certbot 可执行文件的符号链接。 这将确保 certbot 命令可以在您的服务器上正确运行:

sudo ln -s /snap/bin/certbot /usr/bin/certbot

Certbot 提供了多种通过插件获取 SSL 证书的方式。 Nginx 插件将负责重新配置 Nginx 并在必要时重新加载配置。 要使用此插件,请键入以下内容:

sudo certbot --nginx -d your_domain -d www.your_domain

这将使用 --nginx 插件运行 certbot,使用 -d 指定您希望证书有效的名称。

如果这是您第一次运行 certbot,系统将提示您输入电子邮件地址并同意服务条款。 完成此操作后,certbot 将与 Let's Encrypt 服务器通信,为您的域请求证书。 如果成功,您将收到以下输出:

OutputSuccessfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/jeanellehorcasitasphd.com/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/jeanellehorcasitasphd.com/privkey.pem
This certificate expires on 2022-03-03.
These files will be updated when the certificate renews.
Certbot has set up a scheduled task to automatically renew this certificate in the background.

Deploying certificate
Successfully deployed certificate foryour_domain to /etc/nginx/sites-enabled/myproject
Successfully deployed certificate for your_domain to /etc/nginx/sites-enabled/myproject
Congratulations! You have successfully enabled HTTPS on https://your_domain and https://your_domain

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
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 是一个非常灵活的框架,旨在为您的应用程序提供功能,而不会对结构和设计进行过多限制。 您可以使用本指南中描述的通用堆栈来为您设计的烧瓶应用程序提供服务。