如何在CentOS7上使用uWSGI和Nginx部署Web2pyPython应用程序

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

介绍

web2py 框架是一个功能强大且易于使用的工具,用于快速开发功能齐全的 Python Web 应用程序。 使用 web2py,您可以通过使用管理 Web UI 轻松开发和管理您的应用程序。

在本指南中,我们将演示如何在 CentOS 7 上部署 web2py 应用程序。 我们将使用 uWSGI 应用程序服务器与具有多个工作进程的应用程序进行交互。 在 uWSGI 前面,我们将在反向代理配置中设置 Nginx 来处理实际的客户端连接。 这是一种比单独使用 web2py 服务器或 uWSGI 更强大的部署策略。

先决条件和目标

为了完成本指南,您应该拥有一个全新的 CentOS 7 服务器实例,该实例具有配置了 sudo 权限的非 root 用户。 您可以通过我们的 初始服务器设置指南 来了解如何设置它。

我们将下载 web2py 框架并对其进行测试,以确保默认应用程序环境正常运行。 之后,我们将下载并安装 uWSGI 应用程序容器,作为请求和 web2py Python 代码之间的接口。 我们将在此之前设置 Nginx,以便它可以处理客户端连接和对 uWSGI 的代理请求。 我们将配置我们的每个组件以在启动时启动,以最大限度地减少管理干预的需要。

下载 web2py 框架

我们的第一步是下载实际的 web2py 框架。 这是在 GitHub 上的 git 存储库中维护的,因此下载它的最佳方式是使用 git 本身。

我们可以通过键入以下命令从默认的 CentOS 存储库下载并安装 git

sudo yum install git

安装 git 后,我们可以将存储库克隆到用户的主目录。 我们可以随意命名应用程序。 在我们的示例中,为简单起见,我们使用名称 myapp。 我们需要添加 --recursive 标志,因为数据库抽象层作为其自己的 git 子模块处理:

git clone --recursive https://github.com/web2py/web2py.git ~/myapp

web2py 框架将被下载到您的主目录中名为 myapp 的目录中。

我们可以通过移动到目录来测试默认应用程序:

cd ~/myapp

管理界面必须由 SSL 保护,因此我们可以制作一个简单的自签名证书来测试这一点。 通过键入以下内容创建服务器密钥和证书:

openssl req -x509 -new -newkey rsa:4096 -days 3652 -nodes -keyout myapp.key -out myapp.crt

您必须为要生成的证书填写一些信息。 在这种情况下,唯一真正重要的部分是 Common Name 字段,它应该引用您服务器的域名或 IP 地址:

. . .

Country Name (2 letter code) [AU]:US
State or Province Name (full name) [Some-State]:New York
Locality Name (eg, city) []:New York City
Organization Name (eg, company) [Internet Widgits Pty Ltd]:DigitalOcean
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:server_domain_or_IP
Email Address []:admin@email.com

完成后,SSL 密钥和证书应该在您的应用程序目录中。 这些将分别称为 myapp.keymyapp.crt

完成后,我们可以启动 web2py Web 界面来测试它。 为此,我们可以键入:

python web2py.py -k myapp.key -c myapp.crt -i 0.0.0.0 -p 8000

系统将要求您选择管理界面的密码。

现在,您可以在 Web 浏览器中访问您的应用程序,方法是导航到:

https://server_domain_or_IP:8000

确保在上述地址中使用 https 而不是 http。 您将收到警告,您的浏览器无法识别 SSL 证书:

这是意料之中的,因为我们已经签署了自己的证书。 单击“高级”链接或浏览器提供的任何其他链接,然后按计划继续访问该站点。 您将看到 web2py 界面:

通过点击最右侧的“管理界面”按钮,您应该能够输入您在运行服务器时选择的密码并进入管理站点:

这使您可以访问运行应用程序的实际代码,允许您从界面本身编辑和调整文件。

环顾四周后,在终端窗口中键入 CTRL-C。 我们已经测试了我们的应用程序,并证明当 web2py 开发服务器运行时,它可以在 Web 上访问。

安装和配置 uWSGI

现在我们已经可以运行 web2py 应用程序,我们可以配置 uWSGI。 uWSGI 是一个应用服务器,可以通过称为 WSGI 的标准接口与应用程序进行通信。 要了解更多信息,请阅读我们在 Ubuntu 14.04 上设置 uWSGI 和 Nginx 指南的 本节

