Taiga 6.10 配置详解:五份配置文件逐段精讲
Taiga 6.10 五份配置文件逐段精讲:config.py、conf.json、events/protected 双 .env、Nginx location 与 systemd 单元,含修改生效路径与三条硬约束排障实录。
Taiga 6.10 配置详解:五份配置文件逐段精讲
Taiga 单机部署没有「一个配置文件管所有」的幸运:一个实例要维护五份配置——taiga-back 的 settings/config.py、taiga-front-dist 的 dist/conf.json、taiga-events 的 .env、taiga-protected 的 .env,加上 Nginx 站点文件与 systemd 单元。它们之间存在三条硬约束:SECRET_KEY 三处一致、浏览器与服务器地址口径一致、每份配置改完后的生效路径不同。本文基于 Ubuntu 22.04 实测环境(back 6.10.2 / front-dist 6.10.3 / events 6.10.0 / protected 6.10.1,服务器 10.89.73.10)逐段拆解,安装过程见《Ubuntu 22.04 安装 Taiga 6.10 指南》。
一、配置全景与生效路径
| 文件 | 所属模块 | 格式 | 改完后的生效动作 |
|---|---|---|---|
| /home/taiga/taiga-back/settings/config.py | taiga-back + taiga-async | Python | systemctl restart taiga taiga-async |
| /home/taiga/taiga-front-dist/dist/conf.json | 浏览器端前端 | JSON | 无需重启,浏览器强刷(Ctrl+F5) |
| /home/taiga/taiga-events/.env | taiga-events | dotenv | systemctl restart taiga-events |
| /home/taiga/taiga-protected/.env | taiga-protected | dotenv | systemctl restart taiga-protected |
| /etc/nginx/conf.d/taiga.conf | Nginx | nginx conf | sudo nginx -t && sudo systemctl restart nginx |
systemd 单元本身一般不动;要调 worker 数、并发数时改单元文件后需 sudo systemctl daemon-reload 再重启对应服务。
三条硬约束:
- SECRET_KEY 三处一致:config.py 的
SECRET_KEY、events.env的SECRET、protected.env的SECRET_KEY必须是同一个字符串。events 用它校验前端 JWT,protected 用它签发附件下载令牌,任何一处不一致都不会在启动时报错,只会在运行期表现为静默失败。 - TAIGA_SITES_DOMAIN 与 conf.json 的 api/eventsUrl 指向同一个对外地址:前者决定后端生成的绝对 URL(邮件链接、sitemap、资源地址),后者决定浏览器请求打向哪里。
- 开关型配置双侧同开:如公开注册需同时改后端
PUBLIC_REGISTER_ENABLED = True(Python 大写)与前端 conf.json 的"publicRegisterEnabled": true(JSON 小写),官方文档特别强调大小写不是笔误。
二、taiga-back:settings/config.py
config.py 基于 settings/config.py.prod.example 生成,头部 from .common import * 继承全部默认值,因此「没写的就用 common.py 默认」。以下按段拆解。
2.1 数据库段 DATABASES
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'taiga',
'USER': 'taiga',
'PASSWORD': 'q1w2e3r4',
'HOST': '127.0.0.1',
'PORT': '5432',
}
}
样例里 HOST/PORT 为空串(走本机 Unix socket)。显式写 127.0.0.1:5432 走 TCP 更直观,也便于日后把数据库迁到独立主机。Taiga 仅支持 PostgreSQL,无 MySQL 驱动。
2.2 站点段:SECRET_KEY、TAIGA_URL、SITES
SECRET_KEY = "tk7vXq2mLp9wR4nZ8eYs3Ja6Hf1dC0ug"
TAIGA_SITES_SCHEME = "http"
TAIGA_SITES_DOMAIN = "10.89.73.10"
FORCE_SCRIPT_NAME = ""
TAIGA_URL = f"{ TAIGA_SITES_SCHEME }://{ TAIGA_SITES_DOMAIN }{ FORCE_SCRIPT_NAME }"
SITES = {
"api": { "name": "api", "scheme": TAIGA_SITES_SCHEME, "domain": TAIGA_SITES_DOMAIN },
"front": { "name": "front", "scheme": TAIGA_SITES_SCHEME, "domain": f"{ TAIGA_SITES_DOMAIN }{ FORCE_SCRIPT_NAME }" }
}
DEFAULT_PROJECT_SLUG_PREFIX = False
要点:
SECRET_KEY参与加密签名(JWT 签发、重置口令令牌),生产必须换成随机长串,并与 events/protected 保持一致;更换它会使所有已登录会话失效。- 三个站点变量决定
TAIGA_URL,进而影响邮件里的链接、导出文件里的资源地址。反代后如果链接域名不对,先查这里。 - 子路径部署:Taiga 既可部署在独立域名/端口(本例),也可挂在子路径(如 https://example.com/taiga/)。子路径模式需三处联动:`FORCE_SCRIPT_NAME = "/taiga"
、conf.json 的"baseHref": "/taiga/"加 api/eventsUrl 带前缀、以及 front-dist 的dist/index.html中<base href="/">改为<base href="/taiga/">`,Nginx 相应把 location 都挪到 /taiga/ 前缀下(官方文档有完整模板)。 DEFAULT_PROJECT_SLUG_PREFIX = False表示项目 URL 不再带用户名前缀(样例默认值即是 False)。
2.3 静态与媒体段
MEDIA_URL = f"{ TAIGA_URL }/media/"
DEFAULT_FILE_STORAGE = "taiga_contrib_protected.storage.ProtectedFileSystemStorage"
THUMBNAIL_DEFAULT_STORAGE = DEFAULT_FILE_STORAGE
STATIC_URL = f"{ TAIGA_URL }/static/"
DEFAULT_FILE_STORAGE 指向 protected 插件后,附件不再从 Django 直接下发,而是生成带时限令牌的 URL 交给 Nginx/protected 处理。MEDIA_ROOT/STATIC_ROOT 注释掉即用 common.py 默认值:/home/taiga/taiga-back/media 与 /home/taiga/taiga-back/static(后者由 collectstatic 填充,实测 1008 个文件)。
2.4 邮件段
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' # 实验:打印到 stdout
# 生产:
# EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
DEFAULT_FROM_EMAIL = 'noreply@example.com'
EMAIL_USE_TLS = True
EMAIL_HOST = 'smtp.example.com'
EMAIL_PORT = 587
EMAIL_HOST_USER = 'user'
EMAIL_HOST_PASSWORD = 'password'
CHANGE_NOTIFICATIONS_MIN_INTERVAL = 120 # 秒,通知合并间隔
样例里 EMAIL_USE_TLS 与 EMAIL_USE_SSL 同时为 True 是占位写法,实际二选一(587 用 TLS,465 用 SSL)。切到 console 后端时,邮件内容出现在 taiga-async(批量通知)与 taiga(同步通知)的 journal 日志里。
2.5 事件与异步段(RabbitMQ 双连接)
EVENTS_PUSH_BACKEND = "taiga.events.backends.rabbitmq.EventsPushBackend"
EVENTS_PUSH_BACKEND_OPTIONS = {
"url": "amqp://taiga:q1w2e3r4@127.0.0.1:5672/taiga"
}
CELERY_ENABLED = os.getenv('CELERY_ENABLED', 'True') == 'True'
CELERY_BROKER_URL = "amqp://taiga:q1w2e3r4@127.0.0.1:5672/taiga"
CELERY_RESULT_BACKEND = None
CELERY_ACCEPT_CONTENT = ['pickle', ]
CELERY_TASK_SERIALIZER = "pickle"
CELERY_RESULT_SERIALIZER = "pickle"
CELERY_TASK_DEFAULT_QUEUE = 'tasks'
要点:
- back 向 RabbitMQ 推事件、投任务;events 与 celery 分别消费。URL 里的
/taiga是 vhost 名,与 3.3 节创建的一致。 CELERY_ENABLED从环境变量读,systemd 单元没设该变量时默认 True(celery 正常工作);跑一次性管理命令(如 migrate、createsuperuser)时官方命令行临时置 False,避免命令进程连 MQ。- 任务序列化用 pickle,这是官方选择,也意味着 broker 必须做好访问控制(不要把 5672 暴露到公网)。
CELERY_RESULT_BACKEND = None:任务结果不落库。
2.6 其他高频开关
ENABLE_TELEMETRY = False # 匿名遥测上报,内网环境建议关
PUBLIC_REGISTER_ENABLED = False # 公开注册总开关(后端侧)
DEBUG = False # 生产必须 False
DEBUG 在样例顶部已置 False;切勿在生产开 True,它会向前端暴露完整报错栈。限流(REST_FRAMEWORK 的 throttle rates)在样例中以注释形式给出,按需启用。
三、taiga-front-dist:dist/conf.json
conf.json 由 dist/conf.example.json 复制而来,是浏览器加载的唯一动态配置。核心字段:
{
"api": "http://10.89.73.10/api/v1/",
"eventsUrl": "ws://10.89.73.10/events",
"baseHref": "/",
"defaultLanguage": "en",
"rtlLanguages": ["he", "ar", "fa"],
"publicRegisterEnabled": false,
"feedbackEnabled": true,
"privacyPolicyUrl": null,
"termsOfServiceUrl": null,
"maxUploadFileSize": null,
"supportUrl": "https://tree.taiga.io/support",
...
}
3.1 必改字段
| 字段 | 说明 |
|---|---|
| api | 后端 API 根地址,末尾必须带斜杠,写法 http://<域名或IP>/api/v1/ |
| eventsUrl | WebSocket 地址,http 站点用 ws://,https 站点用 wss:// |
| baseHref | 根路径部署写 /,子路径部署写 /taiga/(并同步改 index.html) |
3.2 常用可选字段
| 字段 | 说明 |
|---|---|
| defaultLanguage | 默认界面语言,中文界面可写 "zh-hans" |
| publicRegisterEnabled | 登录页是否显示注册入口,须与后端 PUBLIC_REGISTER_ENABLED 同开同关 |
| maxUploadFileSize | 前端上传大小限制(字节),null 用后端默认;Nginx 侧还有 client_max_body_size 要联动 |
| feedbackEnabled | 是否显示「反馈」按钮 |
验证 conf.json 是否被正确服务:
curl -s http://127.0.0.1/conf.json | python3 -c 'import json,sys; d=json.load(sys.stdin); print(d["api"], "|", d["eventsUrl"])'
回显:
http://10.89.73.10/api/v1/ | ws://10.89.73.10/events
四、两份 .env:events 与 protected
4.1 taiga-events/.env
RABBITMQ_URL="amqp://taiga:q1w2e3r4@127.0.0.1:5672/taiga"
WEB_SOCKET_SERVER_PORT=8888
APP_PORT=3023
SECRET="tk7vXq2mLp9wR4nZ8eYs3Ja6Hf1dC0ug"
ALGORITHM="HS256"
AUDIENCE=
ISSUER=
USER_ID_CLAIM="user_id"
LOG_LEVEL="info"
WEB_SOCKET_SERVER_PORT=8888是 Nginx 代理目标,APP_PORT=3023是内部健康检查/HTTP 端口,两者都不要与业务端口冲突。SECRET与 back 的 SECRET_KEY 一致;JWT 默认 HS256,AUDIENCE/ISSUER 留空即可。- 排障时把 LOG_LEVEL 调到 debug,重启后 journalctl -u taiga-events 观察握手与订阅。
4.2 taiga-protected/.env
SECRET_KEY=tk7vXq2mLp9wR4nZ8eYs3Ja6Hf1dC0ug
MAX_AGE=300
TAIGA_SUBPATH=
MAX_AGE:附件下载令牌有效期(秒),默认 300;过期后前端会自动向 API 换新令牌。TAIGA_SUBPATH:子路径部署时写/taiga。- 此文件键值不带引号,与 events 的 .env 风格不同,照抄样例即可。
五、Nginx 站点配置逐段解析
完整站点文件见安装指南 9.1 节,这里解释四个关键 location:
(1)静态前端 location /
location / {
alias /home/taiga/taiga-front-dist/dist/;
index index.html;
try_files $uri $uri/ index.html =404;
}
AngularJS 单页应用依赖 history 路由,try_files ... index.html 保证任意前端路径都回落到入口文件。实测坑:alias 与 try_files 组合在部分 Nginx 版本有路径拼接歧义,若遇到诡异 404,可把 alias 换成等效的 root /home/taiga/taiga-front-dist/dist;(location 为 / 时两者等价)。更常见的 404 根因是家目录 750 权限(见 5.3 排障)。
(2)受保护附件三件套
location /_protected/ {
internal; # 只允许内部跳转,外部直接访问 404
alias /home/taiga/taiga-back/media/;
add_header Content-disposition "attachment";
}
location /media/ {
proxy_pass http://127.0.0.1:8003/; # 交给 taiga-protected 校验令牌
}
浏览器拿到的附件 URL 先打到 protected 服务(8003),后者校验 JWT 令牌后向 Nginx 发内部重定向(X-Accel-Redirect)落到 /_protected/,由 Nginx 直接从磁盘发文件。internal 指令是附件防直链的关键。实测无令牌请求 GET /media/ 返回 404(Django 风格 NOT FOUND,232 字节),链路符合预期。
(3)WebSocket location /events
location /events {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_connect_timeout 7d;
proxy_send_timeout 7d;
proxy_read_timeout 7d;
proxy_pass http://127.0.0.1:8888/events;
}
三条超时拉到 7 天防止长连接被 Nginx 回收;缺 Upgrade/Connection 头会导致握手降级失败,前端表现为看板不实时刷新。
(4)全局项:client_max_body_size 50M(上传上限,与 conf.json 的 maxUploadFileSize 联动)、large_client_header_buffers 4 32k(兼容长 JWT 头)。
六、systemd 单元要点
四个单元的参数没有玄学,只有三个可调点:
| 单元 | 关键参数 | 说明 |
|---|---|---|
| taiga.service | gunicorn --workers 4 | API 并发,CPU 核数×1~2 常见;低配机器降到 2 |
| taiga-async.service | celery --concurrency 4 | 任务并发;--worker -B 表示 worker+beat 合体 |
| taiga-events.service | ExecStart 绝对路径 | 官方模板 npm 裸命令在 systemd 下可能 PATH 失败,写 /usr/bin/npm |
| taiga-protected.service | gunicorn --workers 4 | 附件流量小,2 已够 |
两个单元都有 Restart=always + RestartSec=3,进程崩溃自动拉起。WantedBy=default.target(官方模板)在多用户服务器上等效 graphical/multi-user target,可保持不动。
七、排障实录:三个配置相关故障
7.1 首页 404:家目录权限
现象与修复过程已在安装指南 9.2 节完整记录:adduser 默认 750 家目录导致 Nginx(www-data)stat 失败,错误日志 Permission denied,chmod 755 /home/taiga 后恢复。凡静态资源 404 且 API 正常,先看 /home/taiga/logs/nginx.error.log。
7.2 附件下载 403/404:SECRET 不一致
protected 用 SECRET_KEY 验签,back 用 SECRET_KEY 签发,两边不一致时附件链接永远失效,且 protected 日志只有低调的验签失败。排查口诀:三个配置文件里的密钥串 diff 一下。
7.3 改了 conf.json 不生效
conf.json 是浏览器级配置:服务端无状态、Nginx 直接发文件。生效路径是强刷浏览器(Ctrl+F5)清掉缓存的旧 JSON;确认方法即 3 节的 curl 校验。不要去重启任何 systemd 服务。
八、配置核对清单
上线前按序核对:
grep SECRET_KEY taiga-back/settings/config.py taiga-events/.env taiga-protected/.env三值一致(events 里叫 SECRET)。- config.py 的 TAIGA_SITES_DOMAIN 与 conf.json 的 api/eventsUrl 同域同协议。
- https 站点:conf.json 用 wss://,TAIGA_SITES_SCHEME = "https",Nginx 加 443 server 块与证书。
- 公开注册:后端 True + 前端 true 双开。
- 上传大小:Nginx client_max_body_size ≥ conf.json maxUploadFileSize。
- 每份配置改动后按第一节表格执行对应生效动作。
- 重启后跑一遍安装指南 10.1 节的验证清单。
日常启停、备份与更深入的排障见《Taiga 6.10 运维命令手册:服务、备份与排障》。