网站发了一篇新教程,访问数字增加了,却不知道读者去了哪个页面、从哪里进来。服务器日志能记录请求,但图片、机器人和页面访问混在一起,直接数请求容易得到错误结论。Umami 可以收集网页访问与事件,给站点维护留一份容易查看的统计。
自建统计需要部署服务,也需要把追踪脚本放到网站里。统计后台正常,不代表目标网站已经发送数据。这篇先安装一个小实例,再用可识别的测试访问核对路径、网站 ID 和事件,最后安排数据库备份。后台数字来自实际成功收集的请求,不等于所有访问者的完整记录。
先决定要回答哪几个问题
个人站点可以先关注页面访问、来源和设备分布,看看新文章有没有被打开、主要入口来自哪里。不要第一次就给每个按钮加事件,得到几十张没人看的图表。先用一个真实问题决定要记录什么,再验证收集结果是否支持判断。
访问量和访客数的含义不同,机器人、屏蔽脚本、浏览器限制与重复访问也会影响结果。比较两个时间段时,确认追踪方式没有中途变化。脚本刚装上的数据不能直接和以前只有服务器请求日志的数字混在一起做趋势。
不在事件字段里提交用户密码、令牌或完整表单内容。页面 URL 也可能带敏感参数,安装之前就应检查目标网站实际会生成什么地址。是否需要收集、告知与限制范围,按网站实际业务要求安排,不能以工具的某个宣传词代替判断。
准备 PostgreSQL 与应用配置
服务器已经安装 Docker Engine、Compose 插件,当前账号有 Docker 权限。Caddy 安装在宿主机,stats.example.com 已解析到 VPS。这个统计域名与被统计网站可以不同,数据库只在 Compose 网络中访问。
mkdir -p /opt/umami/db
cd /opt/umami
umask 077
openssl rand -hex 32
openssl rand -hex 32
openssl rand -hex 32
创建 .env,分别填写数据库密码、应用 secret 和二次验证加密密钥。最后一个值按当前配置要求使用 64 位十六进制字符串,上面的 rand -hex 32 会生成这种格式。三个字段使用不同随机值,不套用公开密码。
UMAMI_DB_PASSWORD=your-generated-database-password
UMAMI_APP_SECRET=your-generated-app-secret
UMAMI_TWO_FACTOR_KEY=your-generated-64-character-hex-key
chmod 600 .env
密钥需要跨重启保持稳定,并进入受保护的备份。数据库密码在 URL 中使用十六进制值可以避免未编码特殊字符的解析问题;若自行换成含特殊字符的密码,需要按连接 URL 的规则编码。
按官方模板启动服务
保存为 compose.yaml。研究时项目官方模板使用 PostgreSQL 15 Alpine,数据路径为 /var/lib/postgresql/data,与 PostgreSQL 18 的目录不同。不要把另一篇教程的数据挂载随手放进来,也不要覆盖已存在的大版本数据库。
services:
umami:
image: ghcr.io/umami-software/umami:latest
restart: unless-stopped
init: true
ports:
- "127.0.0.1:3002:3000"
environment:
DATABASE_URL: postgresql://umami:${UMAMI_DB_PASSWORD:?set database password}@db:5432/umami
APP_SECRET: ${UMAMI_APP_SECRET:?set app secret}
TWO_FACTOR_ENCRYPTION_KEY: ${UMAMI_TWO_FACTOR_KEY:?set two factor key}
DISABLE_TELEMETRY: "1"
depends_on:
db:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:3000/api/heartbeat || exit 1"]
interval: 30s
timeout: 5s
retries: 3
db:
image: postgres:15-alpine
restart: unless-stopped
environment:
POSTGRES_DB: umami
POSTGRES_USER: umami
POSTGRES_PASSWORD: ${UMAMI_DB_PASSWORD:?set database password}
volumes:
- ./db:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]
interval: 5s
timeout: 5s
retries: 5
首次拉取当前镜像,检查通过以后固定摘要或正式版本,避免后台自动跨版本变化。DISABLE_TELEMETRY 控制 Umami 自身的匿名遥测,不是让网站追踪脚本停止收集,也不能说明所有数据都已按你的业务要求处理好。
docker compose config --quiet
docker compose pull
docker compose up -d
docker compose ps
docker compose logs --tail=100 umami db
数据库初始化或迁移失败时先读相应日志,不删除目录重装。应用界面能够返回响应,也要检查数据库健康和迁移状态。重启之后出现账号或站点消失,则优先核对是否使用了原来的数据库挂载。
默认密码改好,再公开统计域名
先通过 SSH 转发打开本机 13002 端口,替换 SSH 用户和服务器地址。官方当前安装文档给出的默认账号是 admin,密码 umami,首次登录后立即修改。
ssh -N -L 13002:127.0.0.1:3002 [email protected]
给其他维护者建立独立账号,根据需要分配网站权限,不共用管理员。二次验证功能需要稳定的加密密钥,启用以后保存恢复资料,并核对退出、重新登录是否正常。
宿主机 Caddy 添加下列站点段,验证配置后重载。代理运行在容器里时,改成共享网络里的服务名与端口。
stats.example.com {
reverse_proxy 127.0.0.1:3002
}
此时用正式 HTTPS 地址登录,确认未登录者不能进入后台。不要在整个域名前面简单增加一个会阻断脚本和收集接口的登录墙,再期待公开网站继续上报;后台访问限制与公开收集入口的安排需要一起设计并验证。
追踪代码放到正确的网站
在后台添加网站,填写实际域名,再复制界面生成的追踪代码。不同网站有不同 ID,不因为它们用相同模板就复制同一个 ID。下面只展示代码结构,替换成自己后台生成的准确值。
<script defer src="https://stats.example.com/script.js" data-website-id="replace-with-generated-website-id"></script>
通过网站模板或明确的部署入口加入代码,不在多个组件重复插入。页面源代码里出现一次脚本,再用浏览器网络面板确认 script.js 成功加载,检查收集请求有没有被内容安全策略、代理或浏览器扩展阻断。
统计网站改过默认脚本名称或收集路径时,追踪代码也要匹配。不要为了绕过屏蔽把字段随机改名后跳过验证,那可能只是让请求换一个地址失败。保留准确的网站 ID,逐项确认加载与上报。
用一个带标记的访问核对数据
选择自己网站中一个便于辨认的测试页面,打开后在后台查看对应网站的实时或近期记录。核对路径、域名、时间和设备,不只看总数字有没有多一。如果同时有真实访问,可以用测试页面路径区分,避免误把其他读者当作自己的测试。
再从手机打开相同页面,确认数据进入同一个网站。然后打开另一篇文章,检查路径是否变化。采用前端路由的网站需要验证实际导航能否被记录,不把完整刷新成功的结果直接套到所有页面切换。
需要记录下载或按钮事件时,使用当前官方接口建立一个明确事件,先在测试环境触发一次,核对名称和字段。事件表示客户端提交了一个动作,不能自动证明下载文件完整、订单成功或用户真正读完内容;业务结果需要对应的验证。
公开分享统计视图之前,用未登录窗口查看能看到什么。路径、来源和事件可能含内部信息,管理权限与分享链接分别检查。账号被删除或网站归属变化后,过去的分享入口是否仍有效也需要核对。
数字偏低时先查追踪链路
后台完全没有新数据,先看脚本是否加载、ID 是否准确、收集请求是否成功,再查服务器日志。脚本部署在缓存模板里,可能要等缓存更新才能出现在所有页面,不是刷新统计后台就能解决。
某些浏览器有数据、另一些没有,检查扩展、网络与策略差异。阻止统计脚本的访问本来就不会出现在相同口径里。不要为了让数字更大就删除所有过滤设置,先明确你想比较的口径。
突然增长时,检查热门路径、来源和部署变化,区分真实传播、重复脚本和异常请求。同一页面插了两份追踪代码可能造成不合理的记录;此时先修安装,再讨论内容效果。
统计页响应慢时同时看应用、数据库、VPS 资源和数据量。不要用删除全部历史作为第一步排障。若需要清理,先备份,再按官方支持的保留与删除方式操作,并记录口径从哪天改变。
数据库和密钥一起备份
统计数据在 PostgreSQL,配置中保存数据库连接、应用 secret 与二次验证加密密钥。备份要把这些材料配套保存。为了取得一致副本,可以安排短维护窗口停止应用,再导出数据库,完成后恢复服务。
cd /opt/umami
mkdir -p /opt/backups/umami
docker compose stop umami
docker compose exec -T db pg_dump -U umami -d umami -Fc > /opt/backups/umami/database.dump
tar -czf /opt/backups/umami/config.tgz compose.yaml .env
docker compose start umami
正式使用为每一批备份建立日期目录,不覆盖唯一可恢复的副本。停止应用期间收集接口不可用,维护窗口应尽量短,不能把这一段缺失数据看作没有访问。导出失败时也要恢复服务,并检查输出是否有效。
恢复演练使用独立数据库和原版本应用,临时入口保持私人,不把正式网站脚本指向测试实例。检查账号、网站 ID、历史数据和权限,再验证二次登录流程。切换正式入口后发一条新的测试访问,确认数据继续落进恢复后的库。
升级出现数据库迁移时,回退要用升级前数据库和旧镜像配套恢复。迁移统计域名还要检查所有网站的追踪地址与内容安全策略。保留这份接入清单,下一次移动 VPS 时才知道哪些页面需要一起检查。