Plainpad 1.2.0 配置参数详解

Plainpad 1.2.0 三层配置面实测详解:.env 15 键与 compose 环境变量映射、settings 表 9 键、用户偏好 6 键逐项说明,APP_KEY 优先级与加密开关批量重加密闭环验证、生产配置模板与六条常见问题(2026-11-02)。

PlainpadPlainpadPHPLaravel自托管MySQL2026/11/02

Plainpad 1.2.0 配置参数详解

目标:把 Plainpad 1.2.0 的全部可调参数面——.env 键、进程环境变量、应用级 Settings 与每用户偏好——逐项讲清含义、默认值与生效验证方法,关键参数全部在跑着的部署上实测闭环。部署过程见 《Plainpad 1.2.0 Docker Compose 部署实战》 篇(本栏 B2),本文沿用同一套运行环境取证。

一、环境信息

本文全部参数与回显取自 2026-11-02 实测的一套运行中部署(B2 篇产物):

  • 操作系统:Ubuntu 26.04.1 LTS(Resolute Raccoon),x86_64
  • 部署形态:Docker Compose 项目 plainpad-1.2.0-stack,应用服务 plainpad(官方镜像 alextselegidis/plainpad:latest,应用版本 1.2.0)+ 数据库服务 mysql(mysql:8.0)
  • 对外访问:http://localhost:8139;API 基址 http://localhost:8139/api.php/v1
  • 数据库凭据:root/secret,库名 plainpad
  • 管理员账号:admin@example.org / 12345678(官方播种,id 7a17c8fd-b84f-4f2c-8ba3-2a484c1a0e1e)

运行栈与版本用 Laravel 自带的 about 命令一次性取证:

cd /opt/data/quzuo/tmp/plainpad/stack
docker compose exec plainpad php artisan about

实测回显(2026-11-02):

PHP Deprecated:  Constant PDO::MYSQL_ATTR_SSL_CA is deprecated since 8.5, use Pdo\Mysql::ATTR_SSL_CA instead in /var/www/html/config/database.php on line 62

  Environment ................................................................  
  Application Name .................................................. Plainpad  
  Laravel Version .................................................... 12.69.0  
  PHP Version ......................................................... 8.5.12  
  Composer Version ......................................................... -  
  Environment ..................................................... production  
  Debug Mode ............................................................. OFF  
  URL ......................................................... localhost:8139  
  Maintenance Mode ....................................................... OFF  
  Timezone ............................................................... UTC  
  Locale ............................................................... en-US  

  Cache ......................................................................  
  Config .......................................................... NOT CACHED  
  Events .......................................................... NOT CACHED  
  Routes .......................................................... NOT CACHED  
  Views ........................................................... NOT CACHED  

  Drivers ....................................................................  
  Broadcasting .......................................................... null  
  Cache ................................................................. file  
  Database ............................................................. mysql  
  Logs ................................................................. daily  
  Mail .......................................................................  
  Queue ................................................................. sync  
  Session ............................................................... file  

  Storage ....................................................................  
  public/storage .................................................. NOT LINKED  

回显要点:应用跑在 production、Debug OFF;数据库驱动 mysql;会话与缓存都是 file 驱动(存在应用文件系统内,重建即失效);首行的 PHP Deprecated 是应用 config/database.php 使用了 PHP 8.5 已废弃常量的无害提示(见 B2 篇排障记录)。

💡 技术拓展:about 显示的各项驱动在 Laravel 中均可换实现,Plainpad 默认值的取舍——

驱动面本文实测值常见可选项Plainpad 用默认值的后果
Sessionfilecookie / database / redis重建应用即在线登录失效,无需额外中间件
Cachefileredis / database / array无缓存穿透风险,但换机需带 storage/ 目录
Queuesyncdatabase / redis任务同步执行,不装 worker 也不丢消息
Logsdailysingle / syslog按天滚动,位于 storage/logs/

这些键虽在 .env 体系内可写,但官方 .env.example 并未暴露它们(见第四章总览),常规部署保持默认即可。

二、前置条件

  1. 已按 B2 篇完成部署且服务健康:
