Spug v4.1.1 配置参数详解
Spug v4.1.1 配置体系全解析:部署环境变量、首启生成的 overrides.py、settings.py 常量(Redis 键/目录/鉴权豁免)与 nginx/Redis/进程管理组件配置,逐项实测值与调优建议。
Spug v4.1.1 配置参数详解
目标:把 Spug v4.1.1 的配置体系讲透——部署期环境变量、首启自动生成的运行时覆盖配置、镜像内置常量、以及 nginx/Redis/进程管理三类组件配置,逐项给出实测值、生效机制与调优建议。本文所有配置原文均于 2026-10-25 从一台按 《Spug v4.1.1 Docker Compose 部署指南》 部署并正常运行 v4.1.1 的服务器上实查(直接读取配置文件原文),文中行号与取值逐字照抄。
一、环境信息
| 项目 | 实测值 |
|---|---|
| 部署形态 | 官方 Compose 编排:Spug 应用 + MariaDB 10.11(宿主端口 8128→80) |
| Spug 版本 | v4.1.1(镜像内源码目录 /data/spug,程序目录 /data/spug/spug_api) |
| 后端 | Python 3.11.17 / Django 4.2 / gunicorn(9001) / daphne(9002) / Redis 7.0.15 / nginx 1.22.1 |
| 实测方式 | 读取容器内配置文件原文(settings.py、overrides.py、/etc/nginx/nginx.conf、/etc/redis.conf、/etc/supervisord.conf、/entrypoint.sh)并实测生效行为 |
| 实测日期 | 2026-10-25 |
二、参数概览:四层配置载体与优先级
Spug 的配置分散在四层载体上,理解「谁覆盖谁」是改配置的第一步:
| 层 | 载体 | 生成/修改方式 | 生效时机 | 是否跨升级保留 |
|---|---|---|---|---|
| ① 部署环境变量 | 编排文件 environment(MYSQL_、TZ、SPUG_ADMIN_ 等) | 部署前改编排 | 每次启动重新读取 | 随编排保留 |
| ② 运行时覆盖配置 | /data/spug/spug_api/spug/overrides.py | 首次启动由启动脚本自动生成;文件头注释明确「可在此追加自己的配置」 | 每次进程启动导入 | 保留(落盘在数据卷) |
| ③ 镜像内置常量 | /data/spug/spug_api/spug/settings.py | 随镜像发布,一般不改 | 首次安装 rsync 到数据卷后生效 | 升级版本时随源码更新 |
| ④ 组件与应用内配置 | nginx(/etc/nginx/nginx.conf)、Redis(/etc/redis.conf)、进程管理(/etc/supervisord.conf)、数据库内「系统设置」 | 直接改文件或 Web 后台 | supervisorctl restart 对应进程 | ①②保留;组件文件升级时以镜像内模板为准 |
优先级关系:settings.py 末尾以 from spug.overrides import * 方式导入覆盖层(源码原文 # override default config),因此 ② overrides.py 的同名项覆盖 ③ settings.py,环境变量又是 overrides.py 的取值来源——最终决定权排序为:环境变量 → overrides.py → settings.py 内置值。
三、部署环境变量详解(编排级)
以下变量由启动脚本 /entrypoint.sh 实测读取(逐字摘录关键判断逻辑,行号 96~129):
if [ -n "${MYSQL_HOST:-}" ]; then
log "waiting for the database at $MYSQL_HOST:${MYSQL_PORT:-3306}"
……
deadline = time.time() + int(os.environ.get('SPUG_DB_WAIT', '180'))
……
host=os.environ['MYSQL_HOST'], port=int(os.environ.get('MYSQL_PORT') or 3306),
user=os.environ.get('MYSQL_USER', 'spug'), passwd=os.environ.get('MYSQL_PASSWORD', ''),
db=os.environ.get('MYSQL_DATABASE', 'spug'), connect_timeout=5,
……
log "MYSQL_HOST is not set, using SQLite at $API/db.sqlite3 (fine for a trial, use MySQL/MariaDB for real use)"
……
admin_user=${SPUG_ADMIN_USER:-admin}
admin_password=${SPUG_ADMIN_PASSWORD:-}
| 变量 | 默认值 | 作用与实测行为 |
|---|---|---|
MYSQL_HOST | 未设置 | 总开关:设置后启用 MySQL/MariaDB 引擎并在启动前等待数据库可达;未设置则退化为 SQLite(实测日志原文:MYSQL_HOST is not set, using SQLite at $API/db.sqlite3 (fine for a trial, use MySQL/MariaDB for real use)),官方定位仅供试用 |
MYSQL_PORT | 3306 | 数据库端口 |
MYSQL_DATABASE | spug | 库名,须与 db 服务的 MARIADB_DATABASE 一致(首启自动建库) |
MYSQL_USER | spug | 业务账号,须与 MARIADB_USER 一致 |
MYSQL_PASSWORD | 空 | 业务密码,须与 MARIADB_PASSWORD 一致 |
SPUG_DB_WAIT | 180(秒) | 等待数据库就绪的超时上限,超时后启动脚本退出并提示检查 MYSQL_* 配置 |
TZ | UTC | 时区;必须是合法 zoneinfo 名(脚本校验 /usr/share/zoneinfo/ 下存在才生效),决定任务计划执行时刻、监控时间戳与数据库会话时区 |
SPUG_ADMIN_USER | admin | 首启创建的管理员用户名 |
SPUG_ADMIN_PASSWORD | 未设置 | 首启管理员密码;设置则用该值创建(日志:created the admin account '$admin_user' with SPUG_ADMIN_PASSWORD),未设置则随机生成并打印在日志 |
SPUG_DB_PASSWORD(compose 模板变量) | spug.cc | 官方编排用它同时注入 MYSQL_PASSWORD 与 MARIADB_PASSWORD,两侧必须同值 |
⚠️ 三个易错点(实测确认):①
MYSQL_*与MARIADB_*是两套变量,改一侧必翻车;②TZ写错时区名不会报错,而是静默回落 UTC;③SPUG_ADMIN_PASSWORD只在「首次创建管理员」时有效,数据卷已初始化后改它不会更新已有账号密码(改密码见 CLI 篇user reset)。
四、运行时配置详解(settings.py 与 overrides.py)
4.1 overrides.py:首启自动生成的覆盖层(实测全文)
首次启动后生成于 /data/spug/spug_api/spug/overrides.py,实测全文如下(逐字照抄,SECRET_KEY 为本机实测值,每台不同):
# Generated by the Docker image on first start and kept across upgrades; add your own
# settings here. Database and time zone come from the container environment.
import os
DEBUG = False
ALLOWED_HOSTS = ['127.0.0.1']
SECRET_KEY = '_iOcJxJgTzposLg_bscr6fRZbHlCFTj1SMAVbURve7EZ9ATqe9l7vPIFSQDscE5yZ6k'
_tz = os.environ.get('TZ', '')
if _tz and not _tz.startswith('/') and os.path.isfile('/usr/share/zoneinfo/' + _tz):
TIME_ZONE = _tz
if os.environ.get('MYSQL_HOST'):
DATABASES = {
'default': {
'ATOMIC_REQUESTS': True,
'ENGINE': 'django.db.backends.mysql',
'NAME': os.environ.get('MYSQL_DATABASE', 'spug'),
'USER': os.environ.get('MYSQL_USER', 'spug'),
'PASSWORD': os.environ.get('MYSQL_PASSWORD', ''),
'HOST': os.environ['MYSQL_HOST'],
'PORT': os.environ.get('MYSQL_PORT', '3306'),
'OPTIONS': {
'charset': 'utf8mb4',
'sql_mode': 'STRICT_TRANS_TABLES',
}
}
}
逐项注解:
| 配置项 | 实测值 | 说明 |
|---|---|---|
DEBUG | False | 生产安全缺省;排障时可临时改 True 后重启 spug-api 进程 |
ALLOWED_HOSTS | ['127.0.0.1'] | 仅允许 127.0.0.1 作为 Host。外部域名为何能正常访问:编排内 nginx 以 proxy_pass http://127.0.0.1:9001 转发且未设置 Host 头,Django 收到的 Host 恒为 127.0.0.1,校验天然通过;若自建外层反代直连 9001,需把对外域名追加进该列表 |
SECRET_KEY | 随机 64 位字符串(首启生成) | 会话与凭据加密根基;换库/迁移部署时不要重新生成,否则已保存的凭据将无法解密 |
TIME_ZONE | 取 TZ,实测 Asia/Shanghai | 仅当 TZ 是合法 zoneinfo 名才写入 |
DATABASES | MySQL 引擎,ATOMIC_REQUESTS: True(每个请求包在一个事务里)、charset: utf8mb4、sql_mode: STRICT_TRANS_TABLES | 与 db 服务编排参数一一对应;ATOMIC_REQUESTS 意味着批量接口出错即整体回滚 |
4.2 settings.py 内置常量详解(实测摘录,行号 74~142)
缓存与消息通道(Redis 是批量执行/发布/流水线控制台输出与 WebSocket 消息的载体,源码注释原文:the deploy/build/pipeline consoles use get_redis_connection() to stream their output through redis lists):
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/1",
"KEY_PREFIX": "spug",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
}
}
}
CHANNEL_LAYERS = {
"default": {
"BACKEND": "channels_redis.core.RedisChannelLayer",
"CONFIG": {
"hosts": [("127.0.0.1", 6379)],
"prefix": "spug:channel",
"capacity": 1000,
"expiry": 120,
},
},
}
内置
DATABASES是 SQLite(db.sqlite3),仅作为未设MYSQL_HOST时的兜底;编排形态下被 overrides.py 的 MySQL 配置覆盖。
| 配置项 | 实测值 | 说明 |
|---|---|---|
CACHES.default.LOCATION | redis://127.0.0.1:6379/1 | 1 号库做缓存;Redis 为服务内进程,仅监听本机回环 |
CACHES.default.KEY_PREFIX | spug | 所有缓存键前缀 |
CHANNEL_LAYERS.prefix | spug:channel | WebSocket 通道层键前缀 |
CHANNEL_LAYERS.capacity | 1000 | 单通道消息容量,超容量丢最旧消息;大量并发在线终端时可调大 |
CHANNEL_LAYERS.expiry | 120(秒) | 消息过期时间 |
TOKEN_TTL | 8 * 3600(8 小时) | 登录 access_token 有效期,过期需重新登录 |
任务/队列键名(worker、scheduler、monitor 之间通过这些 Redis 键协作,排查卡任务时可 redis-cli 直接观察):
| 键 | 实测值 |
|---|---|
SCHEDULE_KEY / SCHEDULE_WORKER_KEY | spug:schedule / spug:schedule:worker |
MONITOR_KEY / MONITOR_WORKER_KEY | spug:monitor / spug:monitor:worker |
EXEC_WORKER_KEY / EXEC_RESULT_KEY | spug:exec:worker / spug:exec:result |
REQUEST_KEY | spug:request |
BUILD_KEY | spug:build |
PIPELINE_KEY | spug:pipeline |
目录常量(决定发布产物与传输文件落盘位置,均在数据卷内):
| 配置项 | 实测值 | 说明 |
|---|---|---|
TRANSFER_DIR | <BASE_DIR>/storage/transfer | 批量执行的文件分发暂存 |
DEPLOY_DIR | <BASE_DIR>/storage/deploy | 应用发布产物 |
REPOS_DIR | <BASE_DIR 上两级>/repos | 源码树之外(实测即 /data/repos),源码注释:kept outside of the source tree, the docker image mounts it as /data/repos |
BUILD_DIR | <REPOS_DIR>/build | 构建工作目录 |
国际化与鉴权豁免:
| 配置项 | 实测值 | 说明 |
|---|---|---|
LANGUAGE_CODE | en-us | v4 起界面语言由前端切换(中/英双语),后端基准 en |
TIME_ZONE | Asia/Shanghai(settings 默认值) | 实际被 overrides 按 TZ 覆盖 |
USE_TZ | False | 时间以本地时区落库 |
AUTHENTICATION_EXCLUDES | /account/login/、/setting/basic/、正则 /apis/.* | 登录页、系统基本设置、开放 API 三类路径免登录鉴权(开放 API 用独立凭据) |
SPUG_VERSION | v4.1.1 | 版本标识,升级时启动脚本对比新旧值决定是否重装源码 |
| 中间件链 | TranslateMiddleware → AuthenticationMiddleware → HandleExceptionMiddleware → XFrameOptionsMiddleware | 认证在异常处理之前,未带 token 的请求直接 401 |
4.3 组件配置详解
nginx(/etc/nginx/nginx.conf 内置 server 块,实测摘录):前端为构建产物(root /data/spug/spug_web/build),单页应用回退 try_files $uri /index.html:
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /data/spug/spug_web/build;
client_max_body_size 0;
add_header X-Frame-Options SAMEORIGIN always;
gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_http_version 1.1;
gzip_comp_level 7;
gzip_types text/plain text/css text/javascript application/javascript application/json;
gzip_disable "MSIE [1-6]\.";
gzip_vary on;
location ^~ /api/ {
rewrite ^/api(.*) $1 break;
proxy_pass http://127.0.0.1:9001;
proxy_read_timeout 180s;
proxy_redirect off;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location ^~ /api/ws/ {
rewrite ^/api(.*) $1 break;
proxy_pass http://127.0.0.1:9002;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location / {
try_files $uri /index.html;
}
}
要点:client_max_body_size 0 即不限制上传体积(大文件分发不受 nginx 限制);/api/ 转发会剥掉 /api 前缀再交给后端;proxy_read_timeout 180s 限定普通 API 的等待上限;/api/ws/ 是 WebSocket 专用升级转发(在线终端与控制台实时输出走这条链路)。
Redis(/etc/redis.conf 实测关键项):
| 配置项 | 实测值 | 说明 |
|---|---|---|
bind / port | 127.0.0.1 / 6379 | 仅本机可连,不对外暴露 |
maxmemory / maxmemory-policy | 2GB / allkeys-lru | 内存上限 2GB,满后 LRU 淘汰;小规格主机建议下调 |
save | 900 1、300 10、60 10000 | RDB 快照策略(缓存与队列用途,无需 AOF) |
appendonly | no | 未开启 AOF |
进程管理(/etc/supervisord.conf 实测 7 个受管程序):
| 程序名 | 启动命令(tools/start-*.sh 实测) | 端口 |
|---|---|---|
nginx | nginx -g "daemon off;" | 80 |
redis | redis-server /etc/redis.conf | 6379 |
spug-api | gunicorn -b 127.0.0.1:9001 -w 2 --threads 8 --access-logfile - spug.wsgi | 9001 |
spug-ws | daphne -p 9002 spug.asgi:application | 9002 |
spug-worker | python3 manage.py runworker | - |
spug-monitor | python3 manage.py runmonitor | - |
spug-scheduler | python3 manage.py runscheduler | - |
五、调优建议(基于实测参数)
- API 并发:
start-api.sh中 gunicorn 固定-w 2 --threads 8(16 并发),中小团队够用;调大后记得supervisorctl restart spug-api。该脚本在数据卷内(/data/spug),改动会跨重启保留,但跨版本升级会随源码更新被覆盖,升级后需复核。 - 在线终端/控制台并发:
CHANNEL_LAYERS.capacity(1000)与 Redismaxmemory(2GB)是两个相关上限;终端较多的团队优先保证 Redis 内存,控制台输出全部经 Redis 列表流转。 - Token 时效:登录态 8 小时(
TOKEN_TTL),高频自动化对接建议改走开放 API 凭据而非长期会话 token。 - 大文件:nginx 已不限上传体积;若在 Spug 之外自建了一层反代,记得同步放开其
client_max_body_size,否则文件分发/上传会在外层被 413 拦截。 - 时区:任务计划按时区触发(
TZ),改编排环境变量后需整体重启编排生效;用错误时区名会静默回落 UTC,务必用Asia/Shanghai这类标准名。 - 数据库事务:
ATOMIC_REQUESTS: True已把每个请求包进事务,无需也不能再在业务代码层重复包事务;STRICT_TRANS_TABLES使非法数据直接报错而非静默截断。
六、常见问题
Q1:改了 settings.py / overrides.py 不生效?
A:Python 进程只读一次配置。supervisorctl restart spug-api spug-ws spug-worker spug-monitor spug-scheduler,或整体 docker compose restart spug。
Q2:overrides.py 会不会被升级覆盖? A:不会。该文件由首启生成并落在数据卷,文件头注释原文明确 kept across upgrades;升级只更新镜像内源码模板。自定义配置写在这里是官方预期姿势。
Q3:外层自建反代直连 9001 报 DisallowedHost?
A:overrides.py 的 ALLOWED_HOSTS = ['127.0.0.1'],编排内 nginx 转发时 Host 恒为 127.0.0.1 所以不受影响;自建反代直连时把域名追加进该列表并重启 spug-api。
Q4:能从 SQLite 切到 MySQL 吗?
A:引擎由 MYSQL_HOST 环境变量决定(有则 MySQL,无则 SQLite),但官方没有内建的 SQLite→MySQL 数据迁移命令;正式使用请在首次部署就配好数据库,避免事后再迁。
Q5:任务计划的时间不对?
A:三查:TZ 是否合法 zoneinfo 名、是否写进了编排 environment(不是只改系统时区)、改动后是否重启了编排。任务计划与时区的关系是 v4.1.0 起的明确行为。
七、总结与参考链接
Spug v4.1.1 的配置体系是「环境变量驱动 + 单文件覆盖」的简洁设计:部署期只调 MYSQL_*/TZ/SPUG_ADMIN_* 几个变量,运行期定制集中在 overrides.py,Redis 键名与目录常量透明可查。掌握 4.1/4.2 两张参数表即可覆盖绝大多数调优与排障场景。账号、升级与服务进程的命令行操作见 《Spug v4.1.1 常用 CLI 命令详解》。
参考链接:
- 部署篇(编排与环境变量实操):《Spug v4.1.1 Docker Compose 部署指南》
- 官方文档:https://spug.cc/docs/about-spug/
- 更新日志(v4.1.0 行为变更:时区、开放 API):https://spug.cc/docs/change-log/
- GitHub 仓库(4.0 分支源码):https://github.com/openspug/spug