Teampass 3.2.3.2 Docker Compose 部署指南

Teampass 3.2.3.2 Docker Compose 部署指南:应用与 MySQL 8.0 双服务编排、安装向导 6 步全程实测(含 CSRF 驱动与 84 表建表回执)、数据持久化与备份恢复、环境变量表、等价 docker run 与运维命令,附安装器缺表、维护模式、口令策略等 8 个实测 FAQ。

Teampass密码管理PHP 应用自托管2026/10/24

Teampass 3.2.3.2 Docker Compose 部署指南

目标:从零完成 Teampass 3.2.3.2 团队密码保管库的双服务编排部署(应用 + MySQL 8.0),走完安装向导全部 6 步并完成管理员账号初始化、普通用户创建与权限矩阵配置,最终得到一个可登录、可建条目、可按角色授权的生产可用实例。已在 Ubuntu 宿主机(内核 6.8.0-138-generic、Docker 29.8.1、Docker Compose v5.5.1)实测通过,全流程命令与回显均为真实执行记录。

一、环境信息

本次实测部署的环境基线如下(均为宿主机实查回显):

项目值来源
宿主机内核6.8.0-138-genericuname -r 实查
Docker29.8.1, build 4a63305docker --version 实查
Docker Composev5.5.1docker compose version 实查
Teampass 版本3.2.3.2(TP_VERSION 3.2.3 + TP_VERSION_MINOR 2)镜像常量实查
应用镜像teampass/teampass:3.2.3.2(737MB)docker images 实查
数据库镜像mysql:8.0(1.1GB,服务端版本 8.0.46)docker images 实查
应用内 PHP8.3.35(NTS)容器内 php -v 实查
应用端口宿主机 8144 → 应用 80compose 映射实查
自定义网络teampass-3232-net(bridge,子网 10.89.70.0/24)compose 定义实查
数据卷teampass-db(MySQL 数据)、teampass-html(应用全量目录)compose 定义实查

Teampass 3.2.3.2 是官方明确推荐用于全新安装的版本(GitHub Release Notes 原文「3.2.3.2 is the version to use for any new installation」,发布于 2026-10-20)。版本背景与选型对比见《Teampass 3.2.3.2 介绍与选型指南》。

二、镜像选型说明

2.1 应用镜像

Teampass 官方在 Docker Hub 发布 teampass/teampass 镜像,本次实测选择固定版本 tag teampass/teampass:3.2.3.2,理由如下:

  • 版本可追溯:该 tag 对应 GitHub 仓库 nilsteampassnet/TeamPass 的 3.2.3.2 发布版,镜像内 PHP 常量 TP_VERSION='3.2.3'、TP_VERSION_MINOR='2' 实查一致;
  • 不要用 latest 部署生产:实测比对发现 latest tag 与 3.2.3.2 tag 的 manifest digest 不同——latest 指向 master 分支的滚动构建,包含未发布改动,部署后出现的问题无法对应到任何官方发布版本,排障无从溯源;
  • 镜像内自带 PHP 8.3.35 运行时、nginx(php-fpm 由 nginx 用户运行)与 docker-entrypoint.sh 引导脚本,无需自建 Dockerfile。

镜像 tag 清单可通过 Docker Hub API 实查(实测共 401 个 tag,包含 3.2.3.2 与 latest 等),拉取前建议先核对目标 tag 存在。

2.2 数据库镜像

选择 mysql:8.0 官方镜像(服务端 8.0.46 实查)。Teampass 3.2 线要求数据表全部为 InnoDB 且字符集 utf8mb4,compose 中通过启动参数显式指定 --character-set-server=utf8mb4 与 --collation-server=utf8mb4_unicode_ci 保证新库默认值正确。MariaDB 10.7+ 亦可作为数据库(官方要求),但 MySQL 8.0 与安装向导的兼容验证最直接。

2.3 镜像拉取

国内网络环境建议先配置可用的镜像加速地址再拉取;拉取后核对本地镜像:

docker pull mysql:8.0
docker pull teampass/teampass:3.2.3.2
docker images | grep -E 'teampass|mysql:8.0'

实测回显:

teampass/teampass:3.2.3.2   737MB
mysql:8.0                   1.1GB