cd /opt/data/quzuo/tmp/plainpad/stack
docker compose ps
NAME                 IMAGE                            COMMAND                  SERVICE    CREATED          STATUS          PORTS
plainpad-1.2.0-app   alextselegidis/plainpad:latest   "docker-entrypoint.sh"   plainpad   14 minutes ago   Up 14 minutes   0.0.0.0:8139->80/tcp, [::]:8139->80/tcp
plainpad-1.2.0-db    mysql:8.0                        "docker-entrypoint.s…"   mysql      25 minutes ago   Up 25 minutes   3306/tcp, 33060/tcp
  1. 具备进入应用服务执行命令的通道(本文用 docker compose exec plainpad <命令>,等价于在应用安装目录 /var/www/html 下操作)。

  2. 走 API 修改应用级/用户级参数时,需要一个管理员 Bearer Token。获取方法(实测回显):

curl -s -X POST http://localhost:8139/api.php/v1/sessions \
  -H 'Content-Type: application/json' \
  -d '{"email":"admin@example.org","password":"12345678"}'
# {"user_id":"7a17c8fd-b84f-4f2c-8ba3-2a484c1a0e1e","expires_at":"2026-11-02 12:20:47","token":"FE5Is0r75P5jZoalOwHKpWi0NlAsAJwNGRWsRqqFNcwtwD9kWCLQk5RDEPxS"}

export TOKEN=FE5Is0r75P5jZoalOwHKpWi0NlAsAJwNGRWsRqqFNcwtwD9kWCLQk5RDEPxS

本文 API 命令中的 $TOKEN 即取上述真实返回值;令牌过期后重新登录换取即可。

三、参数查看与修改方式

Plainpad 的可调参数分布在三个配置面上,各自的查看与修改入口不同——这是理解本文的关键:

配置面存储位置查看方式修改方式生效时机
环境变量 / .env应用根目录 /var/www/html/.envdocker compose exec plainpad cat .envcompose 服务 environment: + 重建服务重启
应用级设置数据库 settings 表(键值行)应用内 Settings 页 / API / 查库应用内 Settings 页 / API PUT /v1/settings即时
用户偏好数据库 users 表列应用内 Profile 页 / API / 查库应用内 Profile 页 / API PUT /v1/users/{ID}即时

3.1 环境变量与 .env

.env 共 15 个键(官方 .env.example 模板 + 注释,实测全文节选):

docker compose exec plainpad cat .env
APP_NAME=Plainpad
APP_ENV=production
APP_KEY={KEY}
APP_DEBUG=false
APP_URL=http://localhost:8139
APP_REPOSITORY=https://cdn.alextselegidis.com/plainpad/updates/stable
DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=plainpad
DB_USERNAME=root
DB_PASSWORD=secret

(原文件每个键上方带一段英文注释,此处按键值摘录。)注意 APP_KEY={KEY} 仍是模板占位符——这是官方镜像的正常形态:应用实际使用进程环境变量里的密钥,优先级验证见 5.1。

修改方式的正确姿势:在 compose 文件 plainpad 服务的 environment: 列表增删改,然后:

docker compose up -d plainpad

入口脚本会在每次启动时把 BASE_URL/DEBUG_MODE/DB_* 环境变量 sed 回写进 .env(脚本原文实测摘录见 5.2/5.3),直接手工编辑 .env 的这几个键会在下次重启时被环境变量覆盖(见第七章 7.1)。

3.2 应用级设置(settings 表)

数据库里以「一行一键」存储,实测全表:

docker compose exec mysql mysql -uroot -psecret -e 'select name,value from plainpad.settings;'
name                value
mail_from_address   notes@quzuo.net
mail_port           1025
mail_password       
mail_from_name      Plainpad
default_locale      zh-CN
mail_driver         smtp
mail_host           10.89.58.1
mail_encryption     
mail_username       

(表中值是本实验改过的状态,播种默认值见 5.5。)修改入口有两个:应用内 Settings 页面(Mail / Language 两栏),或管理员走 API:

curl -s http://localhost:8139/api.php/v1/settings -H "Authorization: Bearer $TOKEN"
# {"mail_from_address":"notes@quzuo.net","mail_port":"1025","mail_password":"","mail_from_name":"Plainpad","default_locale":"zh-CN","mail_driver":"smtp","mail_host":"10.89.58.1","mail_encryption":"","mail_username":""}

改法与逐项含义见 5.5。

3.3 用户偏好(users 表列)

偏好不是键值对而是表列,合法取值以数据库约束为准,实测列定义:

docker compose exec mysql mysql -uroot -psecret -e 'describe plainpad.users;'
Field       Type                          Null  Key  Default
id          varchar(255)                  NO    PRI  NULL
created_at  timestamp                     YES        NULL
updated_at  timestamp                     YES        NULL
name        varchar(255)                  NO         NULL
email       varchar(255)                  NO    MUL  NULL
password    varchar(255)                  NO         NULL
locale      varchar(255)                  NO         en-US
view        enum('comfortable','compact') NO         compact
line        enum('full','narrow')         NO         full
sort        enum('modified','created','alphabetical')  NO  modified
theme       enum('light','dark')          NO         light
encrypt     tinyint(1)                    NO         0
admin       tinyint(1)                    NO         0

修改入口:应用内 Profile 页(每个用户改自己的),或管理员走 API PUT /v1/users/{ID}(实测见 5.6)。

3.4 artisan 命令面

应用自定义的 artisan 命令只有两个(框架命令除外),实测:

docker compose exec plainpad php artisan list | grep -E '^\s+(refresh|cleanup)'
  cleanup                   Removed unnecessary system files.
  refresh                   Refresh the Plainpad installation after an update.

refresh 用于升级后刷新安装(迁移+缓存),cleanup 清理系统冗余文件,均无参数、静默执行。它们不修改配置值,但 refresh 是「改了 compose 环境变量重建后」推荐的收尾动作(B2 篇 10.4)。

四、参数总览

4.1 .env 15 键总览

键官方默认值(.env.example)作用compose 环境变量可覆盖
APP_NAMEPlainpad应用名(通知/框架文案用)否(入口脚本不处理)
APP_ENVproduction运行环境否
APP_KEY{KEY}(占位)加密密钥派生种子是(APP_KEY,环境变量优先)
APP_DEBUGfalse调试模式,出错显示堆栈是(DEBUG_MODE=TRUE/FALSE)
APP_URL{URL}(占位)应用访问前缀(生成链接/console 用)是(BASE_URL)
APP_REPOSITORYhttps://cdn.alextselegidis.com/plainpad/updates/stable自动更新源否(需挂载改 .env,见 5.4)
DB_CONNECTIONmysql数据库驱动否(官方部署路径仅 MySQL,见 5.3)
DB_HOSTlocalhost(镜像内默认 db)数据库主机是(DB_HOST)
DB_PORT3306数据库端口否
DB_DATABASE{DATABASE}(镜像内默认 plainpad)库名是(DB_NAME)
DB_USERNAME{USERNAME}(镜像内默认 root)数据库用户是(DB_USERNAME)
DB_PASSWORD{PASSWORD}(镜像内默认 secret)数据库口令是(DB_PASSWORD)

(表内「镜像内默认值」来自官方镜像 ENV 实查,传统 PHP 主机安装时以 .env.example 占位符为准。)

4.2 官方镜像环境变量总览

官方 Docker 部署只认这 7 个环境变量(来源:官方 Docker 文档 + 入口脚本实测):

环境变量映射到 .env 键说明
APP_KEYAPP_KEY不写进 .env,以环境变量直接生效(5.1)
BASE_URLAPP_URL生产写真实域名
DEBUG_MODEAPP_DEBUG仅接受 TRUE/FALSE(大小写均识别)
DB_HOSTDB_HOST等于数据库服务名
DB_NAMEDB_DATABASE库名
DB_USERNAMEDB_USERNAME用户名
DB_PASSWORDDB_PASSWORD口令

⚠️ 注意:镜像 ENV 里另有 MAIL_SMTP_*/MAIL_FROM_* 一批默认值,入口脚本并不处理它们——邮件配置不走环境变量(实测入口脚本全文无 MAIL 相关分支,见 5.5)。

4.3 应用级与用户级参数总览

层参数默认值(播种/表定义)修改入口
settingsdefault_localeen-USSettings 页 / API
settingsmail_driver / mail_host / mail_port / mail_username / mail_password / mail_encryption / mail_from_address / mail_from_namesmtp / smtp.mailtrap.io / 2525 / 空 / 空 / tls / hello@example.org / PlainpadSettings 页 Mail / API
userslocaleen-US(合法值见 5.6)Profile 页 / API
usersviewcompactProfile 页 / API
userslinefullProfile 页 / API
userssortmodifiedProfile 页 / API
usersthemelightProfile 页 / API
usersencrypt0(关)Profile 页 / API
usersadmin0仅管理员经 API/用户管理界面

五、核心参数分类详解

5.1 APP_KEY:加密命脉

