Taiga 6.10 配置详解:五份配置文件逐段精讲

Taiga 6.10 五份配置文件逐段精讲:config.py、conf.json、events/protected 双 .env、Nginx location 与 systemd 单元,含修改生效路径与三条硬约束排障实录。

TaigaTaigaUbuntu 22.04DjangoPostgreSQLRabbitMQ2026/10/28

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.pytaiga-back + taiga-asyncPythonsystemctl restart taiga taiga-async
/home/taiga/taiga-front-dist/dist/conf.json浏览器端前端JSON无需重启,浏览器强刷(Ctrl+F5)
/home/taiga/taiga-events/.envtaiga-eventsdotenvsystemctl restart taiga-events
/home/taiga/taiga-protected/.envtaiga-protecteddotenvsystemctl restart taiga-protected
/etc/nginx/conf.d/taiga.confNginxnginx confsudo nginx -t && sudo systemctl restart nginx

systemd 单元本身一般不动;要调 worker 数、并发数时改单元文件后需 sudo systemctl daemon-reload 再重启对应服务。

三条硬约束:

  1. SECRET_KEY 三处一致:config.py 的 SECRET_KEY、events .env 的 SECRET、protected .env 的 SECRET_KEY 必须是同一个字符串。events 用它校验前端 JWT,protected 用它签发附件下载令牌,任何一处不一致都不会在启动时报错,只会在运行期表现为静默失败。
  2. TAIGA_SITES_DOMAIN 与 conf.json 的 api/eventsUrl 指向同一个对外地址:前者决定后端生成的绝对 URL(邮件链接、sitemap、资源地址),后者决定浏览器请求打向哪里。
  3. 开关型配置双侧同开:如公开注册需同时改后端 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/
eventsUrlWebSocket 地址,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.servicegunicorn --workers 4API 并发,CPU 核数×1~2 常见;低配机器降到 2
taiga-async.servicecelery --concurrency 4任务并发;--worker -B 表示 worker+beat 合体
taiga-events.serviceExecStart 绝对路径官方模板 npm 裸命令在 systemd 下可能 PATH 失败,写 /usr/bin/npm
taiga-protected.servicegunicorn --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 服务。

八、配置核对清单

上线前按序核对:

  1. grep SECRET_KEY taiga-back/settings/config.py taiga-events/.env taiga-protected/.env 三值一致(events 里叫 SECRET)。
  2. config.py 的 TAIGA_SITES_DOMAIN 与 conf.json 的 api/eventsUrl 同域同协议。
  3. https 站点:conf.json 用 wss://,TAIGA_SITES_SCHEME = "https",Nginx 加 443 server 块与证书。
  4. 公开注册:后端 True + 前端 true 双开。
  5. 上传大小:Nginx client_max_body_size ≥ conf.json maxUploadFileSize。
  6. 每份配置改动后按第一节表格执行对应生效动作。
  7. 重启后跑一遍安装指南 10.1 节的验证清单。

日常启停、备份与更深入的排障见《Taiga 6.10 运维命令手册:服务、备份与排障》。