三、前置条件

  1. 服务器已安装 Docker 29.x 与 Compose 插件(docker compose version 可正常返回);
  2. 端口规划:应用对外端口需未被占用(本次用 8144),确认方式 ss -tlnp | grep 8144 无输出;
  3. 子网规划:自定义 bridge 网络显式指定子网,避免与既有网段冲突(本次用 10.89.70.0/24,创建前用 docker network ls 与 docker network inspect 确认未占用);
  4. 数据落盘目录:编排文件与过程资料统一放在 /opt/data/quzuo/tmp/teampass/stack/(生产环境按自身目录规范放置即可);
  5. 数据库口令:预先确定 MySQL root 与业务账号口令。Teampass 安装向导第 4 步对管理员口令有强度要求(实测规则:≥10 位、必须同时包含大小写字母与数字/特殊字符,q1w2e3r4 这类弱口令会被拒绝,详见 FAQ);
  6. 浏览器或 curl:安装向导既可用浏览器逐步完成,也可全程 curl 驱动(本文以 curl 驱动实录)。

四、部署步骤

4.1 编排文件

创建 /opt/data/quzuo/tmp/teampass/stack/docker-compose.yml:

name: teampass-3.2.3.2-stack

services:
  db:
    image: mysql:8.0
    container_name: teampass-3.2.3.2-db
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: q1w2e3r4
      MYSQL_DATABASE: teampass
      MYSQL_USER: teampass
      MYSQL_PASSWORD: q1w2e3r4
    command:
      - --character-set-server=utf8mb4
      - --collation-server=utf8mb4_unicode_ci
    volumes:
      - teampass-db:/var/lib/mysql
    networks:
      - tpnet

  teampass:
    image: teampass/teampass:3.2.3.2
    container_name: teampass-3.2.3.2-web
    restart: unless-stopped
    depends_on:
      - db
    ports:
      - "8144:80"
    volumes:
      - teampass-html:/var/www/html
    networks:
      - tpnet

volumes:
  teampass-db:
  teampass-html:

networks:
  tpnet:
    driver: bridge
    name: teampass-3232-net
    ipam:
      config:
        - subnet: 10.89.70.0/24

要点说明:

  • 应用侧数据卷 teampass-html 挂载整个 /var/www/html。不要只挂载空目录到 /var/www/html——bind mount 一个空宿主目录会把镜像内全部应用文件盖住,导致启动即白屏;命名卷首次挂载时会先拷入镜像内容,行为正确;
  • depends_on: - db 保证启动顺序,镜像 entrypoint 自带 30 次 × 2 秒的数据库就绪等待循环,双保险;
  • compose 项目名 teampass-3.2.3.2-stack 中的点号会被规范化剥掉,数据卷实际前缀为 teampass-3232-stack_(实测卷名 teampass-3232-stack_teampass-html),属正常现象。

4.2 启动与就绪确认

cd /opt/data/quzuo/tmp/teampass/stack
docker compose up -d
docker compose ps

实测回显(应用健康检查通过后):

teampass-3.2.3.2-db   Up 39 minutes   3306/tcp, 33060/tcp
teampass-3.2.3.2-web  Up 34 minutes (healthy)   9000/tcp, 0.0.0.0:8144->80/tcp

HTTP 层验证:

curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8144/index.php

实测返回 200。

4.3 安装向导总览

首次访问 http://<服务器IP>:8144/ 会 302 到 install/install.php 安装向导,共 6 步:路径确认 → 环境检查 → 数据库连接 → 管理员账号 → 建表 → 收尾动作。向导接口全部要求 CSRF 令牌(响应头/页面内 csrf-token meta,请求头 X-CSRF-Token),实测令牌为 64 位十六进制串。以下全部步骤在宿主机用 curl 驱动,cookie 与令牌贯穿全程。

4.4 第 1 步:路径确认

