Django 是一个免费且开源的 Web 应用程序框架,构建于 Python 编程语言。Django 速度极快、安全且具有高度可扩展性。在熟练的开发人员手中,Django 可以快速建立一个功能强大的网站。它可以与流行的 Web 服务器(Apache, Nginx)和数据库(MySQL, MariaDB, PostgreSQL, Oracle、以及 SQLite)等无缝集成。Django 为世界上一些最大的网站提供支持,例如 Instagram、Mozilla 和 NASA。本指南演示了如何在 Ubuntu 20.04 上借助 Django、PostgreSQL、Nginx 和 Gunicorn 设置 Web 应用程序的基础架构。
前提条件
本指南要求您运行配置了基本防火墙和具有 sudo 权限的非 root 用户的 Ubuntu 20.04 服务器。查看这篇关于如何设置 Ubuntu 服务器的详细指南。按照本教程配置具有 sudo 权限的非 root 用户。您还可以按照本指南的步骤配置 Iptables 防火墙.
我们将在虚拟环境中安装 Django。拥有特定于项目的环境可以更轻松地在同一台服务器上管理多个项目。一旦数据库和应用程序设置就绪,我们将部署 Gunicorn 应用程序服务器。Gunicorn 将作为应用程序接口,将客户端请求从 HTTP 转换为我们的应用程序可以使用的 Python 调用。然后,我们将在 Gunicorn 前端部署 Nginx,以利用其快速的连接处理性能和易于实现的安全性功能。
安装必要的软件包
首先,开始安装所有必要的软件包。值得庆幸的是,所有这些软件包都可以直接从 Ubuntu 官方软件包仓库中获取。打开终端,并更新 APT 软件包缓存:
|
1 |
sudo apt update |
软件包列表取决于 Web 应用程序是要使用 Python 2 还是 Python 3。运行以下命令以使用 Python 3 安装 Django:
|
1 |
sudo apt install python3-pip python3-dev libpq-dev postgresql postgresql-contrib nginx curl |
Django 1.11 LTS 是支持 Python 2 的最后一个 Django 版本。如果您打算将 Django 与 Python 2 配合使用,请安装以下软件包:
|
1 |
sudo apt install python-pip python-dev libpq-dev postgresql postgresql-contrib nginx curl |
PostgreSQL 数据库和用户
至于数据库解决方案,我们将使用 PostgreSQL。它是一个功能强大的开源对象关系数据库系统。PostgreSQL 提供了可靠性、健壮性和高性能。有关设置 PostgreSQL 的详细步骤,请查看这篇关于在 Ubuntu 服务器上设置 PostgreSQL 的指南。在本指南中,我们将为我们的 Django 应用程序设置一个专用的数据库和用户。
默认情况下,PostgreSQL 采用“对等身份验证”(peer authentication)作为本地连接的身份验证方案。简而言之,如果用户的操作系统用户名与有效的 PostgreSQL 用户名匹配,“对等身份验证”将对登录进行身份验证。在安装过程中,PostgreSQL 配置了一个操作系统用户 postgres 以对应 postgres PostgreSQL 管理用户。使用以下命令以 postgres 用户身份登录 PostgreSQL 交互式 shell 会话:
|
1 |
sudo -u postgres psql |
您将进入 PostgreSQL 提示符。第一步是为项目创建一个专用数据库。为了进行演示,数据库将被命名为 viktor_project:
|
1 |
CREATE DATABASE viktor_project; |
下一步是为项目数据库创建一个专用用户。该用户应该有一个强用户名。为了进行演示,用户名将为 viktor_project_user:
|
1 |
CREATE USER viktor_project_user WITH PASSWORD 'password123'; |
现在,我们将修改一些参数:
- 特定的连接参数。简而言之,无需在每次建立连接时都查询并设置正确的值。这大大提高了数据库性能。
- 默认编码为
UTF-8。这是一种通用编码,也是 Django 所期望的。 - 默认事务隔离级别为“读已提交”。它阻止读取未提交的事务。
- 时区为
UTC.
所有这些参数更改都是由 Django 项目本身 推荐的。要应用这些更改,请运行以下命令。不要忘记将数据库用户名更改为正确的用户名:
|
1 2 3 |
ALTER ROLE viktor_project_user SET client_encoding TO 'utf8'; ALTER ROLE viktor_project_user SET default_transaction_isolation TO 'read committed'; ALTER ROLE viktor_project_user SET timezone TO 'UTC'; |
将数据库管理员更改为专用的数据库用户:
|
1 |
GRANT ALL PRIVILEGES ON DATABASE viktor_project TO viktor_project_user; |
我们目前对 PostgreSQL 的操作已完成。退出 PostgreSQL 交互式 shell:
|
1 |
\q |
Python 虚拟环境
数据库准备就绪后,我们现在可以专注于建立项目的其余需求。为了更方便地进行管理,我们将建立一个虚拟环境并在其中安装所有 Python 需求。要生成虚拟环境,我们需要 virtualenv。它可以通过 pip 轻松安装。
以下命令将升级 pip 并安装 virtualenv。对于 Python 3,请运行以下命令:
|
1 2 |
sudo -H pip3 install --upgrade pip sudo -H pip3 install virtualenv |
对于 Python 2,请改运行以下命令:
|
1 2 |
sudo -H pip install --upgrade pip sudo -H pip install virtualenv |
一旦 virtualenv 安装完成,就可以创建虚拟环境了。接下来,为虚拟环境创建一个专用目录:
|
1 |
mkdir -v ~/viktor_project |
之后,将当前活动目录更改为虚拟环境的专用目录:
|
1 |
cd ~/viktor_project |
在该目录中,运行以下命令。virtualenv 工具将创建一个以项目名称命名的虚拟环境:
|
1 |
virtualenv viktor_project |
它将创建一个以项目名称命名的子目录。该子目录将包含本地版本的 Python 和 pip。它为项目安装和配置隔离的 Python 环境提供了灵活性。
以下命令将激活虚拟环境:
|
1 |
source viktor_project/bin/activate |
终端提示符将发生变化,表明您正在 Python 虚拟环境中操作。现在我们已经进入了虚拟环境,我们将安装必要的 Python 需求。我们需要 Django、Gunicorn 和 psycopg2(PostgreSQL 适配器)。以下命令将指示本地 pip 安装这些组件:
|
1 |
pip install django gunicorn psycopg2-binary |
即使您使用的是 Python 3,pip 也是正确的命令。这是因为在虚拟环境中,pip3 被重命名为 pip。
新建 Django 项目
Python 组件就绪后,我们就可以开始处理实际的 Django 项目文件了。
-
创建 Django 项目
项目目录已经建立。我们将告诉 Django 在那里安装其文件。此过程将生成一个包含实际代码的二级目录。该目录还将包含一个管理脚本。关键是,我们显式地告诉 Django 目标目录,而不是让它根据当前目录来决定目录:
|
1 |
django-admin.py startproject viktor_project ~/viktor_project |
Django 将相应地创建项目。以下是我们将重点关注的一些重要文件和目录。目录和文件名是根据演示使用的。
~/viktor_project/manage.py:Django 的项目管理脚本。~/viktor_project/viktor_project/:它是包含 Django 项目的包。它应该包含文件 __init__.py、settings.py、urls.py、asgi.py 和 wsgi.py。
-
调整项目设置
项目创建后,第一件事就是调整其配置。在文本编辑器中打开 settings.py:
|
1 |
nano ~/viktor_project/viktor_project/settings.py |
我们要寻找的第一个指令是 ALLOWED_HOSTS。它定义了可以连接到 Django 实例的服务器或域名。如果任何带有 Host 请求头的传入请求与 ALLOWED_HOSTS 列表不匹配,它将引发异常。Django 推荐这样做以避免某些类型的安全漏洞:
|
1 |
ALLOWED_HOSTS = ['<server_ip_or_domain_name_1>',' server_ip_or_domain_name_2','localhost'] |
我们接下来要关注的部分是 DATABASE。它管理数据库访问。默认情况下,它包含 SQLite 数据库引擎的配置。但是,我们将在项目中使用 PostgreSQL 数据库。Django 将使用 psycopg2 适配器与 PostgreSQL 进行通信:
|
1 2 3 4 5 6 7 8 9 10 |
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql_psycopg2', 'NAME': 'viktor_project', 'USER': 'viktor_project_user', 'PASSWORD': 'password123', 'HOST': 'localhost', 'PORT': '', } } |
现在,移到文件底部。添加以下行以指示静态文件的位置。这有助于 Nginx 处理对这些项的请求:
|
1 2 |
import os STATIC_ROOT = os.path.join(BASE_DIR, 'static/') |
我们对 settings.py 的工作目前已完成。保存文件并关闭编辑器。
-
完成初始项目设置
我们现在可以将初始数据库模式迁移到专用的 PostgreSQL 数据库。运行以下命令:
|
1 2 |
~/viktor_project/manage.py makemigrations ~/viktor_project/manage.py migrate |
接下来,我们需要为项目创建一个超级用户。要生成超级用户,请运行以下命令:
|
1 |
~/viktor_project/manage.py createsuperuser |
将所有静态文件收集到我们在 settings.py 中指定的目录。静态文件将被收集到项目目录下名为“static”的独立目录中:
|
1 |
~/viktor_project/manage.py collectstatic |
现在,我们需要调整服务器防火墙。如果您遵循了服务器配置指南,那么您应该已经配置并激活了 UFW。我们将为 8000 端口创建一个例外。这是 Django 使用的默认端口。查看此指南以了解更多关于UFW 防火墙基础知识和用法.
|
1 |
sudo ufw allow 8000 |
接下来,验证该操作:
|
1 |
sudo ufw status |
最后,我们可以测试服务器的实际运行情况。启动 Django 开发服务器:
|
1 |
~/viktor_project/manage.py runserver 0.0.0.0:8000 |
如果配置成功,Django 开发服务器应该会启动并接受传入的请求。打开浏览器并转到服务器的 IP/域名加端口 8000:
|
1 |
http://<server_or_domain>:8000 |
您应该会到达 Django 默认的索引页面。要访问管理面板,请在 URL 后面附加 /admin。管理面板只能由我们事先创建的超级用户访问:
|
1 |
http://<server_or_domain>:8000/admin |
登录后,您将进入默认的 Django 管理界面:
我们现在已经完成了测试。要停止服务器,请在终端窗口中按“Ctrl + C”。
-
测试 Gunicorn
在离开虚拟环境之前,我们要确保 Gunicorn 可以为应用程序提供服务。测试的方法是使用 Gunicorn 加载项目的 WSGI 模块。
Gunicorn 命令位于项目目录中:
|
1 2 |
cd ~/viktor_project gunicorn --bind 0.0.0.0:8000 viktor_project.wsgi |
这将在 Django 运行的相同接口上启动 Gunicorn。我们可以再次从普通的 Web 浏览器中测试该应用。请注意,管理界面不会应用任何样式,因为 Gunicorn 仍然不知道如何找到静态 CSS 内容:
|
1 |
http://<server_or_domain>:8000 |
完成后,在终端窗口中按“Ctrl + C”以停止 Gunicorn 服务器。
-
退出虚拟环境
Django 应用程序配置已完成。运行以下命令退出虚拟环境:
|
1 |
deactivate |
Gunicorn 套接字和服务文件
我们已经验证了 Gunicorn 可以与 Django 应用程序进行交互。但是,我们需要一种更健壮的方法来管理应用程序服务器。这就需要用到 systemd。Systemd 是 Linux 上最流行的初始化系统之一。这里有一份关于如何管理 systemd 服务和单元.
我们可以为 Gunicorn 创建套接字和服务文件,让 systemd 像管理服务一样管理它。在启动时,将生成 Gunicorn 套接字。该套接字将监听传入的连接。当连接发生时,systemd 将启动 Gunicorn 进程来处理该连接。
-
Gunicorn 套接字
让我们首先创建一个 Gunicorn 套接字。该文件需要使用 sudo 权限创建:
|
1 |
sudo nano /etc/systemd/system/gunicorn.socket |
在文件中输入以下代码:
|
1 2 3 4 5 6 7 |
[Unit] Description=gunicorn socket [Socket] ListenStream=/run/gunicorn.sock [Install] WantedBy=sockets.target |
如您所见,代码有三个部分。
[Unit]:此部分描述套接字。[Socket]:它定义了套接字的位置。[Install]:此部分确保 systemd 在正确的时间创建套接字。
保存文件并关闭编辑器。
-
Gunicorn 服务
接下来,我们将为 Gunicorn 创建一个服务文件。与套接字文件类似,它也必须使用 sudo 权限创建:
|
1 |
sudo nano /etc/systemd/system/gunicorn.service |
输入以下代码:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
[Unit] Description=gunicorn daemon Requires=gunicorn.socket After=network.target [Service] User=cloudsigma Group=www-data WorkingDirectory=/home/cloudsigma/viktor_project ExecStart=/home/cloudsigma/viktor_project/viktor_project/bin/gunicorn \ --access-logfile - \ --workers 3 \ --bind unix:/run/gunicorn.sock \ viktor_project.wsgi:application [Install] WantedBy=multi-user.target |
代码包含多个部分:
[Unit]:此部分指定元数据和依赖项。它还描述了仅在达到网络目标后才启动。[Service]:此部分指定了运行该进程的用户和组。组的所有权设置为“www-data”,以便 Nginx 可以与 Gunicorn 进行通信。它还映射了工作目录并指定了启动命令。[Install]:此部分告诉 systemd 如果在开机时启用此服务,应将其链接到什么。它应该在常规多用户系统开始运行后启动。
接下来,保存文件并关闭编辑器。
-
启用 Gunicorn 套接字
Gunicorn 套接字已准备就绪。因此,您可以运行以下命令。它将启动并启用该套接字。套接字文件将创建于 /run/gunicorn.sock(开机时)。当连接到该套接字时,systemd 将启动 Gunicorn 服务来处理它:
|
1 2 |
sudo systemctl start gunicorn.socket sudo systemctl enable gunicorn.socket |
检查 Gunicorn 套接字的状态:
|
1 |
sudo systemctl status gunicorn.socket |
现在,检查套接字文件是否存在:
|
1 |
file /run/gunicorn.sock |
如果 systemctl 的状态指示错误,或者未找到 gunicorn.sock 文件,则表明套接字未正确创建。请查看详细日志以获取线索:
|
1 |
sudo journalctl -u gunicorn.socket |
别忘了再次检查 gunicorn.socket 文件以查找潜在的错误。
-
套接字激活
到目前为止,我们已经启动了 gunicorn.socket。但是,在没有任何连接请求的情况下,gunicorn.service 将不会激活。接下来,验证 Gunicorn 的状态:
|
1 |
sudo systemctl status gunicorn |
我们可以通过使用 curl 发送连接请求来测试套接字激活机制:
|
1 |
curl --unix-socket /run/gunicorn.sock localhost |
您应该会从应用程序中获得 HTML 输出。这表明 Gunicorn 已成功启动并能够为 Django 应用程序提供服务。验证 Gunicorn 服务的当前状态:
|
1 |
sudo systemctl status gunicorn |
如果出现任何异常行为或输出(指示错误),请查看详细日志以获取线索:
|
1 |
sudo journalctl -u gunicorn |
如果对 gunicorn.service 文件进行了更改,则需要重新加载守护进程以重新读取服务定义。这还需要重新启动 Gunicorn 服务:
|
1 2 |
sudo systemctl daemon-reload sudo systemctl restart gunicorn |
配置 Nginx
现在,我们将配置 Nginx 以将传入流量传递给该进程。首先,在 Nginx 中创建一个新的服务器块:
|
1 |
sudo nano /etc/nginx/sites-available/viktor_project |
然后,输入以下代码:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
server { listen 80; server_name 31.171.250.71; location = /favicon.ico { access_log off; log_not_found off; } location /static/ { root /home/cloudsigma/viktor_project; } location / { include proxy_params; proxy_pass http://unix:/run/gunicorn.sock; } } |
以下是配置中的多个块:
service:此块定义了服务器应正常监听 80 端口,并应响应服务器的域名或 IP 地址。location:这是第一个 location 条目。它定义了在哪里可以找到静态资源。location:这是第二个 location 条目。此块定义了标准代理参数以及如何将流量传递到 Gunicorn 套接字。
保存文件并关闭编辑器。将文件链接到“sites-enabled”目录以激活:
|
1 |
sudo ln -s /etc/nginx/sites-available/viktor_project /etc/nginx/sites-enabled |
在此之后,测试 Nginx 配置中是否存在任何语法错误:
|
1 |
sudo nginx -t |
如果您没有发现错误,请重启 Nginx 以应用更改:
|
1 |
sudo systemctl restart nginx |
我们需要再次修改 UFW 规则。我们不再需要访问开发服务器,因此可以删除 8000 端口的例外规则。此外,我们希望打开 80 端口以允许正常流量:
|
1 2 |
sudo ufw delete allow 8000 sudo ufw allow 'Nginx Full' |
验证这些防火墙规则更改:
|
1 |
sudo ufw status |
现在应该可以通过普通的网页浏览器访问该服务器了。
故障排除步骤
如果正确执行了所有步骤,应该可以通过互联网访问 Django 应用程序。如果无法访问,则说明安装未按计划进行。我们需要进行故障排除以找出问题根源。
-
Nginx 显示默认页面
如果 Nginx 显示的是默认页面而不是应用程序代理,这通常意味着 server_name 在服务器块中配置错误。
在此示例中,服务器块存储在以下位置:
|
1 |
/etc/nginx/sites-available/viktor_project |
该 server_name 条目决定了 Nginx 将使用哪个服务器块来响应请求。如果显示默认页面,那么 Nginx 可能无法将请求与明确的服务器块相匹配,因此它退而使用默认块:
|
1 |
/etc/nginx/sites-available/default |
检查您的 Django 项目的服务器块是否具有正确的 server_name.
-
502 Bad Gateway
502 错误表示 Nginx 无法成功代理请求。导致 502 错误可能有各种各样的配置问题,因此我们需要线索来进行正确的故障排除。
线索的主要来源是 Nginx 错误日志。通常,它会提示在代理过程中导致问题的条件。使用以下命令检查 Nginx 错误日志:
|
1 |
sudo tail -F /var/log/nginx/error.log |
打开日志后,尝试再次访问服务器。它应该会在日志中生成一条新的错误消息。这有助于缩小问题范围。以下是几种可能的消息:
- connect() to unix:/run/gunicorn.sock failed (2: No such file or directory)
这表示 Nginx 无法在配置中定义的位置找到 gunicorn.sock。该位置由站点块下的 proxy_pass 指令所描述。检查 proxy_pass 是否指示了 gunicorn.sock(由 gunicorn.socket systemd 单元生成)的正确位置:
|
1 |
/etc/nginx/sites-available/viktor_project |
如果 gunicorn.sock 未在 /run 目录下找到,这意味着 systemd 无法生成它。您应该重新检查 Gunicorn 套接字文件配置步骤。
- connect() to unix:/run/gunicorn.sock failed (13: Permission denied)
这表示由于权限问题,Nginx 无法连接到 Gunicorn 套接字。如果该过程是以 root 用户而不是 sudo 用户身份执行的,就可能会发生这种情况。尽管 systemd 成功生成了 gunicorn.sock,但 Nginx 无法使用它。
一个可能的元凶可能是根目录 (/) 与 gunicorn.sock 文件之间的权限受限。检查套接字文件及其每个父目录的权限和所有权:
|
1 |
namei -l /run/gunicorn.sock |
第一列描述文件权限。第二列描述所有者用户,第三列描述所有者组。如果通往 gunicorn.sock 的任何目录没有正确的读取和执行权限, Nginx 将无法访问该套接字。
-
Django 显示 “could not connect to the server: Connection refused”
这表示 Django 无法连接到 PostgreSQL 服务器。请确保 PostgreSQL 服务器已启动并正在运行:
|
1 |
sudo systemctl status postgresql |
如果它没有运行,请运行以下命令来启动并启用它:
|
1 2 |
sudo systemctl start postgresql sudo systemctl enable postgresql |
如果您仍然遇到此错误,请确保在以下路径下正确定义了数据库凭据:settings.py:
|
1 |
~/viktor_project/viktor_project/settings.py |
更多故障排除
为了进行额外的故障排除,系统设置了各种日志。这些日志可以帮助缩小问题源头的范围。
以下是可提供帮助的日志列表:
- Nginx 日志
|
1 |
sudo journalctl -u nginx |
- 访问日志-Nginx
|
1 |
sudo less /var/log/nginx/access.log |
- 错误日志-Nginx
|
1 |
sudo less /var/log/nginx/error.log |
- 应用程序日志-Gunicorn
|
1 |
sudo journalctl -u gunicorn |
- 套接字日志-Gunicorn
|
1 |
sudo journalctl -u gunicorn.socket |
|
1 |
sudo systemctl restart gunicorn |
|
1 2 |
sudo systemctl daemon-reload sudo systemctl restart gunicorn.socket gunicorn.service |
|
1 2 |
sudo nginx -t sudo systemctl restart nginx |
结语
本指南成功演示了如何奠定 Django 的基础。Django 提供了 Web 应用程序的许多常用组件,使您能够专注于独特的元素。Django 项目将在虚拟环境中运行。Gunicorn 管理客户端请求与 Django 之间的通信。最后,Nginx 作为反向代理来处理客户端连接。
祝您使用愉快!










评论
暂无评论。发表第一条评论吧。