周日上午十点,我盯着Google Analytics的新版界面,突然意识到扎心的事实——我网站那点可怜的流量,正在成为谷歌广告机器的免费燃料。更魔幻的是,我还主动嵌入了追踪代码,请它来收集。那一刻,我决定全部推倒重来,用开源的Matomo夺回数据主动权。
结果这趟“自由之旅”比想象中折腾得多,每一步都有坑等着。下面这份诚实到残忍的部署清单,记录了我踩过的五个大坑和最终爬出来的方法,每一个都是用半小时以上的debug时间换来的。
先说第一个大坑:Docker 权限的“防呆”陷阱。官方文档上来就让把用户加到 docker 组:sudo usermod -aG docker $USER,然后 newgrp docker。看似人畜无害的两行命令,实则暗藏杀机——如果你跳过 newgrp 直接跑 docker 命令,就会收到冷冰冰的 permission denied,然后怀疑自己是不是写错了用户名。newgrp 的作用是刷新当前会话的组权限,不然你就算加了组,shell 还是认旧身份。很多人在这里浪费过半小时去重启机器,我就干过。更值得吐槽的是,这种设计本身就很反直觉:把用户添加到某个组,难道不应该立刻生效吗?Linux 的组权限模型就是这么老派,它要求你重新登录或者用 newgrp 手动刷新,仿佛在说“你确定要这么干?确定就再敲一行”。这一步虽然简单,但它是整个部署的第一道心态测试——能心平气和走完,后面才撑得住。
第二坑:环境变量文件里的“明文炸弹”。按照教程,我们需要创建 .env 文件,里面躺着两行密码:MYSQL_ROOT_PASSWORD 和 MYSQL_PASSWORD,并且要求至少16位字符。教程很贴心地提醒用强密码,但没告诉你:这个文件会原样躺进项目目录,任何能访问服务器的人,一个 cat .env 就能拿到数据库王牌。我一边生成 32 位随机字符串,一边心想:这不就是现代版的把钥匙垫在门垫下面吗?更讽刺的是,我们费劲巴拉地摆脱谷歌追踪,结果自己却在本地留下一个明文密码文件。当然,你可以事后用权限控制、秘钥管理工具来擦屁股,但部署指南对此只字未提。很多新手就这样把 .env 草草丢进服务器,然后某天发现数据库被勒索病毒光顾。这种隐性风险,正是“照教程跑通”和“真正安全落地”之间的鸿沟。所以我的血泪补丁是:创建完 .env 立刻 chmod 600,并且永远不要提交到版本控制。顺便说一句,Docker Compose 读取 .env 的行为也很贼,它会把文件中所有变量自动注入到容器环境,意味着你万一写了个多余的变量,它也会悄悄跟进去,不留一丝痕迹。
第三坑:Nginx 反向代理的“照抄就死”配置。教程给的 matomo.conf 在两个 server 块里都出现了 server_name matomo.example.com,而且证书路径里也嵌着同样的域名。很多人想当然地把 matomo.example.com 替换成自己的真实域名,然后发现 Nginx 死活起不来——因为证书文件根本还不存在。这个配置文件暗藏一个时序依赖:证书签发工具尚未生成有效证书之前,443 段落的 ssl_certificate 指向的是空路径。幸好,部署流程设计得很巧妙:先只启动 db 和 app,然后把 Nginx 和证书客户端都晾在一边,等到用 standalone 模式拿到证书后,才启动 Nginx。但这中间的“空窗期”很反常识:你看着 Nginx 的配置里明明写着监听 443,端口也开了,但访问网站就是失败。很多人会下意识地去重启、检查证书路径,然后陷入死循环。根本原因就是:配置是提前写好的“架子”,必须等证书就位后才能启用。这种模式就像先印好带照片的员工卡,结果入职当天拍照系统宕机。所以,关键是把启动顺序刻在脑子里:先 db 和 app;然后停掉一切占 80 端口的进程,用证书工具 standalone 模式获取证书;最后再启动 Nginx。一旦顺序错了,端口被占用,整个签发操作会直接挂掉。
第四坑:Docker Compose 编排里的“依赖幻觉”。docker-compose.yaml 里 app 服务配置了 depends_on: - db,看起来像那么回事,但老手都知道,这仅仅保证 db 容器先启动,根本不检查 MariaDB 是否真的准备好接受连接。于是经典场景来了:app 容器启动飞快,Matomo 应用程序立刻尝试连接数据库,而 MariaDB 还在慢悠悠初始化数据目录,结果就是满屏的“无法连接数据库”错误。应用日志里那一行行红色的 access denied 能瞬间击溃信心。解决办法是给 db 服务添加健康检查,并让 app 的 depends_on 带上 condition: service_healthy,这样 Docker Compose 会等到数据库通过健康检测后才启动应用容器。另一种土办法是在 app 的启动命令里加入一个等待循环,但前者更优雅,也更贴合容器化的初衷。不看穿这层依赖幻觉,你很可能在第一个 docker-compose up 就心态爆炸。
第五个坑最隐蔽:证书到期前的静默死亡。部署完后很多人以为万事大吉,却不知道 Let’s Encrypt 证书只有 90 天有效期。如果没有配置自动续期任务,三个月后网站就会因为证书过期而无法访问,访客只看到满屏的安全警告。证书客户端提供了续期命令和定时任务模板,但很多教程压根不提这一茬。你必须在 crontab 里添加一条每周执行一次的续期指令,并让 Nginx 重新加载配置,否则前面所有折腾都会以“网站挂了”尴尬收场。这最后一公里,才是真正区分玩具部署和生产级部署的分水岭。
热门跟贴