BASE=http://127.0.0.1:8144
CK=/opt/data/quzuo/tmp/teampass/ck.txt
CSRF=$(curl -s -c $CK $BASE/install/install.php | grep -oP 'csrf-token" content="\K[a-f0-9]+')
echo ${#CSRF}    # 实测 64

curl -s -b $CK -H "X-CSRF-Token: $CSRF" $BASE/install/install-steps/run.step1.php \
  -d "absolutePath=/var/www/html/public" \
  -d "urlPath=http://192.168.146.128:8144/"

实测回显:

{"success":true,"message":"<i class=\"fa-solid fa-check\"><\/i> Done"}

urlPath 要写成用户实际访问的应用 URL(含协议、IP/域名与端口),它会被写入站点设置 cpassman_url,后续邮件通知、附件链接等都基于它。

4.5 第 2 步:环境检查

逐项调用 run.step2.php,检查目录可写、PHP 扩展与运行参数:

step2() { curl -s -b $CK -H "X-CSRF-Token: $CSRF" $BASE/install/install-steps/run.step2.php "$@"; echo; }
step2 -d type=directory -d path=/var/www/html/app/config/
step2 -d type=directory -d path=/var/www/html/app/includes/libraries/csrfp/libs/
step2 -d type=directory -d path=/var/www/html/storage/files/
step2 -d type=extension -d name=mbstring
step2 -d type=extension -d name=openssl
step2 -d type=php_version -d version=
step2 -d type=execution_time -d limit=30

实测回显(核心项全部 {"success":true};可选项 posix/opcache/php_fpm 通过,pcntl/apcu/redis 为 false,均为可选能力不影响安装)。官方镜像的目录权限与扩展已预置到位,全部目录检查与必需扩展(mbstring/openssl/bcmath/xml/curl)一次通过。

4.6 第 3 步:数据库连接

curl -s -b $CK -H "X-CSRF-Token: $CSRF" $BASE/install/install-steps/run.step3.php \
  -d "dbHost=db" -d "dbName=teampass" -d "dbLogin=teampass" -d "dbPw=q1w2e3r4" \
  -d "dbPort=3306" -d "tablePrefix=teampass_" \
  -d "teampassAbsolutePath=/var/www/html/public" \
  -d "teampassUrl=http://192.168.146.128:8144/"

实测回显:

{"success":true,"message":"<i class=\"fa-solid fa-check\"><\/i> Done"}

dbHost 填 compose 服务名 db(同网络内 DNS 解析),数据库与账号由 compose 环境变量 MYSQL_DATABASE/MYSQL_USER/MYSQL_PASSWORD 预建。

4.7 第 4 步:管理员账号

curl -s -b $CK -H "X-CSRF-Token: $CSRF" $BASE/install/install-steps/run.step4.php \
  -d "adminPassword=q1w2E3R4T5" -d "adminEmail=admin@example.com" \
  -d "adminName=admin" -d "adminLastname=User" \
  -d "dbHost=db" -d "dbName=teampass" -d "dbLogin=teampass" -d "dbPw=q1w2e3r4" \
  -d "dbPort=3306" -d "tablePrefix=teampass_"

实测回显:

{"success":true,"message":"<i class=\"fa-solid fa-check\"><\/i> Done"}

注意:首次实测用 q1w2e3r4 被向导拒绝(口令策略要求 ≥10 位且含大小写与数字/特殊字符),改用 10 位混合口令后通过。

4.8 第 5 步:建表

run.step5.php 按动作逐个建表/执行迁移,实测全部 84 个动作一次通过(OK=84 FAIL=0),包括 utf8 迁移、InnoDB 引擎设定,以及 items/users/roles/rights/sharekeys/log_items/log_system/auth_failures/background_tasks/webauthn 等全部业务表:

for a in utf8 migrateToUtf8mb4 checkAndSetInnoDBEngine api automatic_del cache cache_tree \
         categories categories_folders categories_items defuse_passwords emails export files \
         items items_change items_edition items_otp kb kb_categories kb_items kb_comments \
         kb_edition ldap_groups_roles languages log_items log_system misc nested_tree \
         notification otv background_tasks background_subtasks background_tasks_logs \
         restriction_to_roles rights roles_title roles_values sharekeys_fields sharekeys_files \
         sharekeys_items sharekeys_logs sharekeys_suggestions suggestion tags templates tokens \
         users auth_failures items_importations user_private_keys users_groups \
         users_groups_forbidden users_roles users_favorites users_latest_items \
         users_options_favorites encryption_migration_stats websocket_events \
         websocket_connections websocket_tokens network_acl items_corruption api_tokens \
         api_sessions api_rate_limit import_tracking item_health user_nudges rotation_flags \
         access_reviews access_review_items data_classification user_notifications \
         emails_templates lapr_endpoints lapr_accounts lapr_policies lapr_audit_log \
         lapr_rate_limit items_revisions api_idempotency webauthn_credentials sharekeys_webauthn; do
  curl -s -b $CK -H "X-CSRF-Token: $CSRF" $BASE/install/install-steps/run.step5.php \
    -d "action=$a" -d "dbHost=db" -d "dbName=teampass" -d "dbLogin=teampass" \
    -d "dbPw=q1w2e3r4" -d "dbPort=3306" -d "tablePrefix=teampass_" | grep -o '"success":true' \
    || echo "FAILED: $a"
done

实测 84 个动作无任何 FAILED 输出。建表后登录数据库核验:

docker exec teampass-3.2.3.2-db mysql -uteampass -pq1w2e3r4 teampass \
  -e "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='teampass';"

实测返回 85(84 张业务表 + 系统自动生成的 1 张)。

4.9 第 6 步:收尾动作

依次执行 6 个收尾动作,全部返回 {"success":true,"message":"<i class=\"fa-solid fa-check\"><\/i> Done"}:

动作作用(实测效果)
secureFile在 secrets/ 下生成随机文件名(SECUREFILE)的 Defuse 主密钥文件
chmod收紧 storage/ 与 secrets/ 目录权限
settingsFile生成 settings.php(数据库连接信息,DB 口令为密文)
csrf生成 CSRF 防护配置 csrfp.config.php
cronJob写入定时任务配置
cleanInstall标记安装完成
for a in secureFile chmod settingsFile csrf cronJob cleanInstall; do
  curl -s -b $CK -H "X-CSRF-Token: $CSRF" $BASE/install/install-steps/run.step6.php \
    -d "action=$a" -d "dbHost=db" -d "dbName=teampass" -d "dbLogin=teampass" \
    -d "dbPw=q1w2e3r4" -d "dbPort=3306" -d "tablePrefix=teampass_"; echo
done

4.10 安装后验证

安装完成后访问 http://<服务器IP>:8144/ 进入登录页,用第 4.7 节创建的管理员账号登录。登录成功即代表安装闭环。首次进入系统后有两个必做动作(均为实测结论):

  1. 关闭维护模式:全新安装默认 maintenance_mode=1,非管理员用户登录会被拒绝(错误提示 maintenance_mode_enabled)。管理员进入后台设置把维护模式关闭后普通用户方可登录;
  2. 确认站点 URL:后台设置中的站点 URL 应与实际访问地址一致(第 4.4 步写入的 cpassman_url)。

完成一个最小权限模型验证(实测全过程):

  • 创建角色「运维组」,把角色对目标文件夹授写权限(授权接口回执 {"error":false,"message":""});
  • 创建普通用户挂到该角色(创建成功后接口回执返回自动生成口令);
  • 该用户登录后可在授权文件夹内新建条目(回执 {"error":false,"item_id":1,"encryption_task_created":true}),尝试在根目录建文件夹被拒(回执 {"error":true,"message":"Folder is not allowed for this user"}),尝试在授权文件夹下建子文件夹亦被拒(回执 {"error":true,"message":"You are not allowed to do that!"})——证明写权限只覆盖条目增删改,不含文件夹结构变更。

五、数据持久化说明

5.1 数据落点全景

Teampass 的持久化数据分布在三个层面,实测清单如下:

数据落点持久化载体
全部密码条目密文、用户、角色、审计日志MySQL 库 teampass(85 张表)命名卷 teampass-db → /var/lib/mysql
应用代码 + 配置 + 上传附件 + 附件密钥/var/www/html 整目录命名卷 teampass-html
Defuse 主密钥文件/var/www/html/secrets/<随机名>(0600,目录 0700)随 teampass-html 卷持久化(镜像另对其声明独立卷)
settings.php 与 csrfp.config.php/var/www/html/storage/config/(应用路径经符号链接指向)随 teampass-html 卷持久化

5.2 安装产物的符号链接持久化机制

官方镜像 entrypoint 对安装向导产物做了显式的持久化处理(脚本内注释与实测文件属性一致):app/config/settings.php 与 app/includes/libraries/csrfp/libs/csrfp.config.php 在应用路径上是符号链接,实体文件位于 storage/config/。这样安装向导无论写到哪个路径,最终都落在数据卷上,容器重建(docker compose down && up)后不会触发重新安装。实测验证:storage/config/ 下确有 settings.php(1048 字节)与 csrfp.config.php(1192 字节),属主 nginx:nginx、权限 0640。

5.3 备份方法

# 数据库备份
docker exec teampass-3.2.3.2-db sh -c \
  'exec mysqldump -uteampass -p"q1w2e3r4" teampass' > /opt/data/quzuo/tmp/teampass/tp_db_$(date +%F).sql

# 应用目录(含配置与 secrets)备份
docker run --rm -v teampass-3232-stack_teampass-html:/src:ro -v /opt/data/quzuo/tmp/teampass:/dst \
  alpine tar czf /dst/tp_html_$(date +%F).tgz -C /src .

恢复 = 先恢复数据库再恢复应用目录卷;两者必须成对恢复,因为数据库中的 Defuse 密文依赖 secrets/ 主密钥文件解密,配置文件中的数据库口令密文依赖同一密钥,错配将导致无法解密。

5.4 升级时的卷保留

docker compose pull && docker compose up -d 会重建应用服务但保留两个命名卷;镜像 entrypoint 内置数据库版本比对逻辑(读取 teampass_misc 表中的 teampass_version 与 upgrade_timestamp,低于镜像携带的 schema 底线则自动执行升级迁移),升级路径无需手工介入。

六、环境变量表

官方镜像 docker-entrypoint.sh 实查支持的运行时环境变量如下:

变量默认值说明
DB_HOSTdb数据库主机(compose 服务名)
DB_PORT3306数据库端口
DB_NAMEteampass数据库名
DB_USERteampass业务数据库账号
DB_PASSWORD空业务数据库口令(entrypoint 用于就绪等待与升级辅助连接)
DB_PREFIXteampass_数据表前缀
TEAMPASS_URLhttp://localhost站点对外 URL(entrypoint 启动横幅显示用)
PHP_MEMORY_LIMIT512MPHP 内存上限(entrypoint 写入 conf.d 覆盖文件)
PHP_UPLOAD_MAX_FILESIZE100M上传文件上限
PHP_POST_MAX_SIZE同上传上限POST 请求体上限
PHP_MAX_EXECUTION_TIME120脚本最大执行时间(秒)

注意两点(脚本实查):一是这些变量不直接预写 settings.php——安装向导才是数据库连接信息的写入方,环境变量主要用于就绪检测、PHP 运行参数与升级辅助;二是 PHP_* 四项通过生成 /usr/local/etc/php/conf.d/teampass-env.ini 生效,改完需重建容器。

MySQL 侧环境变量(MYSQL_ROOT_PASSWORD/MYSQL_DATABASE/MYSQL_USER/MYSQL_PASSWORD)为 mysql 官方镜像标准变量,仅在数据卷首次初始化时生效;卷已存在时改这些变量不会改动已建库与口令。

七、配置参数说明

部署阶段涉及的参数分三层,逐层说明:

  1. 编排层参数(4.1 节 compose 文件):端口映射、数据卷、子网、字符集启动参数。子网必须显式指定(实测宿主机已有多个 10.89.x.0/24 段的网络,随机分配易冲突);
  2. 安装向导参数(4.4~4.9 节):站点绝对路径与 URL、数据库五项连接参数、表前缀、管理员四项信息。这些参数在安装完成后分别落在 settings.php(数据库连接、cpassman_url 等)与数据库 teampass_misc 表(站点设置全集 294 项);
  3. 运行层参数(第六节环境变量表 + PHP conf.d):内存、上传、执行时间。

安装后如需调整站点行为(密码复杂度、会话时长、双因素策略、附件加密开关等),在管理员后台设置界面修改即可,全部变更实时写库生效(实测:修改 clipboard_life_duration 30→60 后,数据库 teampass_misc 表 valeur 字段立即变为 60)。参数全集逐项详解见《Teampass 3.2.3.2 配置参数详解》同专栏续篇;安全相关参数的加固用法见《Teampass 3.2.3.2 安全加固指南》(同专栏)。

八、配置文件挂载

8.1 需要关注的配置文件清单(容器内实查)

文件权限/属主作用
/var/www/html/storage/config/settings.php0640 nginx:nginx数据库连接(DB_HOST/DB_USER/DB_PASSWD/DB_NAME/DB_PREFIX/DB_PORT/DB_ENCODING 等),数据库口令为 Defuse 密文(def50200... 前缀),非明文
/var/www/html/storage/config/csrfp.config.php0640 nginx:nginxCSRF 防护配置
/var/www/html/secrets/<随机名>0600 nginx:nginx,目录 0700Defuse 加密主密钥,文件名即 settings.php 中 SECUREFILE 常量值
/usr/local/etc/php/conf.d/teampass-env.ini镜像生成entrypoint 按 PHP_* 环境变量生成的 PHP 覆盖配置

8.2 挂载建议

  • 本文 compose 直接用命名卷 teampass-html 挂整个 /var/www/html,上述配置文件全部随卷持久化,无需单独挂载条目;
  • 若希望配置与应用代码分离管理,可追加挂载:- ./config:/var/www/html/storage/config(覆盖命名卷内同路径),但注意宿主目录属主需与容器内 nginx 用户 uid 匹配,否则安装向导写入 settings.php 时会失败(镜像 issue #5238 即此类属主问题);
  • secrets/ 目录安全等级最高(0700/0600),生产环境建议独立卷并纳入备份(5.3 节)。

九、等价 docker run

不用 Compose 时,以下三条命令与 4.1 节编排等价(按序执行):

# 1. 自定义网络(显式子网)
docker network create --driver bridge --subnet 10.89.70.0/24 teampass-3232-net

# 2. 数据库
docker run -d --name teampass-3.2.3.2-db --restart unless-stopped \
  --network teampass-3232-net \
  -e MYSQL_ROOT_PASSWORD=q1w2e3r4 \
  -e MYSQL_DATABASE=teampass \
  -e MYSQL_USER=teampass \
  -e MYSQL_PASSWORD=q1w2e3r4 \
  -v teampass-db:/var/lib/mysql \
  mysql:8.0 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci

# 3. 应用
docker run -d --name teampass-3.2.3.2-web --restart unless-stopped \
  --network teampass-3232-net \
  -p 8144:80 \
  -v teampass-html:/var/www/html \
  teampass/teampass:3.2.3.2

后续安装向导步骤与 4.3~4.10 节完全一致。日常管理推荐 Compose(docker compose ps/logs/stop/up -d 一组命令覆盖全部服务)。

十、常用运维命令

cd /opt/data/quzuo/tmp/teampass/stack

# 状态与健康检查
docker compose ps
docker inspect --format '{{.State.Health.Status}}' teampass-3.2.3.2-web

# 日志跟踪(应用引导横幅含版本号与数据库等待过程)
docker compose logs -f teampass
docker compose logs --tail 100 db

# 重启单个服务 / 全部服务
docker compose restart teampass
docker compose down          # 停止并移除容器,数据卷保留
docker compose up -d         # 重新拉起,数据完整保留

# 版本核对
docker exec teampass-3.2.3.2-web grep -E "TP_VERSION" /var/www/html/app/config/include.php

# 直连数据库排查
docker exec -it teampass-3.2.3.2-db mysql -uteampass -pq1w2e3r4 teampass

# 应用目录内执行 PHP(如命令行维护脚本)
docker exec teampass-3.2.3.2-web php /var/www/html/app/scripts/read-db-version.php

实测补充:服务器重启后 restart: unless-stopped 的服务会自动拉起;若以 Exited 状态存在,docker start teampass-3.2.3.2-db teampass-3.2.3.2-web 即可,数据无损。

十一、常见问题

Q1:拉取的 latest 镜像装出来的版本号和官方 3.2.3.2 对不上? 实测 latest 与 3.2.3.2 两个 tag 的 manifest digest 不同——latest 是 master 分支滚动构建。生产部署一律用固定版本 tag,核对方法:启动后 docker exec teampass-3.2.3.2-web grep -E "TP_VERSION" /var/www/html/app/config/include.php,应看到 3.2.3 与 2 两个常量。

Q2:安装向导第 5 步某动作返回 500,提示缺表 teampass_user_webauthn_credentials? 3.2.3.2 安装器存在遗漏:建表清单不含该表,而后续创建用户等功能的代码会查询它(实测 add_new_user 接口 500,错误栈指向该表不存在)。修复方法为手工补建,实测建表语句如下(列集从代码中该表的 INSERT/UPDATE/SELECT 语句反推):

CREATE TABLE IF NOT EXISTS teampass_user_webauthn_credentials (
  id INT UNSIGNED NOT NULL AUTO_INCREMENT,
  user_id INT NOT NULL,
  credential_id VARBINARY(1024) NOT NULL,
  rp_id VARCHAR(255) NOT NULL,
  public_key_cose MEDIUMBLOB NOT NULL,
  sign_count BIGINT NOT NULL DEFAULT 0,
  aaguid VARCHAR(64) DEFAULT NULL,
  transports VARCHAR(255) DEFAULT NULL,
  label VARCHAR(255) DEFAULT NULL,
  key_wrap_mode VARCHAR(32) NOT NULL DEFAULT 'wrapped',
  wrapped_private_key MEDIUMBLOB DEFAULT NULL,
  wrap_salt VARBINARY(64) DEFAULT NULL,
  backup_eligible TINYINT(1) NOT NULL DEFAULT 0,
  backup_state TINYINT(1) NOT NULL DEFAULT 0,
  created_at VARCHAR(50) DEFAULT NULL,
  last_used_at VARCHAR(50) DEFAULT NULL,
  PRIMARY KEY (id),
  KEY user_id (user_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

补建后重新执行失败的动作即可继续。

Q3:管理员口令 q1w2e3r4 在安装第 4 步被拒? 实测口令策略:长度 ≥10、必须同时包含大写字母、小写字母与数字/特殊字符。换 q1w2E3R4T5 这类 10 位混合口令可通过。该策略同样作用于后台自建用户的口令修改。

Q4:安装完成、管理员能登录,普通用户登录却报 maintenance_mode_enabled? 全新安装默认开启维护模式(teampass_misc 表 maintenance_mode=1),仅管理员可登录。管理员在后台设置中关闭维护模式后普通用户即可登录(实测关闭接口回执 {"error":false,"misc":"1 ; 0"},即 1 改 0)。

Q5:删除过的用户名无法重新创建,提示 "User already exists"? Teampass 的用户删除是软删除(login 改名 <原用户名>_deleted_<时间戳>、置 disabled),且创建用户时的重名校验会同时匹配软删除记录,因此同名用户不能直接重建,官方设计是走「恢复用户」。若确需重建(如测试环境),需清理数据库残留:删除 teampass_users 中该用户行,并同步清理 teampass_user_private_keys、teampass_users_roles、teampass_api 等表中 user_id 指向该用户的行(实测仅清 users 表仍会因残留密钥行报错)。

Q6:文件夹/条目的密码复杂度设置哪些值合法? 复杂度档位是固定枚举(对应枚举值 0/20/38/48/60 五档),传其他值(实测传 64)后端报 Undefined array key 64。后台文件夹编辑界面里只有这五档可选;数据库 teampass_misc 表 type=complex 的行记录了档位定义。

Q7:普通用户对文件夹有写权限,为什么还是不能建子文件夹? 实测权限模型:角色-文件夹的写授权(W)覆盖条目的增删改查,不含文件夹结构变更(建子文件夹被拒,回执 "You are not allowed to do that!"),根目录建文件夹另需 can_create_root_folder 能力(实测无此能力的用户建根目录文件夹回执 "Folder is not allowed for this user")。

Q8:把宿主机空目录 bind mount 到 /var/www/html 后应用白屏/404? bind mount 空目录会盖住镜像内的全部应用文件。应用目录必须用命名卷(首次挂载自动拷入镜像内容,见 4.1 节要点),或在宿主目录先备好完整应用文件。

十二、参考链接