Kanboard 1.2.56 配置参数详解

Kanboard 1.2.56 全量配置参数详解:config.php 与环境变量双入口加载优先级、DB/MAIL/LDAP/反代/认证会话/安全头逐域参数表与默认值,附 SQLite/PostgreSQL 生产模板与 PHP 8.5 MySQL 驱动兼容等实测排障。

KanboardKanboard看板自托管PHP 应用2026/10/24

Kanboard 1.2.56 配置参数详解

目标:系统讲解 Kanboard 1.2.56 的全部配置参数——两个配置入口(config.php 与环境变量)的加载优先级、按域分类的参数详解(路径/数据库/邮件/LDAP/反向代理/认证会话/安全头/插件/HTTP 客户端)、生产配置模板与典型排障。全文参数默认值取自 v1.2.56 源码(config.default.php 共 300 行 + app/constants.php 共 103 个环境变量常量),行为类结论均在本站部署环境实测取证。

一、环境信息

  • 操作系统:Ubuntu 22.04 LTS(x86_64)
  • Kanboard:v1.2.56(源码树 /var/www/kanboard/,标准 tar 包部署视角;官方 Docker 形态的应用根为 /var/www/app,参数体系完全一致)
  • 运行时:PHP 8.5.12 + nginx(官方 Docker 形态)
  • 数据库:默认 SQLite(data/db.sqlite)
  • 源码取证:config.default.php(300 行参数字典)与 app/constants.php(103 个 getenv() 常量定义)逐行核对,查询/实测日期 2026-10-23
  • 验证通道:healthcheck.php(HTTP 接口)、JSON-RPC API(/jsonrpc.php,HTTP Basic 认证)、debug.log(日志文件)

二、前置条件

  • 已完成 Kanboard 1.2.56 部署并能访问 Web 界面(部署流程见本站部署篇);本文所有参数修改后需重载服务生效。
  • 能读取应用源码目录(参数字典就在里面,不依赖外部文档):
cat /var/www/kanboard/config.default.php | head -20

实测回显(文件头部):

<?php

/*******************************************************************/
/* Rename this file to config.php if you want to change the values */
/*                                                                 */
/* Make sure all paths are absolute by using __DIR__ where needed  */
/*******************************************************************/

// Data folder (must be writeable by the web server user and absolute)
define('DATA_DIR', __DIR__.DIRECTORY_SEPARATOR.'data');

// Enable/Disable debug
define('DEBUG', false);

三、参数查看与修改方式

本节先解决「配置从哪来、怎么看当前生效值、怎么改才生效」三个基础问题,再进入逐参数详解。

3.1 两个配置入口与加载优先级

v1.2.56 的配置装载链在 app/common.php 中固定为以下顺序(源码实测):

// app/common.php 装载顺序(节选)
$dbUrlParser = new PicoDb\UrlParser();
if ($dbUrlParser->isEnvironmentVariableDefined()) {   // 1. DATABASE_URL 环境变量
    define('DB_DRIVER', $dbSettings['driver']);       //    直接定义 DB_* 常量
    ...
}
$config_file = __DIR__.'/../data/config.php';         // 2. data/config.php
if (file_exists($config_file)) { require $config_file; }
$config_file = __DIR__.'/../config.php';              // 3. 应用根 config.php
if (file_exists($config_file)) { require $config_file; }
require __DIR__.'/constants.php';                     // 4. 兜底默认值

constants.php 对每个常量的写法是 defined('X') or define('X', getenv('X') ?: 默认值)——因此得到完整优先级链:

优先级配置来源说明
1(最高)DATABASE_URL 环境变量PicoDb 解析,一次性定义全部 DB_* 连接常量
2data/config.php数据目录内配置文件(升级时不会被覆盖,官方推荐自定义位置)
3config.php(应用根)经典入口:cp config.default.php config.php 后修改
4进程环境变量(getenv)官方 Docker 形态编排的主要注入方式
5(最低)代码内默认值config.default.php 只是字典模板,运行时并不加载