APP_KEY 是 Laravel encrypter 的主密钥,Plainpad 用它派生每个用户笔记的加密密钥。官方文档与镜像注释反复强调:一次生成、永久复用,丢失即灾难。

实测优先级验证——.env 里 APP_KEY={KEY} 是占位符,而应用实际生效的是 compose 注入的环境变量值:

docker compose exec plainpad php artisan tinker --execute="echo config('app.key');"
# base64:vB6IesmBqpSCj5ruR1H0PjcSecgiBVNtdBjCNdRaeI0=

与 compose 文件里 APP_KEY=base64:vB6IesmBqpSCj5ruR1H0PjcSecgiBVNtdBjCNdRaeI0= 完全一致。入口脚本的密钥逻辑(官方镜像脚本原文摘录):

if grep -q "APP_KEY=$" /var/www/html/.env || grep -q "APP_KEY={KEY}" /var/www/html/.env; then
    cd /var/www/html && php artisan key:generate --force
fi

即:.env 里密钥为空或仍是 {KEY} 占位时尝试生成;若环境变量已提供 APP_KEY,key:generate 会拒绝覆写并打出 ERROR Unable to set application key. APP_KEY is already present in the environment.——这条 ERROR 正是「固定密钥」在按预期工作(B2 篇 11.3)。

生成方法(新部署时执行一次并永久保存):

echo "base64:$(openssl rand -base64 32)"

💡 技术拓展:APP_KEY 加密笔记的落盘格式是 Laravel encrypter 的 JSON 载荷,实测(5.6 加密闭环)形如 {"iv":"...","value":"...","mac":"..."},算法由 config/app.php 固定为 'cipher' => 'AES-256-CBC'(实查)并附 HMAC 防篡改。常见对称加密模式对比——

模式特点代表
AES-128/256-CBC + HMAC密文不可链式篡改需另配 MACLaravel encrypter 默认(本文所用)
AES-256-GCM自带认证标签,一次遍历完成加密+校验现代 TLS/存储加密主流
XSalsa20/ChaCha20无硬件加速环境性能好NaCl/libsodium 系

Plainpad 跟随 Laravel 默认 AES-256-CBC,密钥即 APP_KEY,因此换 APP_KEY = 全部密文报废。

5.2 BASE_URL / DEBUG_MODE:访问前缀与调试开关

入口脚本对这两个键的改写逻辑(官方镜像脚本原文摘录):

if [ -n "$BASE_URL" ]; then
    sed -i "s|APP_URL=.*|APP_URL=${BASE_URL}|g" /var/www/html/.env
fi
if [ -n "$DEBUG_MODE" ]; then
    if [ "$DEBUG_MODE" = "TRUE" ] || [ "$DEBUG_MODE" = "true" ]; then
        sed -i "s|APP_DEBUG=.*|APP_DEBUG=true|g" /var/www/html/.env
    else
        sed -i "s|APP_DEBUG=.*|APP_DEBUG=false|g" /var/www/html/.env
    fi
fi

