文章

Django 项目生产部署

Django 项目在生产环境的部署涉及多个步骤:

  • 配置 Django 设置
  • 使用 WSGI/ASGI 应用服务器
  • 配置 Nginx
  • 启用 HTTPS
  • 使用生产数据库
  • 管理服务。

使用以上一般步骤来确保项目可以正常地运行在生产环境中。

项目结构

project/
│
├── backend/                   # 后端代码目录
│   ├── backend/               # 后端同名应用
│   │   ├── __init__.py
│   │   ├── asgi.py
│   │   ├── settings.py
│   │   ├── urls.py
│   │   ├── wsgi.py
│   │   └── ...
│   ├── app/                   # 后端应用代码
│   │   ├── migrations/        # 数据库迁移文件
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── apps.py
│   │   ├── models.py
│   │   ├── urls.py
│   │   ├── views.py
│   │   ├── tasks.py
│   │   └── ...
│   ├── conf/                # 后端配置文件
│   │   ├── cert/            # SSL 证书
│   │   ├── supervisor/      # supervisor 配置文件
│   │   ├── uwsgi.ini        # uWSGI 配置文件
│   │   └── ...
│   ├── settings/            # 不同环境配置文件
│   │   └── common.py        # 基础配置模块
│   │   └── development.py   # 开发环境配置
│   │   └── production.py    # 生成环境配置
│   ├── static/              # 静态资源
│   │   └── ...
│   ├── requirements.txt       # Python 依赖文件
│   ├── Dockerfile             # 后端 Dockerfile
│   ├── manage.py              # Django 管理脚本
│   └── ...
│
├── docs/                      # 项目文档
│   ├── architecture.md        # 架构文档
│   └── ...
│
├── .gitignore                  # Git 忽略文件
├── docker-compose.yml          # Docker Compose 配置文件
└── README.md                   # 项目说明文件

本例 Django 项目中,前端页面使用的是 Django 渲染模板,主要涉及后端内容的部署。

上线环境配置

使用 settings.py 分环境模块

settings.py 拆分为多个文件,例如 common.pydevelopment.pyproduction.py,并在每个环境配置文件中配置不同内容。

  • settings/common.py 定义在开发和生产之间共同的基本设置。
  • settings/development.py 定义开发环境的配置内容。
  • settings/production.py 定义生产环境的配置内容。

参考: https://developer.mozilla.org/zh-CN/docs/Learn/Server-side/Django/Deployment

DEBUG 设置

确保在生产环境中 DEBUGFalse,以避免泄露调试信息。

DEBUG = False

ALLOWED_HOSTS 设置

使用 * 允许所有主机名访问,但在生产环境中最好指定具体的主机名或 IP 地址。

ALLOWED_HOSTS = ['*']

ALLOWED_HOSTS = ['yourdomain.com', 'www.yourdomain.com']

安全配置

# HSTS 确保浏览器只通过 HTTPS 连接到项目网站
SECURE_HSTS_SECONDS = 3600
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True

# SSL 重定向,自动将所有 HTTP 请求重定向到 HTTPS
SECURE_SSL_REDIRECT = True

# 防止浏览器对相应内容类型嗅探
SECURE_CONTENT_TYPE_NOSNIFF = True

# 启用浏览器 XXS 过滤器
SECURE_BROWSER_XSS_FILTER = True

# 启用安全 Cookie 确保仅通过 HTTPS 传输
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True

# 点击劫持保护
X_FRAME_OPTIONS = 'DENY'
  • settings.py 相关 cookiessl 安全设置会迫使 http 请求重定向到 https
  • HSTS(HTTP Strict Transport Security) 配置根据需求,可以将 SECURE_HSTS_SECONDS 设置更长时间(例如一年)。
  • X_FRAME_OPTIONS:点击劫持保护,禁止其他网站通过 iframe 嵌入自己的项目网页,防止点击劫持攻击。

敏感信息