💡 说明:config.default.php 头部注释即官方用法——"Rename this file to config.php if you want to change the values"。tar 包部署的标准做法是整文件复制改名后按需修改;官方 Docker 形态则预置了一份仅含两行覆写的 config.php(ENABLE_URL_REWRITE=true、LOG_DRIVER=system),其余走环境变量。

3.2 查看当前生效值

配置是 PHP 常量,用 CLI 经完整入口读取(⚠️ 不要直接 require 'app/constants.php'——它内部依赖 build_app_version() 等函数,单独加载会报 Fatal error: Call to undefined function build_app_version(),必须经 common.php 完整装载):

cd /var/www/kanboard
php -r "require 'app/common.php'; var_dump(DB_DRIVER, LOG_DRIVER, SESSION_HANDLER, DB_WAL_MODE, HTTP_TIMEOUT, BRUTEFORCE_LOCKDOWN, SESSION_DURATION);"

实测回显:

string(6) "sqlite"
string(4) "file"
string(2) "db"
bool(true)
int(10)
int(6)
int(0)

解读:当前实例 DB_DRIVER=sqlite(默认)、LOG_DRIVER=file(已改为文件日志)、SESSION_HANDLER=db(会话入库)、DB_WAL_MODE=true(SQLite WAL 并发优化默认开)、HTTP_TIMEOUT=10 秒、BRUTEFORCE_LOCKDOWN=6 次、SESSION_DURATION=0(浏览器关闭即过期)。

3.3 修改与生效方式

修改入口文件(config.php 或环境变量)后,让 PHP 进程重新装载即可:官方 Docker 形态重启服务进程(nginx + php-fpm 由 s6 托管);tar 包 + php-fpm 形态执行 systemctl reload php-fpm。验证生效重复 3.2 的查看命令对比值即可。

四、参数总览

v1.2.56 全部可配置常量共 103 个(app/constants.php 的 getenv 定义 + 少数纯代码常量),按域分布如下:

参数域代表常量数量(约)
路径与调试DATA_DIR, FILES_DIR, CACHE_DIR, DEBUG, LOG_DRIVER, LOG_FILE8
数据库DB_DRIVER, DB_HOSTNAME, DB_PORT, DB_NAME, DB_USERNAME, DB_PASSWORD, DB_FILENAME, DB_WAL_MODE, DB_SSL_*, DB_TIMEOUT, DB_RUN_MIGRATIONS 等15
邮件MAIL_CONFIGURATION, MAIL_FROM, MAIL_TRANSPORT, MAIL_SMTP_*10
LDAPLDAP_AUTH, LDAP_SERVER, LDAP_USER_, LDAP_GROUP_29
反向代理认证REVERSE_PROXY_AUTH, REVERSE_PROXY_USER_HEADER, TRUSTED_PROXY_*8
认证与会话REMEMBER_ME_AUTH, HIDE_LOGIN_FORM, DISABLE_LOGOUT, BRUTEFORCE_, SESSION_, TOTP_ISSUER9
安全与杂项ENABLE_HSTS, ENABLE_XFRAME, API_AUTHENTICATION_HEADER, MARKDOWN_ESCAPE_HTML 等10
插件PLUGINS_DIR, PLUGIN_API_URL, PLUGIN_INSTALLER3
HTTP 客户端HTTP_PROXY_*, HTTP_TIMEOUT, HTTP_MAX_REDIRECTS, HTTP_VERIFY_SSL_CERTIFICATE7
界面与文档DASHBOARD_MAX_PROJECTS, SHOW_GROUP_MEMBERSHIPS_*, DOCUMENTATION_URL_PATTERN4

