Django 项目生产部署
部署概述
在 Linux 系统中,Django 项目的生产环境部署是一个综合性任务,主要涉及 Django 项目配置、Web 应用托管和代理服务器配置、生产数据库配置以及服务进程管理等内容。
项目结构
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 证书
│ │ ├── 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 渲染模板,主要涉及后端内容的部署。
Django 项目配置
使用 settings.py
分环境模块
将 settings.py
拆分为多个文件,例如 common.py
、development.py
和 production.py
,并在每个环境配置文件中配置不同内容。
settings/common.py
定义在开发和生产之间共同的基本设置。settings/development.py
定义开发环境的配置内容。settings/production.py
定义生产环境的配置内容。
参考: https://developer.mozilla.org/zh-CN/docs/Learn/Server-side/Django/Deployment
DEBUG
设置
确保在生产环境中 DEBUG
为 False
,以避免泄露调试信息。
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
相关cookie
和ssl
安全设置会迫使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())
创建 .env
文件:
将所有敏感信息存储在环境变量中,避免硬编码。例如配置安全密钥、数据库用户名和密码等。
# .env file
# 使用 python-dotenv 包读取环境变量
# 调试开发环境
#DJANGOSETTINGSMODULE='settings.development'
# 部署生产环境
DJANGO_SETTINGS_MODULE='settings.production'
# 将根目录的 utils.py 中的 getenv 函数生成的密钥粘贴此处
SECRET_KEY='gPi5ie7KAYhR5s7YuemgJHIKMgA5p9jxnG_VuUS32H5-JylowuXbXXtz4K179pcUCyg'
# 服务器主机地址
HOST='43.153.xxx.xxx'
# 数据库用户名和密码
DB_USER='quill'
DB_PASS='xxxx'
- 在部署代码阶段,安装依赖库
python-dotenv
。
>注意:.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')
HOST = os.getenv('HOST')
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
venv/*
安全测试
运行命令检查,以确保没有遗漏的安全设置。
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.py
和 uwsgi.py
文件内容。
manage.py
项目管理
动态加载 Django 配置,提供一个易于管理的项目入口点,以支持不同环境(开发、生产)使用不同的配置。
from dotenv import load_dotenv
# 加载 .env 文件中的环境变量
load_dotenv()
def main():
"""Run administrative tasks."""
# 从环境变量中获取 Django 设置模块
# settings_module = os.getenv('DJANGO_SETTINGS_MODULE', 'backend.settings')
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()
# 从环境变量中获取 Django 设置模块
# settingsmodule = os.getenv('DJANGOSETTINGSMODULE', 'backend.settings')
settings_module = os.getenv('DJANGO_SETTINGS_MODULE')
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
启动数据库服务,进入数据库中,创建项目使用的数据库用户信息,确保用户允许远程连接。
-- 登录 MySQL
mysql -u root -p
-- 创建允许远程连接的用户
CREATE USER '用户名'@'%' IDENTIFIED BY '密码';
GRANT ALL PRIVILEGES ON blog.* TO '用户名'@'%';
FLUSH PRIVILEGES;
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': HOST,
# 启动 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
部署代码
拉取项目代码
本例,在 /usr/local/share/
工作目录拉取项目代码。
git clone git@github.com:littlekj/helloBlog.git
创建虚拟环境
推荐在虚拟环境部署项目代码。本例使用 venv
+ pip
来管理 Python 项目中的虚拟环境和依赖。
使用 python3 -m venv
命令来创建虚拟环境。虚拟环境将会创建一个包含 Python 解释器的独立目录,避免与系统的 Python 版本发生冲突。
本例,在工作的项目文件夹根目录(helloBlog/
),初始化虚拟环境:
python3 -m venv venv # 创建虚拟环境,'venv' 为虚拟环境文件夹
这样会在当前目录下创建一个名为 venv
的文件夹,包含一个干净的 Python 环境。
本例,虚拟环境路径即为 /usr/local/share/helloBlog/venv
。
激活虚拟环境
source venv/bin/activate
激活后,你的命令行提示符会发生变化,通常会显示虚拟环境的名称,例如 (venv)
,表示你现在在该虚拟环境中。
安装项目依赖(使用 pip)
在虚拟环境激活后,所有通过 pip
安装的包都会安装在该环境中,而不会影响到系统的全局环境。
安装单个依赖:
pip install <package_name> # 安装指定包,如 requests
安装多个依赖:
如果你的项目中有多个依赖,可以在 requirements.txt
文件中列出依赖项。然后通过以下命令安装所有依赖:
pip install -r requirements.txt
数据迁移处理
数据库迁移:
进入后端项目根目录(helloBlog/backend/
),进行数据库迁移:
python manage.py migrate
创建管理员账户:
python manage.py createsuperuser
收集静态文件:
# 收集静态文件
python manage.py collectstatic
Django 框架项目使用 Python manager.py runserver
启动服务用于开发测试,不建议用于生产环境。所以,生产环境的应用使用 WSGI 服务器托管启动。
配置应用服务器
在 Django 项目部署中,WSGI(Web Server Gateway Interface)是常用的接口标准。它定义了 Web 服务器与 Web 应用之间的通信方式,提供了一种将 Web 应用与服务器或中间件连接起来处理请求的规范。
uWSGI 是一个高性能的 WSGI 应用服务器,常用于托管 Python Web 应用程序,专门处理动态内容(应用的逻辑)。它支持多种应用程序协议、服务模型和部署选项。
uWSGI 典型部署结构:
客户端浏览器
↓
Nginx(处理静态文件、负载均衡)
↓
uWSGI(运行 Python 应用,如 Django)
↓
Django App(处理业务逻辑)
Nginx 和 uWSGI 之间通过 uWSGI 协议通信,效率更高,比走完整的 HTTP 协议栈更轻量。
uWSGI 配置文件可以是用 INI
文件格式,通常文件扩展名为 .ini
。配置文件包含了服务器的运行时配置选项,如应用路径、端口、进程数等。
安装 uWSGI:
venv
虚拟环境中安装:
pip install uwsgi
项目 uWSGI 配置文件:
在后端项目中编辑 uWSGI 配置文件 conf/uwsgi.ini
:
# 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
pidfile=/tmp/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=/usr/local/share/helloBlog/venv
# 指定通信的地址和端口,格式为‘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 服务器
>可略过,后续使用 Systemd 管理服务进程。
安装 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 www-data;
# 工作进程数(建议跟CPU的核数量一致)
worker_processes auto;
# 进程文件
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;
# 错误日志
error_log /var/log/nginx/error.log;
# 开启高效文件传输模式
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;
# 拦截访问 IP 的请求
server {
listen 80;
server_name 43.153.xxx.xxx;
return 301 https://example.com$request_uri;
}
server {
listen 443 ssl http2;
server_name 43.153.xxx.xxx;
#ssl_certificate example.com_bundle.crt;
#ssl_certificate_key example.com.key;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
return 301 https://example.com$request_uri;
}
# HTTP 服务器配置
server {
listen 80;
listen [::]:80;
server_name example.com; # 指定处理请求的域名地址
return 301 https://example.com$request_uri; # 将所有 HTTP 请求重定向到 HTTPS
# 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 地址
}
# 处理 Twikoo 服务请求
location /comment {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# 处理静态文件请求
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;
}
# HTTPS 服务器配置
server {
listen 443 ssl http2; # 在 HTTPS 中启用 HTTP/2,以提高性能
listen [::]:443 ssl http2;
server_name example.com; # 指定处理请求的域名地址
# SSL 配置
#ssl_certificate example.com_bundle.crt;
#ssl_certificate_key example.com.key;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_session_timeout 5m;
# 兼容性更好的协议版本
ssl_protocols TLSv1.2 TLSv1.3;
# 允许的加密套件(兼顾安全性与兼容性)
ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:!MD5;
ssl_prefer_server_ciphers on;
# 关闭 OCSP Stapling(对搜索引擎友好)
ssl_stapling off;
ssl_stapling_verify off;
include /etc/nginx/default.d/*.conf;
# 处理所有路径的请求
location / {
include uwsgi_params; # 包含与 uWSGI 服务器通信所需的标准参数
uwsgi_pass 127.0.0.1:8000; # uWSGI socket 地址
}
# 处理 Twikoo 服务请求
location /comment {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# 处理静态文件请求
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 应用服务器,从而减轻其负担,并加速静态资源的传输。
- 浏览器请求,Nginx 接收请求,匹配
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 www-data;
# 工作进程数(建议跟CPU的核数量一致)
worker_processes auto;
# 进程文件
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;
# 错误日志
error_log /var/log/nginx/error.log;
# 开启高效文件传输模式
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;
# 负载均衡配置
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
keepalive 32; # 提高与后端通信效率
}
# 拦截访问 IP 的请求
server {
listen 80;
server_name 43.153.xxx.xxx;
return 301 https://example.com$request_uri;
}
server {
listen 443 ssl http2;
server_name 43.153.xxx.xxx;
#ssl_certificate example.com_bundle.crt;
#ssl_certificate_key example.com.key;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
return 301 https://example.com$request_uri;
}
# HTTP 服务器配置
server {
listen 80;
listen [::]:80;
server_name example.com; # 指定处理请求的域名地址
return 301 https://example.com$request_uri; # 将所有 HTTP 请求重定向到 HTTPS
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
# 处理主页面请求
location / {# 匹配所有请求路径
include uwsgi_params;
uwsgi_pass http://backend; # 使用负载均衡池
}
# 处理 Twikoo 服务请求
location /comment {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# 处理静态文件请求
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;
}
# HTTPS 服务器配置
server {
listen 443 ssl http2; # 在 HTTPS 中启用 HTTP/2,以提高性能
listen [::]:443 ssl http2;
server_name example.com; # 指定处理请求的域名地址
# SSL 配置
#ssl_certificate example.com_bundle.crt;
#ssl_certificate_key example.com.key;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
ssl_session_timeout 5m;
# 兼容性更好的协议版本
ssl_protocols TLSv1.2 TLSv1.3;
# 允许的加密套件(兼顾安全性与兼容性)
ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:!MD5;
ssl_prefer_server_ciphers on;
# 关闭 OCSP Stapling(对搜索引擎友好)
ssl_stapling off;
ssl_stapling_verify off;
include /etc/nginx/default.d/*.conf;
# 处理所有路径的请求
location / {
include uwsgi_params; # 包含与 uWSGI 服务器通信所需的标准参数
uwsgi_pass http://backend; # 使用负载均衡池
}
# 处理 Twikoo 服务请求
location /comment {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# 处理静态文件请求
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
部分添加upstream backend
,定义了负载均衡池backend
,server
指令用于指定后端服务器静态 IP 地址或 DNS 名称及其权重。 - HTTPS 服务器中更新
uwsgi_pass
为http://backend
,将请求转发到负载均衡池。这样,HTTPS 请求将通过负载均衡池转发到不同的后端服务器。
管理服务进程
systemd
是现代 Linux 系统的标准服务管理器。它更加适合于生产环境,尤其是大规模部署的应用。它提供了稳定的进程管理、日志、资源限制和自动重启等功能。
创建 uWSGI 服务
创建服务文件
sudo vim /etc/systemd/system/myblog-uwsgi.service
写入内容
[Unit]
Description=MyBlog uWSGI Service
After=network.target
[Service]
User=www-data
Group=www-data
WorkingDirectory=/usr/local/share/helloBlog/backend
Environment=PYTHONPATH=/usr/local/share/helloBlog/backend
ExecStart=/usr/local/share/helloBlog/venv/bin/uwsgi --ini /usr/local/share/helloBlog/backend/conf/uwsgi.ini
ExecStop=/bin/kill -QUIT $MAINPID
Restart=always
RestartSec=3
KillSignal=SIGQUIT
TimeoutStopSec=30 # 给 uWSGI 更长时间来停止
StandardOutput=journal # 输出日志到 journal
StandardError=journal # 错误日志输出到 journal
SyslogIdentifier=myblog-uwsgi
LimitNOFILE=65536 # 限制文件描述符数量
LimitMEMLOCK=536870912 # 限制内存锁定
MemoryLimit=536870912 # 限制内存使用
[Install]
WantedBy=multi-user.target
创建 Elasticsearch 服务
> 注意:Elasticsearch 不能用 root 用户运行,必须用专用用户。
确保 elasticuser 存在
# 创建用户(如果还没创建)
sudo useradd -r -m -s /bin/bash elasticuser
# 授予 elasticsearch 目录权限
sudo chown -R elasticuser:elasticuser /opt/elasticsearch
创建服务文件
sudo vim /etc/systemd/system/elasticsearch.service
写入内容
[Unit]
Description=Elasticsearch 7.x
After=network.target
After=syslog.target
[Service]
Type=simple
User=elasticuser
Group=elasticuser
ExecStart=/opt/elasticsearch/bin/elasticsearch
ExecStop=/bin/kill -TERM $MAINPID
Restart=always
RestartSec=3
LimitMEMLOCK=infinity
LimitNOFILE=65536
LimitNPROC=4096
LimitAS=infinity
WorkingDirectory=/opt/elasticsearch
StandardOutput=journal
StandardError=journal
TimeoutStopSec=30
KillMode=process
Environment="ES_JAVA_OPTS=-Xms512m -Xmx1g" # 设置 JVM 堆内存
[Install]
WantedBy=multi-user.target
启用并启动服务
# 重载 systemd 配置
sudo systemctl daemon-reload
# 启用开机自启
sudo systemctl enable myblog-uwsgi.service
sudo systemctl enable elasticsearch.service
# 启动服务
sudo systemctl start myblog-uwsgi.service
sudo systemctl start elasticsearch.service
查看状态和日志
# 查看状态
sudo systemctl status myblog-uwsgi.service
sudo systemctl status elasticsearch.service
# 查看日志(uWSGI)
sudo journalctl -u myblog-uwsgi.service -f
# 查看日志(Elasticsearch)
sudo journalctl -u elasticsearch.service -f
站点访问
一切准备就绪后,启动 Web 服务器、应用服务器、数据库及相关服务进程,即可通过域名访问站点内容。