Redmine 折腾记:从 Docker 部署到项目管理、插件扩展与 AI 集成

日期:2026-10-19
标签:#Redmine #Docker #项目管理 #敏捷开发 #AI #技术实践
环境:Redmine 7.0.2、PostgreSQL 16、Docker Compose、群晖 NAS、Nginx Proxy Manager

一、为什么重新选择 Redmine?

最近一直在寻找一套适合个人及小型团队的项目管理系统。

此前先后了解和尝试过 OpenProject、Leantime、YouTrack 等工具。它们各有优势,但也存在一些问题:有的部署和维护复杂,有的功能受到商业版本限制,有的在反向代理环境下容易出现访问问题。

Redmine 是一款比较传统的开源项目管理工具,界面谈不上现代,但有几个吸引我的特点:

  • 免费开源,核心项目管理功能完整。
  • 支持项目、任务、缺陷、工时、Wiki、版本和甘特图。
  • 支持多项目管理和细粒度权限控制。
  • 有比较成熟的插件扩展机制。
  • 支持 Docker 部署,可以自行维护数据库和数据。
  • 相比一些现代项目管理平台,更容易掌握和控制自己的数据。

因此决定重新部署 Redmine,并尝试把它作为统一的项目管理平台。

今天花了不少时间,从系统部署、插件安装一路折腾到界面定制、敏捷工作流以及 AI 集成,也逐渐对 Redmine 的设计方式有了更深入的认识。

二、Docker 部署:简单,但不代表没有坑

使用官方 Docker 镜像:

  • Redmine 7.0.2
  • PostgreSQL 16 Alpine
  • Docker Compose
  • 数据库和附件使用 Volume 持久化

核心服务配置比较简单:

services:
  db:
    image: postgres:16-alpine
    restart: unless-stopped
    environment:
      POSTGRES_DB: redmine
      POSTGRES_USER: redmine
      POSTGRES_PASSWORD: "${DB_PASSWORD}"
    volumes:
      - redmine_db:/var/lib/postgresql/data

  redmine:
    image: redmine:7.0.2
    restart: unless-stopped
    depends_on:
      - db
    ports:
      - "8088:3000"
    environment:
      REDMINE_DB_POSTGRES: db
      REDMINE_DB_DATABASE: redmine
      REDMINE_DB_USERNAME: redmine
      REDMINE_DB_PASSWORD: "${DB_PASSWORD}"
    volumes:
      - redmine_files:/usr/src/redmine/files

volumes:
  redmine_db:
  redmine_files:

真正麻烦的是后面的反向代理和插件环境。

2.1 双层反向代理导致端口丢失

我的访问链路是:

浏览器
   ↓ HTTPS :7777
群晖反向代理
   ↓
Nginx Proxy Manager
   ↓
Redmine :3000

访问首页正常,但登录、保存或其他页面跳转时,有时会丢掉外部的 7777 端口。

排查过程中认识了三个重要请求头:

Host: redmine.example.com:7777
X-Forwarded-Host: redmine.example.com:7777
X-Forwarded-Proto: https

Nginx 的 $host 通常不保留原始 Host 中的端口,而 $http_host 保留客户端传入的完整 Host。

此外,Rails 在生成 URL 时也可能参考 X-Forwarded-Host。因此,不能只修改一处 Host 就认为问题已经解决。

Redmine 后台也需要设置正确的外部地址:

管理 → 配置 → 一般 → 主机名称和路径

例如:

redmine.example.com:7777

这次得到的经验是:遇到跳转异常,首先应检查 HTTP 响应中的 Location 和反向代理实际传递的请求头,避免在应用层反复修改无关配置。

2.2 浏览器缓存和 HTTP 重定向

浏览器可能缓存永久重定向,因此 URL 异常也不一定完全来自当前服务端配置。

可以通过浏览器 F12 的 Network 查看:

  • Request URL
  • HTTP 状态码
  • Response Headers 中的 Location

这比单纯清除 Cookie 更有针对性。

三、Redmine 插件生态:丰富,但安装体验比较传统

这是今天比较深刻的感受。

Redmine 的插件生态确实丰富,但远不如 WordPress 那样方便。

很多插件的安装流程仍然是:

  1. 下载插件源码。
  2. 复制到 plugins 目录。
  3. 安装 Ruby Gem 依赖。
  4. 执行数据库迁移。
  5. 重启 Redmine。
  6. 必要时编译静态资源。