💡 技术拓展:Kanboard 的配置粒度分三层——编译期常量(本篇的 config.php/getenv,改后需重载)、数据库存储设置(Web 界面「设置」页:项目默认列、日历配置等,运行时可改、存 settings 表)、用户偏好(语言/时区,存 user_has_metadata 表)。三者优先级为用户偏好 > 数据库设置 > 常量默认值;本篇只覆盖第一层,因为它是运维与部署的主要控制面。

五、核心参数分类详解

本节按域逐参数讲解:默认值、语义、修改影响,关键域配实测取证。

5.1 路径与调试

常量默认值说明
DATA_DIR<应用根>/data数据总目录,Web 运行用户必须可写
FILES_DIR$DATA_DIR/files附件存储目录
CACHE_DIR$DATA_DIR/cache文件缓存目录
DEBUGfalse调试模式:true 时每次请求记录渲染耗时、SQL 数、内存
LOG_DRIVERsystem日志驱动:system/stdout/syslog/stderr/file
LOG_FILE$DATA_DIR/debug.logLOG_DRIVER=file 时的日志文件路径

DEBUG + LOG_DRIVER=file 实测(排障期开启):向 API 发一次认证失败请求后查看日志:

head -c 600 /var/www/kanboard/data/debug.log

实测回显:

[2026-10-23 16:31:54] [debug] APP: nb_queries=0
[2026-10-23 16:31:54] [debug] APP: rendering_time=0.045353889465332
[2026-10-23 16:31:54] [debug] APP: memory_usage=2.79M
[2026-10-23 16:31:54] [debug] APP: uri=/healthcheck.php
[2026-10-23 16:31:54] [debug] ###############################################
[2026-10-23 16:32:04] [debug] Subscriber executed: Kanboard\Subscriber\BootstrapSubscriber::execute
[2026-10-23 16:32:04] [debug] Subscriber executed: Kanboard\Subscriber\AuthSubscriber::onLoginFailure
[2026-10-23 16:32:04] [error] API authentication failure for admin
[2026-10-23 16:32:04] [debu

解读:DEBUG 开启后每请求记录 nb_queries(SQL 条数)、rendering_time、memory_usage,认证失败会落 [error] 级日志——排障利器,平时应关闭(日志增长快)。

5.2 数据库(DB_*)

常量默认值说明
DB_DRIVERsqlite驱动:sqlite/mysql/postgres/odbc/dblib/mssql
DB_FILENAME$DATA_DIR/db.sqliteSQLite 数据文件(备份=复制它)
DB_WAL_MODEtrueSQLite WAL 模式,读写并发优化
DB_HOSTNAMElocalhostMySQL/PG 主机
DB_PORTnull端口,null=驱动默认(3306/5432)
DB_NAMEkanboard库名
DB_USERNAME / DB_PASSWORDroot / 空凭据
DB_SSL_KEY / DB_SSL_CERT / DB_SSL_CAnullMySQL SSL 三件套
DB_VERIFY_SERVER_CERTnullMySQL 证书 CN 校验开关
DB_TIMEOUTnullPDO 连接/超时秒数
DB_ODBC_DSNkanboardODBC DSN
DB_RUN_MIGRATIONStrue启动自动跑库结构迁移;false 则升级时需 CLI 手工跑
DB_GROUP_PROVIDER / DB_USER_PROVIDERtrue / true组/用户提供器开关(特殊部署才关)

驱动切换行为实测(两种驱动各指向不可达主机 192.0.2.1,观察 healthcheck 回显差异):

curl -s http://localhost/healthcheck.php

mysql 驱动实测回显(v1.2.56 在 PHP 8.5 运行时下的真实告警):

{"status":503,"message":"Constant PDO::MYSQL_ATTR_INIT_COMMAND is deprecated since 8.5, use Pdo\\Mysql::ATTR_INIT_COMMAND instead"}

postgres 驱动实测回显:

{"status":503,"message":"SQLSTATE[08006] [7] connection to server at \"192.0.2.1\", port 5432 failed: timeout expired"}

解读:postgres 驱动行为正常(连接失败如实报 SQLSTATE);mysql 驱动在 PHP 8.5 下被 deprecated 常量挡在连接之前——这是 v1.2.56(官方 Docker 运行时 PHP 8.5.12)的真实兼容性问题,生产使用 MySQL 形态前必须先实测验证(或等待上游跟进修复),否则建议继续使用 SQLite/PostgreSQL 形态。

5.3 邮件(MAIL_*)

常量默认值说明
MAIL_CONFIGURATIONtrue是否允许界面配置邮件(false 则完全禁用邮件)
MAIL_FROMreplace-me@kanboard.local发件人地址,必改
MAIL_BCC空抄送归档地址
MAIL_TRANSPORTmail传输方式:mail(PHP mail 函数)/sendmail/smtp
MAIL_SMTP_HOSTNAME空SMTP 主机
MAIL_SMTP_PORT25SMTP 端口(TLS 常用 587,SSL 用 465)
MAIL_SMTP_USERNAME / MAIL_SMTP_PASSWORD空SMTP 凭据
MAIL_SMTP_HELO_NAMEnullHELO 名,null 默认
MAIL_SMTP_ENCRYPTIONnullnull(明文)/ssl/tls
MAIL_SENDMAIL_COMMAND/usr/sbin/sendmail -bssendmail 传输的命令行

生产推荐 MAIL_TRANSPORT=smtp + MAIL_SMTP_ENCRYPTION=tls(587 端口),示例:

define('MAIL_FROM', 'kanboard@example.com');
define('MAIL_TRANSPORT', 'smtp');
define('MAIL_SMTP_HOSTNAME', 'smtp.example.com');
define('MAIL_SMTP_PORT', 587);
define('MAIL_SMTP_USERNAME', 'kanboard@example.com');
define('MAIL_SMTP_PASSWORD', 'q1w2e3r4');
define('MAIL_SMTP_ENCRYPTION', 'tls');

⚠️ 注意:SMTP 密码写在 config.php 属敏感值,生产环境应控制文件权限(chmod 640 config.php、属主为运行用户),并把 config.php 纳入配置管理加密存储。

5.4 LDAP(LDAP_*,29 个)

常量默认值说明
LDAP_AUTHfalse总开关,开启后登录走 LDAP
LDAP_SERVER空形如 ldap://dc.example.com:389 或 ldaps://
LDAP_PORT389端口(URL 里带端口时以此为准)
LDAP_SSL_VERIFYtrueldaps 证书校验,自签环境置 false
LDAP_START_TLSfalse389 明文口升级 TLS
LDAP_USERNAME_CASE_SENSITIVEfalse默认把 LDAP 用户名转小写防重名
LDAP_BIND_TYPEanonymous绑定类型:anonymous/user(用户自身凭据绑)/proxy(服务账号绑)
LDAP_USERNAME / LDAP_PASSWORDnullproxy 模式的服务账号(user 模式下 USERNAME 是 DN 模板如 uid=%s,ou=People,dc=example,dc=com)
LDAP_USER_BASE_DN空用户搜索基 DN
LDAP_USER_FILTER空用户过滤器(AD:(&(objectClass=user)(sAMAccountName=%s));OpenLDAP:uid=%s)
LDAP_USER_ATTRIBUTE_USERNAMEuid用户名属性(AD 用 sAMAccountName)
LDAP_USER_ATTRIBUTE_FULLNAMEcn全名属性
LDAP_USER_ATTRIBUTE_EMAILmail邮箱属性
LDAP_USER_ATTRIBUTE_GROUPSmemberof组属性
LDAP_USER_ATTRIBUTE_PHOTO空头像属性(thumbnailPhoto/jpegPhoto)
LDAP_USER_ATTRIBUTE_LANGUAGE空语言同步属性,空=不同步
LDAP_USER_CREATIONtrue首次 LDAP 登录自动建档;false 则仅白名单用户可登录
LDAP_USER_DEFAULT_ROLE_MANAGERfalse新用户默认角色是否为 Manager(false=普通用户)
LDAP_GROUP_ADMIN_DN / LDAP_GROUP_MANAGER_DN空组→管理员/经理角色的映射 DN
LDAP_GROUP_PROVIDERfalse开启后项目权限可授权给 LDAP 组
LDAP_GROUP_BASE_DN / LDAP_GROUP_FILTER / LDAP_GROUP_USER_FILTER空组搜索基/过滤器
LDAP_GROUP_USER_ATTRIBUTEusername组过滤器中用户匹配属性:username/dn
LDAP_GROUP_ATTRIBUTE_NAMEcn组名属性
LDAP_GROUP_SYNCtrue外部认证登录时同步组

最小可用 AD 对接示例:

define('LDAP_AUTH', true);
define('LDAP_SERVER', 'ldap://dc.example.com');
define('LDAP_BIND_TYPE', 'user');
define('LDAP_USERNAME', '%s@example.com');
define('LDAP_USER_BASE_DN', 'CN=Users,DC=example,DC=com');
define('LDAP_USER_FILTER', '(&(objectClass=user)(sAMAccountName=%s))');
define('LDAP_USER_ATTRIBUTE_USERNAME', 'sAMAccountName');

💡 说明:LDAP_BIND_TYPE 三种绑定模式的选择——user 最常用(登录者凭据直接绑 DC 校验,无需服务账号);proxy 适合禁止用户直接绑定的 AD(用服务账号先搜出用户 DN);anonymous 仅当 DC 允许匿名搜索时可用。生产首选 user,权限收紧的域用 proxy。

5.5 反向代理认证与受信代理(REVERSE_PROXY_、TRUSTED_PROXY_)

常量默认值说明
REVERSE_PROXY_AUTHfalse反代认证总开关(SSO 场景)
REVERSE_PROXY_USER_HEADERREMOTE_USER用户名来源头
REVERSE_PROXY_EMAIL_HEADERREMOTE_EMAIL邮箱来源头
REVERSE_PROXY_FULLNAME_HEADERREMOTE_NAME全名来源头
REVERSE_PROXY_DEFAULT_ADMIN空指定默认管理员用户名
REVERSE_PROXY_DEFAULT_DOMAIN空邮箱补全域
TRUSTED_PROXY_HEADERS空受信取真实 IP 的头,如 HTTP_X_REAL_IP,HTTP_X_FORWARDED_FOR
TRUSTED_PROXY_NETWORKS空受信代理网段 CIDR,如 192.168.0.0/16,10.0.0.0/8

⚠️ 注意:TRUSTED_PROXY 两项在 v1.2.55 中刚经历安全修复(防止伪造代理头绕过 IP 级验证码/锁定)。配置了反代就必须同时配 TRUSTED_PROXY_NETWORKS(只信自己网段),否则攻击者可伪造 X-Forwarded-For 规避锁定。

5.6 认证与会话安全(BRUTEFORCE_、SESSION_ 等)

常量默认值说明
BRUTEFORCE_CAPTCHA3连续失败 3 次后出验证码
BRUTEFORCE_LOCKDOWN6连续失败 6 次后锁定账号
BRUTEFORCE_LOCKDOWN_DURATION15锁定分钟数
SESSION_DURATION0会话秒数,0=浏览器关闭即失效
SESSION_HANDLERdb会话存储:db(多实例共享)/php(默认文件)
REMEMBER_ME_AUTHtrue「记住我」开关
HIDE_LOGIN_FORMfalse隐藏登录表单(纯 SSO/LDAP 场景)
DISABLE_LOGOUTfalse禁用登出按钮(SSO 场景)
TOTP_ISSUERKanboard2FA 验证器应用里显示的发行方名
EXTERNAL_AUTH_EXCLUDE_FIELDSusername外部认证登录时不回写的字段

暴力锁定行为实测(API 连错 7 次,BRUTEFORCE_LOCKDOWN=6):

for i in 1 2 3 4 5 6 7; do curl -s -u admin:badpass$i -X POST http://localhost/jsonrpc.php -H 'Content-Type: application/json' -d '{"jsonrpc":"2.0","method":"getVersion","id":1,"params":{}}' > /dev/null; done
php -r "require 'app/common.php'; \$db=new PDO('sqlite:data/db.sqlite'); foreach(\$db->query('select username,nb_failed_login,lock_expiration_date from users') as \$r) echo \$r['username'],' failed=',\$r['nb_failed_login'],' lock_exp=',\$r['lock_expiration_date'],PHP_EOL;"

实测回显:

admin failed=7 lock_exp=1792774656

锁定期间即使用正确密码也返回 401(实测回显):

{"jsonrpc":"2.0","error":{"code":401,"message":"Unauthorized"},"id":null}

⚠️ 重要坑点:内置 CLI user:reset-password 只改密码、不清 nb_failed_login/lock_expiration_date(源码 ResetPasswordCommand::resetPassword 仅调 userModel->update)——锁定期间重置密码后依然 401。恢复方式:等 lock_expiration_date 过期,或手工清零 update users set nb_failed_login=0, lock_expiration_date=0 where username='admin';(清零后实测恢复正常 200)。

5.7 安全响应头与杂项(ENABLE_HSTS、ENABLE_XFRAME 等)

常量默认值说明
ENABLE_HSTStrue发送 Strict-Transport-Security 头
ENABLE_XFRAMEtrue发送 X-Frame-Options: DENY(防点击劫持)
MARKDOWN_ESCAPE_HTMLtrueMarkdown 内 HTML 转义(防 XSS)
API_AUTHENTICATION_HEADER空API 备用认证头名(RFC2617 Basic 之外的形态)
ENABLE_URL_REWRITEfalse(tar 包默认)/ true(官方 Docker 形态预置)URL 重写
HTTP_VERIFY_SSL_CERTIFICATEtrue应用发起 HTTPS(webhook 等)时校验证书,false 允许自签
DASHBOARD_MAX_PROJECTS10仪表盘项目数上限
SHOW_GROUP_MEMBERSHIPS_IN_USERLISTtrue用户列表显示组成员关系
SHOW_GROUP_MEMBERSHIPS_IN_USERLIST_WITH_LIMIT7组显示数量上限(0=全量)
DOCUMENTATION_URL_PATTERNhttps://docs.kanboard.org/v1/user/%s界面帮助链接模板
EXTERNAL_LINK_ALLOW_PRIVATE_NETWORKSfalse外链元数据抓取是否允许私网地址
WEBHOOK_ALLOW_PRIVATE_NETWORKSfalseWebhook 是否允许私网地址

安全头实测(HTTPS 入口):

curl -skI https://localhost/ | grep -iE 'strict-transport|x-frame'

实测回显:

x-frame-options: DENY
strict-transport-security: max-age=31536000

解读:两项默认开启且实测生效;EXTERNAL_LINK_ALLOW_PRIVATE_NETWORKS/WEBHOOK_ALLOW_PRIVATE_NETWORKS 是 v1.2.56 新增的 SSRF 防护开关(默认禁止应用侧请求私网地址),内网集成(如 webhook 打内网服务)时才显式开启。

5.8 插件(PLUGIN_*)

常量默认值说明
PLUGINS_DIR<应用根>/plugins插件目录(放入即加载,删除即卸载)
PLUGIN_API_URLhttps://kanboard.org/plugins.json插件市场清单
PLUGIN_INSTALLERfalseWeb 界面在线安装插件开关,默认关(插件无审核,需人工甄别)

安装插件的稳妥流程:从 kanboard.org/plugins 或插件 GitHub 下载 zip → 解压到 plugins/ → 重载服务 → 界面「插件管理」确认版本兼容(插件须声明支持的 Kanboard 版本)。PLUGIN_INSTALLER=true 仅建议在受控环境开启。

5.9 HTTP 客户端与代理(HTTP_*)

常量默认值说明
HTTP_TIMEOUT10外发 HTTP 超时秒数
HTTP_MAX_REDIRECTS3最大重定向次数
HTTP_PROXY_HOSTNAME / HTTP_PROXY_PORT空 / 3128外发 HTTP 代理(隔离网络访问插件市场/外链元数据用)
HTTP_PROXY_USERNAME / HTTP_PROXY_PASSWORD空代理凭据
HTTP_PROXY_EXCLUDElocalhost例外主机(逗号分隔)
HTTP_VERIFY_SSL_CERTIFICATEtrue见 5.7

六、生产配置模板

两套按规模划分的模板,复制到 config.php 后按注释调整。

6.1 小团队模板(SQLite,≤20 人,2C4G/40GB 磁盘)

<?php

// 日志:文件驱动,关闭 DEBUG
defined('LOG_DRIVER') or define('LOG_DRIVER', 'file');
defined('DEBUG') or define('DEBUG', false);

// 数据库:默认 SQLite,无需任何 DB_* 配置
defined('DB_DRIVER') or define('DB_DRIVER', 'sqlite');

// 邮件:SMTP over TLS
defined('MAIL_FROM') or define('MAIL_FROM', 'kanboard@example.com');
defined('MAIL_TRANSPORT') or define('MAIL_TRANSPORT', 'smtp');
defined('MAIL_SMTP_HOSTNAME') or define('MAIL_SMTP_HOSTNAME', 'smtp.example.com');
defined('MAIL_SMTP_PORT') or define('MAIL_SMTP_PORT', 587);
defined('MAIL_SMTP_ENCRYPTION') or define('MAIL_SMTP_ENCRYPTION', 'tls');

// 会话:8 小时(工作日场景)
defined('SESSION_DURATION') or define('SESSION_DURATION', 28800);

// 暴力破解防护:默认阈值即可(3 次验证码 / 6 次锁定 / 15 分钟)
defined('BRUTEFORCE_CAPTCHA') or define('BRUTEFORCE_CAPTCHA', 3);
defined('BRUTEFORCE_LOCKDOWN') or define('BRUTEFORCE_LOCKDOWN', 6);
defined('BRUTEFORCE_LOCKDOWN_DURATION') or define('BRUTEFORCE_LOCKDOWN_DURATION', 15);

// 插件在线安装保持关闭
defined('PLUGIN_INSTALLER') or define('PLUGIN_INSTALLER', false);

💡 说明:模板内每项用 defined(...) or define(...) 形式书写,与官方 Docker 形态的环境变量注入兼容(环境变量已定义时以环境变量为准),同一份 config.php 可在 tar 包与 Docker 两种形态间复用。

6.2 中型团队模板(MySQL + LDAP + 反代 SSO,≤100 人,4C8G/独立 DB 主机)

<?php

defined('LOG_DRIVER') or define('LOG_DRIVER', 'file');
defined('DEBUG') or define('DEBUG', false);

// 数据库:PostgreSQL(v1.2.56 在 PHP 8.5 下 MySQL 驱动存在 deprecated 兼容问题,见 5.2)
defined('DB_DRIVER') or define('DB_DRIVER', 'postgres');
defined('DB_HOSTNAME') or define('DB_HOSTNAME', 'db.example.internal');
defined('DB_PORT') or define('DB_PORT', 5432);
defined('DB_NAME') or define('DB_NAME', 'kanboard');
defined('DB_USERNAME') or define('DB_USERNAME', 'kanboard');
defined('DB_PASSWORD') or define('DB_PASSWORD', 'q1w2e3r4');

// LDAP 对接(AD)
defined('LDAP_AUTH') or define('LDAP_AUTH', true);
defined('LDAP_SERVER') or define('LDAP_SERVER', 'ldap://dc.example.com');
defined('LDAP_BIND_TYPE') or define('LDAP_BIND_TYPE', 'user');
defined('LDAP_USERNAME') or define('LDAP_USERNAME', '%s@example.com');
defined('LDAP_USER_BASE_DN') or define('LDAP_USER_BASE_DN', 'CN=Users,DC=example,DC=com');
defined('LDAP_USER_FILTER') or define('LDAP_USER_FILTER', '(&(objectClass=user)(sAMAccountName=%s))');
defined('LDAP_USER_ATTRIBUTE_USERNAME') or define('LDAP_USER_ATTRIBUTE_USERNAME', 'sAMAccountName');
defined('LDAP_GROUP_ADMIN_DN') or define('LDAP_GROUP_ADMIN_DN', 'CN=Kanboard-Admins,CN=Users,DC=example,DC=com');

// 反代后真实 IP(只信任本网段代理)
defined('TRUSTED_PROXY_HEADERS') or define('TRUSTED_PROXY_HEADERS', 'HTTP_X_FORWARDED_FOR');
defined('TRUSTED_PROXY_NETWORKS') or define('TRUSTED_PROXY_NETWORKS', '10.0.0.0/8');

// 纯 SSO 场景可加:REVERSE_PROXY_AUTH / HIDE_LOGIN_FORM
defined('SESSION_HANDLER') or define('SESSION_HANDLER', 'db');
defined('SESSION_DURATION') or define('SESSION_DURATION', 28800);

⚠️ 注意:DB_PASSWORD/LDAP 等敏感值建议通过环境变量注入而非写入文件;数据库密码应使用专用最小权限账号(仅授 kanboard 库的 DML+DDL 迁移权限)。

七、常见问题(FAQ)

Q1:改了 config.php 不生效?

按优先级链逐层排查(见 3.1):确认文件位置是应用根 config.php 或 data/config.php;确认常量拼写正确(大小写敏感);确认已重载服务(php-fpm reload / 服务重启);确认没有更高优先级来源覆盖(DATABASE_URL 环境变量、已定义的常量不会被子层覆盖)。验证生效值用 3.2 的 php -r 命令直接看常量。

Q2:MySQL 形态 healthcheck 返回 503 提示 PDO::MYSQL_ATTR_INIT_COMMAND deprecated?

v1.2.56 官方 Docker 运行时为 PHP 8.5.12,其 MySQL 驱动代码使用了 PHP 8.5 已废弃的常量(实测回显见 5.2),连接在建立前即报 503。规避:SQLite(默认)或 PostgreSQL 形态;或关注上游对 PHP 8.5 的适配提交后升级。这属于版本兼容性坑,不是配置错误。

Q3:账号被锁定后重置密码为什么还登不上?

user:reset-password 不清理锁定标志(源码级确认 + 实测回显见 5.6)。等 BRUTEFORCE_LOCKDOWN_DURATION(15 分钟)过后自动解锁,或手工清零 users 表的 nb_failed_login 与 lock_expiration_date。

Q4:为什么我的界面没有「插件安装」入口?

PLUGIN_INSTALLER 默认 false(插件无审核机制,官方出于安全默认关闭)。自行放置插件到 plugins/ 目录后重载即可被加载;确需在线安装再显式开启。

Q5:API 调用 401 的排查顺序?

① 确认用 HTTP Basic 认证(v1.2.56 已废弃旧 X-RPC-Auth-* 头);② 确认账号未被暴力锁定(5.6);③ 确认服务端时间正常(2FA 场景 TOTP 时间窗敏感)。Basic 认证可用 curl 一行验证:curl -s -u admin:q1w2e3r4 -X POST http://localhost/jsonrpc.php -H 'Content-Type: application/json' -d '{"jsonrpc":"2.0","method":"getVersion","id":1,"params":{}}',正常回显 {"jsonrpc":"2.0","result":"v1.2.56","id":1}。

八、参考链接