在 Django 项目中使用 .env 文件来集中管理环境变量,并通过 python-dotenv 库将其加载到环境中。

生成密钥 SECRET_KEY

首先,为确保 SECRET_KEY 密钥的安全性,使用如下 Python 脚本生成随机且唯一的密钥:

import secrets

def generate_secret_key(length=50):
    return secrets.token_urlsafe(length)

print(generate_secret_key())

安装 python-dotenv

pipenv install python-dotenv

创建 .env 文件

将所有敏感信息存储在环境变量中,避免硬编码。例如配置安全密钥、数据库用户名和密码等。

# .env file
## 使用 python-dotenv 包读取环境变量
## DJANGOSETTINGSMODULE 设置为 settings.development 或 settings.production

# 调试开发环境
DJANGO_SETTINGS_MODULE='settings.development'

## 部署生产环境
#DJANGOSETTINGSMODULE='settings.production'

# 使用根目录的 utils.py 中的 getenv 函数生成密钥粘贴此处
SECRET_KEY='gPi5ie7KAYhR5s7YuemgJHIKMgA5p9jxnG_VuUS32H5-JylowuXbXXtz4K179pcUCyg'

# 数据库用户名和密码
DB_USER='xxx'
DB_PASS='123456'

注意:.env 文件不被上传到版本控制系统(如 Git),通常通过 .gitignore 忽略。

加载 .env 文件

在项目的 settings 文件(本例 settings/production.py)中加载 .env 存储的环境变量:

import os
from dotenv import load_dotenv

# 加载 .env 文件中的环境变量
load_dotenv()

# 从环境变量中获取配置
SECRET_KEY = os.getenv('SECRET_KEY')
DB_USER = os.getenv('DB_USER')
DB_PASS = os.getenv('DB_PASS')
REDIS_AUTH = os.getenv('REDIS_AUTH')

if not SECRET_KEY or not DB_USER or not DB_PASS or not REDIS_AUTH:
    raise ValueError('Missing one or more required environment variables.')

注意:使用环境变量时应小心敏感信息的泄露,确保环境变量的访问权限是受保护的。

安全管理

应避免将环境变量文件或敏感信息上传到版本控制系统(如 Git)中。在 .gitignore 中添加如下内容:

.env
database/db.sqlite3
logs/nginx/*
logs/uwsgi/*
!logs/nginx/.gitkeep
!logs/uwsgi/.gitkeep

安全测试

运行命令检查,以确保没有遗漏的安全设置。

python manage.py check --deploy

静态文件配置项

Django 项目有一些 CSS、JavaScript 等静态文件分散在项目的各个应用中,为了方便让 Nginx 处理对这些静态文件的请求,把项目中的全部静态文件收集到一个统一的目录,即项目的根目录,命名为 static

# 其他配置...
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
  • STATIC_ROOT 是用于生产环境,指定了 collectstatic 命令将静态文件集中到的目录。
  • STATICFILES_DIRS 是用于开发环境,指定了额外的静态文件目录供 Django 查找。

为了在开发和生产环境中使用不同的 settings.py 配置文件,接下来更新 manage.pyuwsgi.py 文件内容。

manage.py 项目管理

动态加载 Django 配置,提供一个易于管理的项目入口点,以支持不同环境(开发、生产)使用不同的配置。

from dotenv import load_dotenv

# 加载 .env 文件中的环境变量
load_dotenv()

settings_module = os.getenv('DJANGO_SETTINGS_MODULE')  
os.environ.setdefault('DJANGO_SETTINGS_MODULE', settings_module)
# 其他代码

backend/wsgi.py 设置环境

一个 WSGI 兼容的 Web 服务器网关接口文件。用于将 Django 项目运行在 WSGI 兼容 Web 服务器上,如 Apache、Nginx 等。

在后端项目同名应用下的 wsgi.py 接口文件中更新配置:通过 dotenv 加载 .env 文件中的环境变量,动态配置 Django 项目的 DJANGO_SETTINGS_MODULE 环境变量。

from dotenv import load_dotenv

# 加载 .env 文件中的环境变量
load_dotenv()

settings_module = os.getenv('DJANGO_SETTINGS_MODULE')

# os.environ.setdefault('DJANGOSETTINGSMODULE', 'backend.settings')
os.environ.setdefault('DJANGO_SETTINGS_MODULE', settings_module)
# 其他代码

安装 MySQL

开发环境调试使用的是 Django 框架自带的的 SQLite3,生产环境使用 MySQL 关系数据库。

要安装MySQL需要先到MySQL官方网站下载对应的RPM文件,选择适合项目和系统的版本。

本例,为兼容项目和 CentOS 9 系统使用 MySQL 版本:8.0.39

MySQL 数据库解压,安装需要的组件:

rpm -ivh mysql-community-common-8.0.39-1.el9.x86_64.rpm && \
rpm -ivh mysql-community-libs-8.0.39-1.el9.x86_64.rpm && \
rpm -ivh mysql-community-debuginfo-8.0.39-1.el9.x86_64.rpm && \
rpm -ivh mysql-community-client-debuginfo-8.0.39-1.el9.x86_64.rpm && \ 
rpm -ivh mysql-community-client-plugins-8.0.39-1.el9.x86_64.rpm && \ 
rpm -ivh mysql-community-client-8.0.39-1.el9.x86_64.rpm && \
rpm -ivh mysql-community-icu-data-files-8.0.39-1.el9.x86_64.rpm && \
rpm -ivh mysql-community-server-8.0.39-1.el9.x86_64.rpm  && \
rpm -ivh mysql-community-devel-8.0.39-1.el9.x86_64.rpm

启动数据库服务,进入数据库中,创建项目使用的数据库用户信息:

CREATE USER '用户名'@'%' IDENTIFIED BY '密码';

Django 项目安装三方库:

pipenv install mysqlclient

Django 中配置数据库连接:

DATABASES = {
    # 'default': {
    #     'ENGINE': 'django.db.backends.sqlite3',
    #     'NAME': os.path.join(BASE_DIR, 'database', 'db.sqlite3'),
    # }

    'default': {
        # 数据库引擎配置
        'ENGINE': 'django.db.backends.mysql',
        # 数据库的名称
        'NAME': 'blog',
        # 数据库服务器的 IP 地址(如果是本机,可以配置成 localhost 或 127.0.0.1)
        'HOST': '101.34.xxx.xxx',
        # 启动 MySQL 服务的端口号
        'PORT': 3306,
        # 数据库用户名和口令
        'USER': DB_USER,
        'PASSWORD': DB_PASS,
        # 数据库使用的字符集
        'CHARSET': 'utf8mb4',
        # 数据库时间日期的时区设定
        'TIME_ZONE': 'Asia/Chongqing',
        # 设置连接最大存活时间(例如 600 秒,0 表示无连接池,None 表示永久连接)
        'CONN_MAX_AGE': 600,
    }
}

若使用购买的云服务器,可能需要开启 3306 端口(若数据库部署与项目程序不在同一主机上,还需要管控 IP 地址)。

安装 Python

如果需要清除旧版本的安装,删除对应的安装的文件夹即可。

rm -rf  /usr/local/python38/

下载:

wget https://www.python.org/ftp/python/3.9.13/Python-3.9.13.tar.xz

参考 [[../../Linux/Python 源码编译安装|Python 源码编译安装]]

部署代码

安装 pipenv

pip3 install pipenv

注意:通过 pipenv shell 激活虚拟环境,然后执行操作。

获取 pipenv 虚拟环境路径:

# pipenv --venv
/root/.local/share/virtualenvs/backend-2ZtQ7vfC

拉取远程仓库:

git clone git@github.com:littlekj/helloBlog.git

进入项目根目录,安装项目依赖:

pipenv install --deploy --ignore-pipfile
  • --deploy 表示“部署”模式,在此模式下,pipenv 只根据 Pipfile.lock 文件安装依赖。如果 Pipfile.lock 文件不匹配或丢失,安装将失败。
  • --ignore-pipfile 表示 pipenv 忽略 Pipfile,只根据 Pipfile.lock 安装依赖。

检查环境:

Pipfile.lock 文件存在且是最新的,如果更新 Pipfile.lock,运行命令:

pipenv lock

进入后端项目根目录,进行数据库迁移:

pipenv run python manage.py migrate

创建管理员账户:

pipenv run python manage.py createsuperuser

收集静态文件:

# 收集静态文件 
pipenv run python manage.py collectstatic

Django 框架项目使用 Python Manager.py runserver 启动服务用于开发测试,不建议用于生产环境。所以,生产环境的应用使用 WSGI 服务器托管启动。

配置应用服务器

在 Django 项目部署中,WSGI(Web Server Gateway Interface)是常用的接口标准。它定义了 Web 服务器与 Web 应用之间的通信方式,提供了一种将 Web 应用与服务器或中间件连接起来处理请求的规范。

uWSGI 是一个高性能的 WSGI 应用服务器,常用于托管 Python Web 应用程序,专门处理动态内容(应用的逻辑)。它支持多种应用程序协议、服务模型和部署选项。

uWSGI 配置文件可以是用 INI 文件格式,通常文件扩展名为 .ini。配置文件包含了服务器的运行时配置选项,如应用路径、端口、进程数等。

安装 uWSGI:

pipenv install uwsgi

项目 uWSGI 配置文件:

在后端项目中编辑 uWSGI 配置文件 conf/uwsgi.ini

[uwsgi]
# 配置前导路径,通常是项目的根目录
base=/usr/local/share/helloBlog/backend

# 项目名称,用于指代应用
name=backend

# 指定 uWSGI 启动时的工作目录
chdir=%(base)

# 指定 WSGI 应用模块,格式为’模块名:应用名‘
module=%(name).wsgi:application

# 启动守护进程模式,将 uWSGI 置于后台运行
master=true

# 设置进程数,通常 CPU 核心数的 2 到 4倍
processes=4

# 指定 PID 文件的位置,便于进程管理
pidfile=/run/uwsgi.pid

# 退出时自动清理 Unix 套接字和 PID 文件
vacuum=true

# 设置每个工作进程处理的最大请求数,超过会重启该进程
max-requests=5000

# 启用 thunder lock,优化多进程环境下的锁性能
thunder-lock = true

# 启用线程支持,如果应用程序依赖线程则需要启用
enable-threads = true

# 指定监听队列的长度
listen = 120

# 处理更大的请求数据块
buffer-size = 32768  # 增加缓冲区大小
harakiri = 60        # 设置超时时间
post-buffering = 4096  # 处理较大 POST 数据块

# 使用非 root 用户运行 uWSGI,提高安全性
#uid=www-data
#gid=www-data

# 设置 Python 虚拟环境的路径
pythonhome=/root/.local/share/virtualenvs/backend-2ZtQ7vfC

# 指定通信的地址和端口,格式为‘IP:端口’
# 如果使用 Unix 套接字,格式为‘socket=/tmp/uwsgi.sock’
socket=127.0.0.1:8000

# 将日志输出到指定文件
logto=%(base)/logs/uwsgi/uwsgi.log

# 或让 uWSGI 进程在后台运行并记录日志
#daemonize=%(base)/logs/uwsgi/uwsgi-daemon.log
  • 设置监听队列,uWSGI 文档
  • 设置缓冲区大小以处理更大的请求数据块。
  • 可以使用其他用户 www-data 以安全的方式运行,赋予权限:
chown -R www-data:www-data /path/to/your/project
chown www-data:www-data /path/to/your/uwsgi.sock
chown www-data:www-data /path/to/your/logs

启动 uWSGI 服务器

可略过,后续使用 Supervisor 管理服务进程。

安装 nohup 工具:

yum install coreutils

启动服务器:

进入后端项目根目录执行:

nohup uwsgi --ini conf/uwsgi.ini -b 65535 > logs/uwsgi.log 2>&1 &
  • nohup 是一个工具,用于在后台运行命令并忽略挂起信息。nohup 允许 uWSGI 进程在用户注销或中断关闭后继续运行,适用于生产环境。
  • -b 65535 设置请求的缓冲区大小。
  • > uwsgi.log 2>&1 将标准输出和标准错误重定向到 uwsgi.log 文件。不指定输出文件,nohup 默认输出重定向到 nohup.out
  • 使用 & 符号将进程放到后台运行。

参考 uWSGI 文档如何使用 WSGI 部署 Django 项目

配置 Web 服务器

在现代 Web 架构中,Nginx 作为反向代理服务器代表后端应用服务器处理客户端请求,它位于目标服务器的前端,处理客户端发来的请求,并将请求转发给相应的内部服务器。

uWSGI 和 Nginx 实现项目的动静分离,Nginx 可以处理静态文件请求,动态请求则转发给 uWSGI。Nginx 和 uWSGI 通过 uWSGI 协议或 HTTP 协议进行高效的通信,分离职责,可以最大化性能。

Nginx 和 uWSGI 之间常用 uWSGI 协议或 HTTP 协议。uWSGI 协议比 HTTP 更高效,是推荐的选择。

安装 Nginx

yum install nginx

配置 Nginx

修改全局配置文件(/etc/nginx/nginx.conf):

# 配置用户
user nginx;

# 工作进程数(建议跟CPU的核数量一致)
worker_processes auto;

# 错误日志
error_log /var/log/nginx/error.log;

# 进程文件
pid /run/nginx.pid;

# 加载动态模块配置
include /usr/share/nginx/modules/*.conf;

# 工作模式(多路IO复用方式)和连接上限
events {
    use epoll;  # `epoll` 是一种 I/O 事件通知机制,提供处理高并发请求的效率
    worker_connections 1024;
}

# HTTP服务器相关配置
http {
    # 日志格式
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    # 访问日志
    access_log  /var/log/nginx/access.log  main;

    # 开启高效文件传输模式
    sendfile            on;

    # 用sendfile传输文件时有利于改善性能
    tcp_nopush          on;

    # 禁用Nagle来解决交互性问题
    tcp_nodelay         on;

    # 客户端保持连接时间
    keepalive_timeout   65;

    # MIME类型配置的最大哈希大小
    types_hash_max_size 4096;

    # 包含MIME类型的配置
    include             /etc/nginx/mime.types;

    # 默认使用二进制流格式
    default_type        application/octet-stream;

    # 加载模块化配置
    include /etc/nginx/conf.d/*.conf;

    # 包含项目的Nginx配置文件
    #include /usr/local/share/helloBlog/backend/conf/*.conf;
 
    client_header_buffer_size 2k;
    large_client_header_buffers 4 8k;
    client_max_body_size 2m;

    # HTTP 服务器配置
	server {
	    listen       80;
	    listen       [::]:80;
	    server_name example.com 101.34.xxx.xxx;  # 指定处理请求的域名或 IP 地址,建议使用域名
	    # Load configuration files for the default server block.
	    include /etc/nginx/default.d/*.conf;

	    # 处理主页面请求
	    location / {# 匹配所有请求路径
		include uwsgi_params;
		uwsgi_pass 127.0.0.1:8000;  # uWSGI socket 地址
	    }

	    # 处理静态文件请求
	    location /static/ {
		alias /usr/local/share/helloBlog/backend/static/;  # 静态文件存储路径
		expires 30d;  # 缓存静态文件 30 天
	    }
	    # 日志文件配置
	    access_log /usr/local/share/helloBlog/backend/logs/nginx/access.log;
	    error_log /usr/local/share/helloBlog/backend/logs/nginx/error.log;
	}

	# 将 HTTP 请求重定向到 HTTPS
	#location / {
	#	return 301 https://$host$request_uri;
	#}

	# HTTPS 服务器配置
	server {
	    listen      443 ssl http2; # 在 HTTPS 中启用 HTTP/2,以提高性能
        listen       [::]:443 ssl http2;
	    server_name example.com 101.34.xxx.xxx;  # 指定处理请求的域名或 IP 地址

	    # SSL 配置
	    ssl_certificate     /usr/local/share/helloBlog/backend/conf/cert/zone.example.com_bundle.crt;
	    ssl_certificate_key /usr/local/share/helloBlog/backend/conf/cert/zone.example.com.key;
	    ssl_session_timeout 5m;
	    ssl_protocols TLSv1.2 TLSv1.3;
	    ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384';
	    ssl_prefer_server_ciphers on;

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

	    # 处理所有路径的请求
	    location / {
		include uwsgi_params;  # 包含与 uWSGI 服务器通信所需的标准参数
		uwsgi_pass 127.0.0.1:8000;  # uWSGI socket 地址
	    }

	    # 处理静态文件请求
	    location /static/ {
		alias /usr/local/share/helloBlog/backend/static/;  # 静态文件存储路径
		expires 30d;  # 缓存静态文件 30 天
	    }
	    # 日志文件配置
	    access_log /usr/local/share/helloBlog/backend/logs/nginx/access.log;
	    error_log /usr/local/share/helloBlog/backend/logs/nginx/error.log;
	}
}

说明:

  • server_name 可以指定域名或公网 IP,让所有来自该域名或 IP 地址的请求被 Nginx 服务处理。
  • location /:是 Nginx 配置的规则, / 是通用匹配所有以 / 开头的请求路径。
    • include uwsgi_params;: 包含了与 uWSGI 服务器通信所需的标准参数。uwsgi_params 包括了与 uWSGI 服务器进行交互所需的 HTTP 请求头和参数。
    • uwsgi_pass 127.0.0.1:8000; 将请求转发到 127.0.0.1:8000,即本地回环地址上的 uWSGI 服务器。
    • Nginx 中使用回环地址将请求转发到本机上的 uWSGI 实例。它是安全的,避免外部访问直接到 uWSGI 的端口,使所有请求都必须经过 Nginx,从而运行 Nginx 进行额外的处理和安全控制。
    • 相应地,如果 uWSGI 服务器仅绑定在 127.0.0.1 上,并且没有绑定到外部接口(如 0.0.0.0),那么外部用户将无法直接访问这个端口。它只能监听本地 Nginx 访问。
  • location /static/:这个块处理所有以 /static/ 开头的 URL 请求。
    • 浏览器请求,Nginx 接收请求,匹配 location /static/ 块。
    • Nginx 在配置参数 alias 对应路径上寻找静态资源。Nginx 将其返回给浏览器,完成静态资源的加载访问。
    • Nginx 直接处理静态文件的请求,而不经过 Web 应用服务器,从而减轻其负担,并加速静态资源的传输。

确保已创建自定义日志路径:

mkdir -p /usr/local/share/helloBlog/backend/logs/nginx
mkdir -p /usr/local/share/helloBlog/backend/logs/uwsgi

HTTPS 加密配置

网站部署建议使用 HTTPS 加密访问,可以到相关网站申请域名,国内服务器需要备案;然后使用 openssl 自签名配置 SSL 证书,或在域名网站生成 SSL 证书,存放在 Nginx 配置文件指定的路径。

网站访问

公网 IP(Public IP)是指你在互联网上的唯一地址,它允许其他设备或服务从全球范围内访问你的服务器或计算机。

在 Linux 系统下,公网 IP 可以通过 curl 命令获取。

获取公网 IPv4

# curl -s https://ipinfo.io/ip
101.34.xxx.xxx

注意:若开启了代理服务,获取的公网 IP 一般会有变化。

防火墙设置

确保服务器的防火墙允许相关端口的流量:HTTP (80)、HTTPS (443) 和 MySQL (3306) 等。

负载均衡

当服务器性能不佳时,可以部署多个后端应用服务器,使用 Nginx 的负载均衡器,将请求分发到指定的后端应用服务器,并根据权重进行负载均衡。

修改 nginx.conf 配置(未验证):

# 配置用户
user nginx;

# 工作进程数(建议跟CPU的核数量一致)
worker_processes auto;

# 错误日志
error_log /var/log/nginx/error.log;

# 进程文件
pid /run/nginx.pid;

# 包含其他的配置
include /usr/share/nginx/modules/*.conf;

# 工作模式(多路IO复用方式)和连接上限
events {
    use epoll;  # `epoll` 是一种 I/O 事件通知机制,提供处理高并发请求的效率
    worker_connections 1024;
}

# HTTP服务器相关配置
http {
    # 日志格式
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    # 访问日志
    access_log  /var/log/nginx/access.log  main;

    # 开启高效文件传输模式
    sendfile            on;

    # 用sendfile传输文件时有利于改善性能
    tcp_nopush          on;

    # 禁用Nagle来解决交互性问题
    tcp_nodelay         on;

    # 客户端保持连接时间
    keepalive_timeout   65;

    # MIME类型配置的最大哈希大小
    types_hash_max_size 4096;

    # 包含MIME类型的配置
    include             /etc/nginx/mime.types;

    # 默认使用二进制流格式
    default_type        application/octet-stream;

    # 包含其他配置文件
    include /etc/nginx/conf.d/*.conf;

    # 包含项目的Nginx配置文件
    #include /usr/local/share/helloBlog/backend/conf/*.conf;

	# 负载均衡配置
	upstream backend {
        server 192.168.1.100 weight=2;  # 后端应用服务器 1,权重为 2
        server 192.168.1.101 weight=1;  # 后端应用服务器 2,权重为 1
        server 192.168.1.102 weight=1;  # 后端应用服务器 3,权重为 1
    }

	# HTTP 服务器配置
	server {
		listen 80;
		server_name 101.34.xxx.xxx example.com; # 指定处理请求的IP地址或域名
	
		# 将 HTTP 请求重定向到 HTTPS
		location / {
			return 301 https://$host$request_uri;
		}
	}
	
	# HTTPS 服务器配置
	server {
	    listen      443 ssl http2; # 在 HTTPS 中启用 HTTP/2,以提高性能
	    server_name 101.34.xxx.xxx example.com;  # 指定处理请求的域名或 IP 地址
	
	    # SSL 配置
	    ssl_certificate     /usr/local/share/helloBlog/backend/conf/cert/cert.pem;
	    ssl_certificate_key /usr/local/share/helloBlog/backend/conf/cert/key.pem;
	    ssl_session_timeout 5m;
	    ssl_protocols TLSv1.2 TLSv1.3;
	    ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384';
	    ssl_prefer_server_ciphers on;
	
	    # 日志文件配置
	    access_log /usr/local/share/helloBlog/backend/logs/access.log;
	    error_log /usr/local/share/helloBlog/backend/logs/error.log;
	
	    # 处理主页面请求
	    location / {
	        include uwsgi_params;
	        uwsgi_pass http://backend;  # 使用负载均衡池
	    }
	
	    # 处理静态文件请求
	    location /static/ {
	        alias /usr/local/share/helloBlog/backend/static/;  # 静态文件存储路径
	        expires 30d;  # 缓存静态文件 30 天
	    }
	}
}

说明:

  • 负载均衡配置:在 http 部分添加 upstream backend,定义了负载均衡池 backendserver 指令用于指定后端服务器静态 IP 地址或 DNS 名称及其权重。
  • HTTPS 服务器中更新 uwsgi_passhttp://backend,将请求转发到负载均衡池。这样,HTTPS 请求将通过负载均衡池转发到不同的后端服务器。

管理服务进程

Supervisor 是一个进程控制系统,用于在 Unix-like 系统中启动、停止和管理进程。利用 supervisorctl,可以方便地管理进程,确保相关服务可以在控制系统启动时自动启动,并且在崩溃时自动重启。

虚拟环境中安装:

pipenv install supervisor

Supervisor 配置:

Supervisor 的主配置文件通常位于 /etc/supervisord.conf

Pip 方式安装的默认配置文件不存在,通过以下命令生成一个默认配置文件:

echo_supervisord_conf > /etc/supervisord.conf

编辑 /etc/supervisord.conf,设置 include 目录以包含自定义的 .ini 配置文件。

例如:

vim /etc/supervisord.conf
[include]
;files = relative/directory/*.ini
files = supervisord.d/*.ini

创建程序配置文件:

/etc/supervisord.d 目录下创建程序自定义配置文件,例如, /etc/supervisord.d/myapp.ini

[program:uwsgi]
command=/root/.local/share/virtualenvs/backend-2ZtQ7vfC/bin/uwsgi --ini /usr/local/share/helloBlog/backend/conf/uwsgi.ini
stopsignal=QUIT
autostart=true
autorestart=true
redirect_stderr=true
stdout_logfile=/var/log/supervisor/supervisor.log

[program:elasticsearch]
command=/opt/elasticsearch/bin/elasticsearch
autostart=true
autorestart=true
stderr_logfile=/var/log/supervisor/elasticsearch.err.log
stdout_logfile=/var/log/supervisor/elasticsearch.out.log
user=elasticuser
  • [program:uwsgi] 定义了一个名为 uwsgi 的程序块。使用 supervisorctl 命令来管理这个进程。
    • 运行 uwsgi 以启动 Web 项目应用服务器,使用指定的 uwsgi.ini 配置文件。
    • stopsignal=QUIT 指定发送给进程的信号以停止程序。
    • autostart=true 表示 Supervisor 启动时会自动启动此程序。
    • autorestart=true 表示程序如果崩溃,Supervisor 会自动重启它。
    • redirect_stderr=true 表示将标准错误输出重定向到标准输出日志文件中。将错误和输出日志合并到一个文件。
    • stderr_logfile 指定错误日志文件的路径。如果 redirect_stderr=true,这个设置通常不会被使用。
    • stdout_logfile 指定标准输出日志文件的路径。如果 redirect_stderr=true,错误日志会被合并到这个文件中。

启动 Supervisor 服务:

如果添加了 systemd 服务单元,可以通过如下命令启动:

systemctl start supervisord

或者直接运行程序命令启动:

supervisord -c /etc/supervisord.conf

启动 Supervisor 服务后,会默认启动管理在 /etc/supervisord.conf 中设置的所有进程。

使用 Supervisor 控制进程:

启动所有程序:

supervisorctl start all
  • 停止进程: stop,查看状态:status,重启进程:restart

管理多个服务程序:

# supervisorctl
elasticsearch                    RUNNING   pid 1836532, uptime 22:58:41
uwsgi                            RUNNING   pid 1836533, uptime 22:58:41
supervisor> status
elasticsearch                    RUNNING   pid 1836532, uptime 22:59:15
uwsgi                            RUNNING   pid 1836533, uptime 22:59:15
supervisor> stop uwsgi
uwsgi: stopped
supervisor> status
elasticsearch                    RUNNING   pid 1836532, uptime 23:00:10
uwsgi                            STOPPED   Nov 23 08:27 PM
supervisor> start uwsgi
uwsgi: started
supervisor> 

站点访问

一切准备就绪后,启动 Web 服务器、应用服务器、数据库及相关服务进程,即可通过域名访问站点内容。

本文由作者按照 CC BY 4.0 进行授权。