其中最麻烦的是 Ruby 依赖和版本兼容性。

我不希望为了安装几个插件专门维护一个自定义 Dockerfile,所以选择继续使用官方镜像,通过宿主机挂载插件目录管理代码。

3.1 主要研究的插件

插件 作用 认识
Dashboard 任务看板 适合项目内任务管理
Agile 敏捷看板 适合状态流转及敏捷实践
Checklists 任务检查清单 适合标准化执行步骤
Issue Templates 问题模板 减少重复填写
Time Logger 工时计时 补充原生工时功能
View Customize 页面定制 灵活性很高
SSO Suite 单点登录 安装简单,但遇到了兼容问题
AI Helper AI 辅助项目管理 功能强大,安装和配置更复杂

并不是所有插件都值得安装。尤其在 Redmine 7 和较新的 Rails、Ruby 环境下,插件声称兼容也不能保证实际启动成功。

3.2 Dashboard 缺少 slim-rails

安装 Dashboard 后,遇到:

Could not find gem 'slim-rails' in locally installed gems.

这说明插件需要的 Ruby Gem 没有安装。

可以在 Redmine 根目录检查并安装依赖:

cd /usr/src/redmine
bundle check
bundle install

不过,Docker 官方镜像中的 Gem 如果直接安装在容器文件系统内,重新创建容器后可能丢失。

这也是不使用自定义镜像所需要承担的维护成本。

3.3 Bundler 国内镜像的问题

由于网络原因,执行 bundle install 时连接 RubyGems 比较困难。

尝试通过 Bundler 配置镜像:

---
BUNDLE_MIRROR__HTTPS://RUBYGEMS__ORG/: "https://mirrors.tuna.tsinghua.edu.cn/rubygems/"
BUNDLE_TIMEOUT: "30"
BUNDLE_RETRY: "2"

再把配置文件挂载到容器。

过程中还遇到了两类错误:

Gem sources must be absolute. You provided '/'.

以及:

SSL alert handshake failure

前者需要检查 Bundler 配置格式;后者属于 HTTPS/TLS 连接问题,不能简单归因于插件。

最终的经验是:先验证镜像站网络连通性,再运行 Bundler,而不是看到依赖缺失就反复安装。

另外,日志中反复出现:

Your Gemfile lists the gem puma more than once.

这属于 Gemfile 重复声明警告,不应直接把它当成 Redmine 无法启动的根因。

四、SSO 集成:一个 Zeitwerk 命名错误

希望让 Redmine 使用群晖 SSO 登录,因此尝试了 Redmine SSO Suite。

插件不需要复杂的 Gem 安装,但启动时遇到了真正的兼容性问题:

uninitialized constant RedmineSsoSuite::Version
Did you mean? RedmineSsoSuite::VERSION

这是 Rails Zeitwerk 自动加载机制发现的命名不一致。

插件文件使用了:

module RedmineSsoSuite
  VERSION = '...'
end

而自动加载器期望文件提供:

RedmineSsoSuite::Version

通过在保留原常量的前提下补充兼容定义,解决了这次启动异常。

例如:

Version = VERSION

当然,这属于针对当前问题的临时兼容补丁,不代表插件其他功能已经完全兼容。

插件启动后,还遇到了 OAuth/OIDC 重定向地址错误地使用 localhost 的问题。

这次经验提醒我:SSO 不仅仅是填写 Client ID 和 Secret,还要保证 Redmine 对自身外部地址的认知正确。

尤其在多层反向代理环境中,Issuer、Redirect URI、外部端口都必须一致。

五、项目管理:真正需要的是整体项目看板

一开始研究 Dashboard 和 Agile 时,我发现自己其实混淆了两种看板。

5.1 任务看板和项目组合看板

任务看板的对象是问题或任务:

待办 → 进行中 → 已完成

而我更希望的是项目组合看板:

所有项目
├── 项目 A:进行中
├── 项目 B:有风险
├── 项目 C:已完成
└── 项目 D:待启动

理想的项目总览应该能够看到:

  • 项目名称和负责人。
  • 当前进度与状态。
  • 未完成任务数量。
  • 近期活动及延期风险。
  • 点击后进入项目内部。

Redmine 原生项目列表提供了基础信息,但缺乏现代化的项目组合驾驶舱。