安装 uWSGI

与上面链接的指南不同,在本教程中,我们将全局安装 uWSGI。 在我们安装 uWSGI 之前,我们需要安装 pip、Python 包管理器和 uWSGI 所依赖的 Python 开发文件。 我们还需要一个编译器来构建实际的二进制文件。 要获得 pip,我们必须使用包含额外包的 EPEL 存储库。

我们可以通过键入以下内容来激活 EPEL 存储库:

sudo yum install epel-release

之后,我们可以通过键入来安装我们需要的包

sudo yum install python-devel python-pip gcc

现在我们可以通过输入 pip 全局安装 uWSGI:

sudo pip install uwsgi

uWSGI 应用程序容器服务器使用 WSGI 接口规范与 Python 应用程序接口。 web2py 框架在其 handlers 目录中包含一个旨在提供此接口的文件。 要使用该文件,我们需要将其移出目录并进入主项目目录:

mv ~/myapp/handlers/wsgihandler.py ~/myapp

使用主项目目录中的 WSGI 处理程序,我们可以通过键入以下内容来检查 uWSGI 是否能够为应用程序提供服务:

uwsgi --http :8000 --chdir ~/myapp -w wsgihandler:application

这应该会在端口 8000 上再次启动应用程序。 这一次,由于我们没有使用 SSL 证书和密钥,它将通过纯 HTTP 而不是 HTTPS 提供服务。 您可以使用 http 协议在浏览器中再次进行测试。 您将无法测试管理界面,因为 web2py 在加密不可用时会禁用此功能。

完成后,在终端窗口中键入 CTRL-C 以停止服务器。

创建 uWSGI 配置文件

现在我们知道 uWSGI 可以为应用程序提供服务,我们可以使用应用程序的信息创建一个 uWSGI 配置文件。

/etc/uwsgi/sites 创建一个目录来存储我们的配置,然后进入该目录:

sudo mkdir -p /etc/uwsgi/sites
cd /etc/uwsgi/sites

我们将调用我们的配置文件 myapp.ini

sudo nano myapp.ini

在配置文件中,我们需要从一个 [uwsgi] 标题开始,我们所有的配置指令都将放置在该标题下。 在标头之后,我们将指示应用程序的目录路径,并告诉它要执行的模块。 这将与我们之前在命令行中使用的信息相同。 您不需要修改模块行:

[uwsgi]
chdir = /home/user/myapp
module = wsgihandler:application

接下来,我们需要指定我们希望 uWSGI 在主模式下运行。 我们想产生五个工作进程:

[uwsgi]
chdir = /home/user/myapp
module = wsgihandler:application

master = true
processes = 5

接下来,我们需要指定我们希望 uWSGI 如何获取连接。 在我们对 uWSGI 服务器的测试中,我们接受了正常的 HTTP 连接。 但是,由于我们将在 uWSGI 之前将 Nginx 配置为反向代理,因此我们还有其他选择。

我们可以使用 Unix 套接字,而不是使用网络端口,因为所有组件都在单个服务器上运行。 这更安全并提供更好的性能。 这个套接字不会使用 HTTP,而是实现 uWSGI 的 uwsgi 协议,这是一种快速二进制协议,设计用于与其他服务器通信。 Nginx 可以使用 uwsgi 协议进行原生代理,所以这是我们最好的选择。

我们需要将运行进程的用户设置为我们自己的用户,因为我们拥有这些文件。 我们还将修改套接字的权限和所有权,因为我们将授予 Web 服务器写入权限。 套接字本身将放置在 /run/uwsgi 目录中(稍后我们将创建此目录),uWSGI 和 Nginx 都可以访问它。 我们将设置 Vacuum 选项,以便在服务停止时自动清理套接字文件:

[uwsgi]
chdir = /home/user/myapp
module = wsgihandler:application

master = true
processes = 5

uid = user
socket = /run/uwsgi/myapp.sock
chown-socket = user:nginx
chmod-socket = 660
vacuum = true

我们的 uWSGI 配置文件现在已经完成。 保存并关闭文件。

为 uWSGI 创建一个 Systemd 单元文件

我们已经为 uWSGI 创建了一个配置文件,但是我们还没有将我们的应用服务器设置为在启动时自动启动。 为了实现这个功能,我们可以创建一个 Systemd 单元文件。