实测对应关系:compose 设 BASE_URL=http://localhost:8139 → .env 内 APP_URL=http://localhost:8139(3.1 全文回显)→ artisan about 的 URL 行显示 localhost:8139(第一章回显),三处一致即映射生效。DEBUG_MODE=FALSE → APP_DEBUG=false → about 显示 Debug Mode ... OFF。

  • BASE_URL:应用生成绝对链接(如邮件内链接)的前缀,生产必须写真实域名(如 https://notes.example.com),否则通知邮件里的链接指向错误主机。
  • DEBUG_MODE:仅排障时临时 TRUE——出错页面会带堆栈与配置细节,公网环境常开等于信息泄露。

5.3 DB_*:数据库连接五键

compose 环境变量 DB_HOST/DB_NAME/DB_USERNAME/DB_PASSWORD 由入口脚本逐一 sed 进 .env(脚本原文与 5.2 同段,逻辑相同:if [ -n "$DB_HOST" ]; then sed ...)。实测生效链:compose DB_HOST=mysql → .env DB_HOST=mysql(3.1 回显)→ artisan about 的 Drivers 区 Database ... mysql(第一章回显)→ 数据读写正常(3.2 查库回显)。

后端支持范围:应用 config/database.php 保留了 Laravel 的 sqlite/mysql/pgsql/sqlsrv 四套连接模板(实查行号 38/46/66/81),但官方部署路径只支持 MySQL/MariaDB——入口脚本等待数据库就绪的 PDO 探测硬编码 mysql:host=,.env.example 也固定 DB_CONNECTION=mysql,官方文档示例同样只有 MySQL。把 DB_CONNECTION 改成 pgsql 会绕过入口脚本的等待逻辑且不被官方支持,生产勿试。

DB_PORT 固定 3306(.env 键存在但 compose 环境变量列表不含它;同网段服务名直连时默认端口足够)。

5.4 APP_REPOSITORY:自动更新源

.env 键 APP_REPOSITORY=https://cdn.alextselegidis.com/plainpad/updates/stable,实查其唯一消费点在自动更新服务提供者:

docker compose exec plainpad grep -rn "APP_REPOSITORY" app/
# app/Providers/AutoUpdateServiceProvider.php:21:            $autoUpdateService->setUpdateUrl(env('APP_REPOSITORY'));

它决定应用内 Settings→Update 与 API 根资源(GET /v1 的 updates 列表、PUT /v1 触发更新)从哪个源解析更新包;1.2.0 起发布包带 Ed25519 签名(.sig)校验,校验不过即拒绝(来源:官方 1.2.0 Release Notes,见 《Plainpad 1.2.0 介绍与选型指南》 篇三)。实测当前源无新版本时的行为:

curl -s -X PUT http://localhost:8139/api.php/v1 -H "Authorization: Bearer $TOKEN" -w '\nHTTP %{http_code}\n'
# HTTP 404

404 即「没有可安装的更新」(源码逻辑:检查源后无新版本直接回 404)。若内网隔离环境想自建更新源,需修改 .env 该键——但入口脚本不映射它,只能挂载自定义 .env 或进应用目录改文件,且 Docker 形态下官方不建议应用内自动更新(更新写入文件系统,重建即丢,见 B2 篇第五节),该键主要服务于传统 PHP 主机安装。

5.5 应用级设置(settings 表 9 键)

播种默认值来自官方 SettingsSeeder(实查源码),与 3.2 实测表对照即知哪些被改过:

键播种默认作用
default_localeen-US新用户默认界面语言
mail_driversmtp邮件传输方式
mail_hostsmtp.mailtrap.ioSMTP 主机
mail_port2525SMTP 端口
mail_username空SMTP 账号
mail_password空SMTP 口令
mail_encryptiontlsSMTP 加密方式
mail_from_addresshello@example.org发件人地址
mail_from_namePlainpad发件人名称

修改走管理员 API(非管理员调用返回 401,实测见 《Plainpad 1.2.0 API 使用详解》 篇)。下面是一次真实的 PUT 回写(值即当前生效状态)与 GET 复核:

curl -s -X PUT http://localhost:8139/api.php/v1/settings \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"default_locale":"zh-CN","mail_driver":"smtp","mail_host":"10.89.58.1","mail_port":"1025","mail_username":"","mail_password":"","mail_encryption":"","mail_from_address":"notes@quzuo.net","mail_from_name":"Plainpad"}' \
  -w '\nHTTP %{http_code}\n'
# HTTP 200(成功时响应体为空)

curl -s http://localhost:8139/api.php/v1/settings -H "Authorization: Bearer $TOKEN"
# {"mail_from_address":"notes@quzuo.net","mail_port":"1025","mail_password":"","mail_from_name":"Plainpad","default_locale":"zh-CN","mail_driver":"smtp","mail_host":"10.89.58.1","mail_encryption":"","mail_username":""}

两个要点:

  1. 邮件配置只存在于 settings 表,与镜像 ENV 里的 MAIL_SMTP_* 默认值无关(入口脚本不处理它们,官方文档明确 "Mail is not configured through environment variables")。忘记 SMTP 口令时改库或走 API,不要去翻环境变量。
  2. default_locale 只决定新用户/未设置偏好者的语言,已有用户各自 locale 列优先(3.3 表定义),所以改完 default_locale 老用户界面不变是预期行为(见 7.6)。

💡 技术拓展:mail_driver 可选的 Laravel 邮件传输方式——

驱动行为适用
smtp连 SMTP 服务器投递生产标准(本文实测用)
log邮件内容写日志不投递调试/审计
sendmail交给本机 sendmail 程序主机已有 MTA
array / null收件箱置内存/丢弃测试

Plainpad 播种默认 smtp;无邮件服务器时找回/通知邮件会静默失败(API 仍回 200),生产建议配真实 SMTP 或明确接受「无邮件」。

5.6 用户偏好(6 键)与加密开关闭环

偏好键与合法值(数据库 enum 约束实测 + 源码实查 app/Models/User.php 的 public const LOCALES = ['en-US', 'de-DE', 'fr-FR', 'sv-SE', 'zh-CN'];):

键合法值默认作用
localeen-US / de-DE / fr-FR / sv-SE / zh-CNen-US界面语言
viewcomfortable / compactcompact列表密度
linefull / narrowfull行宽
sortmodified / created / alphabeticalmodified笔记默认排序
themelight / darklight主题
encrypt0 / 10服务端加密开关(见下)

修改实测(管理员 PUT 用户,成功回显返回整个用户对象):

curl -s -X PUT http://localhost:8139/api.php/v1/users/7a17c8fd-b84f-4f2c-8ba3-2a484c1a0e1e \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"name":"Admin","email":"admin@example.org","locale":"en-US","view":"compact","line":"full","sort":"modified","theme":"light","admin":true,"encrypt":true}'
# {"id":"7a17c8fd-b84f-4f2c-8ba3-2a484c1a0e1e","created_at":"2026-11-02T00:20:21.000000Z","updated_at":"2026-11-02T00:47:23.000000Z","name":"Admin","email":"admin@example.org","locale":"en-US","view":"compact","line":"full","sort":"modified","theme":"light","encrypt":true,"admin":true}

⚠️ 注意:PUT 是全量提交语义——payload 必须带齐 name/email/locale/view/line/sort/theme/admin/encrypt 全部字段,漏字段即被重置或校验失败(1.2.0 之前「编辑用户丢失加密标志导致笔记不可读」正是这类事故的官方修复,来源:1.2.0 Release Notes)。

encrypt 开关闭环实测(本次取证的核心):

第一步,开启 encrypt 后新建笔记,API 返回明文、但数据库落密文:

curl -s -X POST http://localhost:8139/api.php/v1/notes \
  -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
  -d '{"title":"加密测试标题","content":"这是会被服务端加密的正文内容。","pinned":false}'
# 输出节选:{"id":"01c33676-f0ec-49a5-a7eb-32b1e8afe0c8",...,"title":"\u52a0\u5bc6\u6d4b\u8bd5\u6807\u9898","content":"\u8fd9\u662f\u4f1a\u88ab\u670d\u52a1\u7aef\u52a0\u5bc6\u7684\u6b63\u6587\u5185\u5bb9\u3002",...}

docker compose exec mysql mysql -uroot -psecret -e "select left(title,60) as t,left(content,60) as c from plainpad.notes;"
t                                                            c
eyJpdiI6Im1FZnRMZzJ0MUZYZnJjZFNwS2lxU2c9PSIsInZhbHVlIjoiZ0hx  eyJpdiI6IjA2YzZpUGoyMTZsalQ2UXdWa0hBYkE9PSIsInZhbHVlIjoiV2hw

base64 解开头即 {"iv":...,"value":...}——标题与正文均以 Laravel encrypter 密文入库(5.1 拓展表),这正是官网「你写的日记 vs 数据库里的密文」演示的落地形态。

第二步,把开关切回关闭,既有笔记被批量解密回明文——实测先建一条明文基线笔记,再开开关,笔记立即变密文;再关开关,DB 直接查回明文:

docker compose exec mysql mysql --default-character-set=utf8mb4 -uroot -psecret -e "select left(title,30) as t,left(content,30) as c from plainpad.notes;"
t          c
明文基线    关闭状态下的正文

即:开关切换 = 对该用户全部笔记做一次完整的解密/加密重写,API 读取始终透明返回明文。这带来两个运维含义:数据量大的账号切换开关耗时随笔记数线性增长;切换中途失败会留下混合状态(1.2.0 已修复此缺陷,来源:官方 Release Notes),切换前务必备份数据库(B2 篇 10.3)。

六、生产配置模板

综合前三章,生产环境(真实域名 + HTTPS 反代之后)的 compose 配置模板:

name: plainpad-prod

services:
  plainpad:
    image: alextselegidis/plainpad:latest
    depends_on:
      - mysql
    ports:
      - '127.0.0.1:80:80'          # 只监听回环,由 Nginx/Caddy 反代终结 TLS
    environment:
      - APP_KEY=base64:你的固定密钥-openssl-rand-base64-32生成后存入密码管理器
      - BASE_URL=https://notes.example.com
      - DEBUG_MODE=FALSE
      - DB_HOST=mysql
      - DB_NAME=plainpad
      - DB_USERNAME=plainpad
      - DB_PASSWORD=换强口令与mysql服务一致
    networks:
      - plainpad-net

  mysql:
    image: mysql:8.0
    command: --default-authentication-plugin=mysql_native_password
    environment:
      - MYSQL_ROOT_PASSWORD=换强口令
      - MYSQL_DATABASE=plainpad
      - MYSQL_USER=plainpad
      - MYSQL_PASSWORD=与上方DB_PASSWORD一致
    volumes:
      - db_data:/var/lib/mysql
    networks:
      - plainpad-net

volumes:
  db_data:

networks:
  plainpad-net:
    driver: bridge

相对实验版(B2 篇)的三处生产化改动及理由:

  1. BASE_URL 写真实域名:5.2——邮件内链接与生成 URL 的唯一来源;
  2. 数据库改用普通账号:不再 root 直连,MYSQL_USER/MYSQL_PASSWORD 与 DB_USERNAME/DB_PASSWORD 对应即可(入口脚本只认这 5 个 DB 键,5.3);
  3. 端口只绑 127.0.0.1:PWA 安装与「加密传输」前提都要求 HTTPS,TLS 交给反向代理(官方文档:安装为应用需要 HTTPS)。

上线后按序验证与加固(每步都有实测方法):

curl -s -o /dev/null -w 'HTTP %{http_code}\n' https://notes.example.com/   # 期望 200
  1. 用默认管理员 admin@example.org / 12345678 首登,立即在 Profile 改邮箱与密码(官方播种值人人可知);
  2. Settings→Mail 填真实 SMTP(5.5),发一封找回密码邮件验证投递;
  3. Settings 改 default_locale 为团队语言;
  4. 每个账号在 Profile 按需开 encrypt(5.6,开前备份)。

七、常见问题

7.1 直接编辑了 .env,重启后改动被吞

现象:进应用目录改了 .env 的 APP_URL/DB_HOST 等,docker compose restart 后改回原值。原因:入口脚本每次启动按环境变量 sed 覆写这些键(5.2/5.3 脚本原文)。解决:改动一律落到 compose environment: 再 docker compose up -d plainpad;入口脚本不覆写的键(如 APP_REPOSITORY)直接改 .env 才有效,但重建应用文件系统时 .env 若未挂载会按模板重建——长期定制建议挂载持久化或接受「环境变量 + 应用内设置」的官方面。

7.2 重启日志出现 "ERROR Unable to set application key"

ERROR  Unable to set application key. APP_KEY is already present in the environment.

无害(B2 篇 11.3):.env 内 APP_KEY 是 {KEY} 占位、触发入口脚本的 key:generate --force,而环境变量已有固定密钥,Laravel 拒绝覆写——这正是 5.1 描述的「环境变量优先、密钥固定」在正常工作。可忽略。

7.3 想用 MAIL_SMTP_* 环境变量配邮件,改了没反应

镜像 ENV 里的 MAIL_SMTP_*/MAIL_FROM_* 是残留默认值,入口脚本不处理(4.2 注意项),官方文档明确邮件不走环境变量。解决:应用内 Settings→Mail 或 API PUT /v1/settings(5.5 实测)。

7.4 换了 APP_KEY,加密笔记全部无法打开

APP_KEY 是笔记密文的派生密钥(5.1),换 key 后旧密文永久不可解。恢复方法只有一个:把 APP_KEY 改回原值。预防:密钥生成即入密码管理器,compose 文件纳入备份;这也是官方文档反复强调「固定复用」的原因。

7.5 开启/关闭 encrypt 后应用短暂无响应

开关切换会重写该用户全部笔记的密文/明文(5.6 实测语义),笔记量大时耗时线性增长。操作前备份数据库(B2 篇 10.3),避开高峰执行。

7.6 改了 default_locale,老用户界面语言没变

预期行为:default_locale 只作用于新用户(5.5),每个用户的 locale 列优先。让老用户各自在 Profile 改语言,或管理员经 API PUT /v1/users/{ID} 代改(5.6 实测,注意全量字段)。

八、参考链接

Plainpad 1.2.0 配置参数详解 - Quzuo