Agile 和 Dashboard 主要解决任务级管理,并不直接等于项目组合管理。

因此,后续需要把「项目总览」与「项目内部任务看板」分开考虑。

5.2 项目关闭与归档

Redmine 原生支持:

  • 关闭项目:项目变成只读,通常仍可查询。
  • 归档项目:从日常项目列表中隐藏,但保留数据。

归档主要在管理后台操作,并不是直接在普通项目页面完成。

我认为合理的项目生命周期应该是:

计划中 → 进行中 → 已完成 → 关闭 → 归档

这里的前几步属于项目管理流程,后两步使用 Redmine 原生的关闭与归档能力。

归档不会删除数据,也不会自动减少存储空间。

六、敏捷工作流:减少状态比增加状态更重要

Redmine 默认使用「新建、进行中、已解决、已关闭」等问题状态。

今天认真思考后发现,对个人开发和小型团队而言,过多状态可能只会增加操作成本。

尤其是「已解决」和「已关闭」,如果没有专门的测试或验收角色,两者的区别其实并不大。

我准备尝试更简单的三状态流程:

待办 → 进行中 → 已完成

状态 定义
待办 已决定处理,但未开始
进行中 正在开发、测试或处理
已完成 满足完成标准,不需要进一步操作

如果未来有独立的测试、评审或验收环节,再增加「待验收」。

Redmine 中,问题是否属于关闭状态,并不完全由状态名称决定,而取决于「管理 → 问题状态」中的「问题已关闭」标记。

因此,可以把「已关闭」重命名为「已完成」,并继续将其视为关闭状态。

另外,可以保留一个特殊的「已取消」状态,用于区分真正完成的任务和决定不再执行的任务。

这里最重要的并不是把看板做得多复杂,而是明确什么叫“完成”。

七、工时管理:Redmine 原生能力基本够用

Redmine 自带工时登记,能够关联项目、问题、活动和日期。

其中一个实用配置是设置默认工时活动。

进入:

管理 → 枚举值 → 活动(时间跟踪)

可以指定全局默认活动,例如「开发」。

项目还可以单独启用或禁用相应活动。

对于实际使用,我觉得不必把工时分类做得特别复杂,初期保留几类即可:

  • 开发
  • 测试
  • 设计
  • 项目管理

另外,Redmine 的问题详情页虽然可以通过「编辑」修改状态,但缺少足够直接的「解决」「关闭」快捷按钮。

问题列表右键修改状态反而更加方便。

这也是 Redmine 传统界面在操作效率上的不足之一。

八、View Customize:最有价值的界面扩展工具

今天发现比较有潜力的插件是 Redmine View Customize。

它支持在管理后台编写 HTML、CSS、JavaScript,根据 URL 匹配规则修改页面。

与为了每个小功能单独安装插件相比,它更适合解决一些轻量界面定制需求。

8.1 在「我的工作台」添加项目列表

Redmine 原生「我的工作台」更侧重问题、活动和工时,没有足够理想的项目组合入口。

通过 View Customize,可以在 /my/page 注入 JavaScript,读取 /projects 页面,提取项目名称和链接,再显示成项目卡片。

配置示例:

Path pattern: ^/my/page/?$
Type: JavaScript
Insertion position: Bottom of all pages

最初尝试通过 REST API:

/users/current.json?include=memberships

但遇到了用户名密码认证弹窗。

由于不希望在浏览器脚本里保存 API Key,后来改为读取原生 /projects HTML 页面。

这个办法的优点是不需要额外 API 认证,而且能够复用当前网页登录会话。

缺点是依赖页面 DOM 结构,主题升级或 Redmine 版本变化后可能需要调整。

随后又把原来的表格改成响应式卡片,提高了工作台的可读性。

8.2 首页跳转到我的工作台

还尝试通过 View Customize,将 Redmine 首页 / 自动跳转到 /my/page。

核心实现非常简单:

if (window.location.pathname === "/") {
  window.location.replace("/my/page");
}

不过,是否执行还涉及登录状态判断、规则匹配和脚本注入位置。

这一项还需要继续验证和完善,不应把代码简单保存就视为已经实现。

8.3 一个新的认识

View Customize 的优势是修改界面和交互,但它不是完整的后端扩展框架。