我们将在保存用户创建的单元文件的 /etc/systemd/system 目录中创建单元文件。 我们将调用我们的文件 uwsgi.service

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

[Unit] 部分开始,该部分用于指定元数据。 我们将在这里简单地描述我们的服务:

[Unit]
Description=uWSGI Emperor service

接下来,我们将打开 [Service] 部分。 我们将使用 ExecStartPre 指令来设置运行服务器所需的部分。 这将确保创建 /run/uwsgi 目录,并且我们的普通用户拥有它,并且 Nginx 组作为组所有者。 带有 -p 标志的 mkdir 和 chown 命令都成功返回,即使它们已经存在。 这就是我们想要的。

对于由 ExecStart 指令指定的实际启动命令,我们将指向 uwsgi 可执行文件。 我们将告诉它以“Emperor 模式”运行,允许它使用它在 /etc/uwsgi/sites 中找到的文件来管理多个应用程序。 我们还将添加 Systemd 正确管理流程所需的部分。 这些取自uWSGI文档here

[Unit]
Description=uWSGI Emperor service

[Service]
ExecStartPre=/usr/bin/bash -c 'mkdir -p /run/uwsgi; chown user:nginx /run/uwsgi'
ExecStart=/usr/bin/uwsgi --emperor /etc/uwsgi/sites
Restart=always
KillSignal=SIGQUIT
Type=notify
NotifyAccess=all

现在,我们需要做的就是添加 [Install] 部分。 这允许我们指定何时应该自动启动服务。 我们将把我们的服务绑定到多用户系统状态。 每当系统为多个用户设置(正常运行条件)时,我们的服务将被激活:

[Unit]
Description=uWSGI Emperor service

[Service]
ExecStartPre=/usr/bin/bash -c 'mkdir -p /run/uwsgi; chown user:nginx /run/uwsgi'
ExecStart=/usr/bin/uwsgi --emperor /etc/uwsgi/sites
Restart=always
KillSignal=SIGQUIT
Type=notify
NotifyAccess=all

[Install]
WantedBy=multi-user.target

完成此操作后,保存并关闭文件。

此时我们将无法成功启动服务,因为它依赖于可用的 nginx 用户。 我们将不得不等到安装 Nginx 之后才能启动 uWSGI 服务。

安装和配置 Nginx 作为反向代理

配置好 uWSGI 并准备就绪后,我们现在可以安装和配置 Nginx 作为我们的反向代理。 这可以通过输入 yum 下载:

sudo yum install nginx

安装 Nginx 后,我们可以继续修改服务器块配置。 我们将编辑主要的 Nginx 配置文件:

sudo nano /etc/nginx/nginx.conf

web2py 应用程序会检测您是使用纯 HTTP 还是使用 SSL 加密进行连接。 因此,我们的文件实际上将包含每个服务器块。 我们将从配置为在端口 80 上运行的服务器块开始。

更改 server_name 以引用您的站点应该可以访问的域名或 IP 地址。 之后,我们将创建一个 location {} 块来匹配静态内容的请求。 基本上,我们希望使用正则表达式来匹配以 /static/ 结尾的请求和前面的路径组件。 我们希望将这些请求映射到 web2py 项目中的 applications 目录。 确保引用用户的主目录和应用名称:

server {
    listen                  80 default_server;
    server_name             server_domain_or_IP;
    root                    /usr/share/nginx/html;

    include /etc/nginx/default.d/*.conf;

    location ~* /(\w+)/static/ {
        root /home/user/myapp/applications/;
    }

    . . .

之后,我们需要调整 location / {} 块以将请求传递到我们的 uWSGI 套接字。 我们只需要包含用 Nginx 打包的 uWSGI 参数文件,并将请求传递给我们配置的套接字(在我们的 uWSGI .ini 文件中):

server {
    listen                  80 default_server;
    server_name             server_domain_or_IP;
    root                    /usr/share/nginx/html;

    include /etc/nginx/default.d/*.conf;

    location ~* /(\w+)/static/ {
        root /home/user/myapp/applications/;
    }

    location / {
        include uwsgi_params;
        uwsgi_pass unix:/home/user/myapp/myapp.sock;
    }
}

    . . .

这将是我们第一个服务器块所需的全部内容。

在文件的底部,但在结束的 http {} 块括号内,制作另一个 server {} 块。 我们将使用它来配置 SSL 连接。

从基础开始。 此服务器块将侦听端口 443(默认 SSL 端口)上的连接。 我们将设置服务器的域名或 IP 地址,就像我们为端口 80 服务器块所做的那样。 要开始实际的 SSL 配置,我们将为此块指定 SSL 应该打开,并且我们将指示 SSL 证书的路径和应该用于加密连接的密钥。 我们将暂时将文件移动到那里:

http {
    . . .
    server {
        listen 80;
        . . .
    }
    server {
        listen 443;
        server_name server_domain_or_IP;

        ssl on;
        ssl_certificate /etc/nginx/ssl/myapp.crt;
        ssl_certificate_key /etc/nginx/ssl/myapp.key;
    }
}

我们将继续使用一些 SSL 样板来建立可接受的协议和密码。 之后,我们可以设置我们在端口 80 服务器块中配置的相同的 location / {} 块:

http {
    . . .
    server {
        listen 80;
        . . .
    }
    server {
        listen 443;
        server_name server_domain_or_IP;

        ssl on;
        ssl_certificate /etc/nginx/ssl/myapp.crt;
        ssl_certificate_key /etc/nginx/ssl/myapp.key;

        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers "HIGH:!aNULL:!MD5 or HIGH:!aNULL:!MD5:!3DES";
        ssl_prefer_server_ciphers on;

        location / {
            include uwsgi_params;
            uwsgi_pass unix:/run/uwsgi/myapp.sock;
        }
    }
}

您现在应该在此文件中配置了两个服务器块。 完成后保存并关闭它。

最后的步骤

接下来,我们需要将 SSL 证书移动到我们指定的目录。 首先创建目录:

sudo mkdir -p /etc/nginx/ssl

现在,将您创建的证书和密钥移动到该目录。 如果您拥有由商业证书颁发机构签署的 SSL 证书,您可以在此处替换证书和相应的密钥,以避免访问者收到不受信任的 SSL 证书警告:

sudo mv ~/myapp/myapp.crt /etc/nginx/ssl
sudo mv ~/myapp/myapp.key /etc/nginx/ssl

修改权限,使非 root 用户无法访问该目录:

sudo chmod 700 /etc/nginx/ssl

nginx 用户必须有权访问我们的应用程序目录,以便它可以根据需要直接提供静态文件。 CentOS 非常严格地锁定每个用户的主目录,因此我们将 nginx 用户添加到我们的用户组,这样我们就可以打开使其运行所需的最低权限。

通过键入此命令将 nginx 用户添加到您的组。 在以下命令中用您的用户名替换 user

sudo usermod -a -G user nginx

现在,我们将授予我们的用户组对目录的执行权限,这将允许 Nginx 进程进入和访问其中的内容:

chmod 710 /home/user

现在,检查你的 Nginx 配置文件是否有语法错误:

sudo nginx -t

如果没有报告语法错误,我们可以继续启动 Nginx:

sudo service nginx start

我们也可以启动我们的 uWSGI 服务:

sudo service uwsgi start

我们需要做的最后一件事是复制应用程序的参数文件,以便在端口 443 上提供连接时可以正确读取该文件。 这包含我们为管理界面配置的密码。 我们只需要将其复制到一个新名称,该名称指示端口 443 而不是端口 8000:

cp ~/myapp/parameters_8000.py ~/myapp/parameters_443.py

这样,您应该能够使用服务器的域名或 IP 地址访问您的服务器。 如果您想登录管理界面,请使用 https

如果一切顺利,您可以通过键入以下命令启用 Nginx 和 uWSGI 在启动时启动:

sudo systemctl enable nginx
sudo systemctl enable uwsgi

结论

在本指南中,我们设置了一个示例 web2py 项目来练习部署。 我们已经将 uWSGI 配置为我们的应用程序和客户端请求之间的接口。 然后我们在 uWSGI 前面设置 Nginx 以允许 SSL 连接并有效地处理客户端请求。

web2py 项目从一开始就提供了一个可行的 Web 界面,从而简化了站点和 Web 应用程序的开发。 通过利用本文中描述的通用工具链,您可以轻松地为您从单个服务器创建的应用程序提供服务。