适合用它实现:

  • 自定义工作台内容。
  • 改善项目卡片样式。
  • 添加快捷导航入口。
  • 调整表格、菜单及页面布局。

不适合依靠它实现复杂的数据管理、权限绕过或数据库业务逻辑。

涉及数据修改的功能,仍然应该使用 Redmine 正式提供的服务端接口并遵守权限控制。

九、AI Helper:Redmine 开始具备 AI 管理能力

今天还尝试安装了 Redmine AI Helper。

它吸引我的地方不只是增加一个 AI 聊天框,而是能够结合 Redmine 中已有的项目信息,辅助完成任务分析和项目管理。

主要能力包括:

  • 查询与总结问题。
  • 辅助拆分任务。
  • 搜索相似问题。
  • 分析项目健康情况。
  • 生成项目相关报告。
  • 接入不同大模型。
  • 通过 MCP 与外部 AI 工具协作。

9.1 安装时遇到的问题

首先出现:

Missing secret_key_base for 'production'

这是 Rails 在生产环境执行数据库迁移时没有正确获取密钥,而不是 AI 模型配置问题。

随后 PostgreSQL 又出现:

relation "ai_helper_settings" does not exist

说明插件尝试访问尚未创建的数据表,或迁移尚未完整完成。

这次认识到:Redmine 插件能够出现在管理页面,不代表安装已经完整完成。

仍然需要检查数据库迁移状态和实际功能。

9.2 AI Helper 的全局与项目级能力

插件配置完成后,在启用了 AI Helper 的项目中可以看到聊天界面,但在项目外看不到。

检查插件的 Hook 代码,发现:

render_on :view_layouts_base_body_top,
          partial: "ai_helper/chat/sidebar"

这说明插件使用了 Redmine 全局页面布局 Hook,但实际是否显示聊天入口,还可能受到模板内部、当前项目上下文和权限判断影响。

同时需要区分两件事:

跨项目查询能力,不等于聊天入口能在所有页面显示。

这是今天比较重要的认识。

AI Helper 可以帮助查询和分析多个项目,但它并不天然等于一个全局 AI 项目组合管理界面。

未来可能需要进一步定制全局入口,或者直接通过 MCP 让外部 AI Agent 访问 Redmine。

十、今天最重要的几个经验

经过这一整天的部署和配置,对 Redmine 有了更清晰的认识。

第一,Redmine 的优势在后端管理能力,而不在默认界面。

项目、任务、权限、工作流和工时能力比较完整,但使用体验需要适当定制。

第二,插件不是越多越好。

每增加一个插件,就增加一个依赖和兼容性风险。尤其是 Redmine 7、Rails 8、Ruby 4 的新组合,不能仅凭插件 README 中的兼容声明判断能否正常使用。

第三,工作流应该尽可能简单。

敏捷管理更重要的是透明、快速流转和明确完成标准,而不是创建更多的问题状态。

第四,项目管理与任务管理需要两个视角。

项目组合视图负责回答“哪些项目需要关注”,任务看板负责回答“具体哪些事情需要执行”。

第五,AI 的价值不应该停留在聊天。

真正有意义的是让 AI 读取项目上下文,帮助分析进度、识别风险、生成报告,并与现有开发工具形成协作。

十一、下一步计划

今天先完成了 Redmine 的初步部署和功能探索,接下来准备继续完善:

  • 优化「我的工作台」,形成真正的跨项目入口。
  • 完善三状态敏捷工作流,统一任务处理方式。
  • 解决 AI Helper 在项目外缺少聊天入口的问题。
  • 验证群晖 SSO 登录的完整流程。
  • 减少功能重复、维护成本高的插件。
  • 评估通过 MCP 与外部 AI Agent 集成的实际价值。

结语

今天最大的感受是:Redmine 是一个成熟、可扩展的项目管理底座,但要把它变成顺手的工作平台,仍然需要花时间做减法和适度定制。

与其不断寻找功能更多的新项目管理软件,不如先明确自己真正需要的工作流程,再决定保留什么、扩展什么。

目前来看,我需要的并不是一套复杂的企业级项目管理系统,而是一个能够统一管理多个项目、快速处理任务、记录工时,并逐步接入 AI 能力的轻量工作平台。

Redmine 有机会承担这个角色。

但接下来的重点,应该从“安装更多插件”转向“减少操作成本,让系统真正用起来”。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注