【实用的开源工具】Umami:用 Docker 和 PostgreSQL 自托管的网站统计
「实用的开源工具」系列:我只收集值得用的开源项目,写清楚它能做什么、怎么部署、有哪些坑,并在文末标明出处。内容整理自官方文档,核对日期 2026-10-31,具体版本以官方为准。文中的命令来自官方 README、文档站和仓库里的 Compose 文件,我没有在本文里逐条实际运行过,上线前请先在测试环境走一遍。
项目信息卡
| 项目 | 说明 |
|---|---|
| 名称 | Umami |
| 做什么 | 开源的网站与产品分析平台,官方 README 称其“隐私优先”,不使用 cookie,可自托管也可用官方云服务 |
| 许可证 | MIT |
| 仓库 | github.com/umami-software/umami |
| 文档 | docs.umami.is(umami.is/docs 会跳转到这里) |
| 最近版本 | v3.4.1(2026-10-23 发布,查询于 2026-10-31)。官方发布说明称这是一个以安全修复为主的版本,建议所有自托管用户升级 |
| 状态 | 仓库未归档,最近一次提交在 2026-10-31 |
| 数据库 | 只支持 PostgreSQL,官方 FAQ 写的最低版本是 v12.14 |
| 运行方式 | 官方 docker compose(应用加 PostgreSQL 两个容器),也可以从源码构建(需要 Node.js 和 pnpm) |
| 默认账号 | 首次建库会创建用户名 admin、密码 umami 的管理员账号,官方要求第一次登录后立刻改密码 |
| 可选组件 | Redis(REDIS_URL,不设就不启用相关功能) |
| 云版差异 | 官方文档表格里写明:邮件报告只在云版提供,其他列出的分析功能自托管版也有 |
官方说明里值得注意的几点
- 官方 FAQ:Umami 的网页跟踪脚本不使用 cookie;是否需要弹 cookie 提示取决于你用的其他服务和适用的法规。
- 官方 FAQ:自托管数据默认永久保留,除非你手动删除。
- 官方环境变量文档:Umami 会收集“完全匿名的遥测数据”用于改进应用,可以用
DISABLE_TELEMETRY关闭;也有DISABLE_UPDATES(关闭新版本检查)和PRIVATE_MODE(关闭所有外部网络请求,网站图标也会因此不显示)。
它能做什么
- 基础统计:页面浏览量、访客、来源、地区、设备、实时活动。
- 营销与转化:UTM 活动、链接、像素、目标、漏斗、归因、留存、收入报告。
- 行为分析:自定义事件、用户旅程、会话回放、热力图(版本要求见各功能页的标注)。
- 团队与共享:看板(boards)、团队、共享链接、API,以及一个默认关闭的官方只读 MCP 服务(需要
MCP_ENABLED=1)。 - 两步验证:v3.3.0 起支持 TOTP 双因素认证,需要先配置密钥(见下文)。
不太适合的场景:你的服务器上只有 MySQL,不想再多装一个 PostgreSQL;或者你需要邮件报告这类官方只在云版提供的功能。
和同类项目怎么选
下面只列我在各项目官方文档里核对过的事实,不涉及性能和“谁更好”的比较:
| Umami | Plausible CE | Matomo | |
|---|---|---|---|
| 许可证 | MIT | AGPL-3.0 | GPL-3.0(或更高) |
| 数据库 | PostgreSQL | PostgreSQL + ClickHouse | MySQL 或 MariaDB |
| cookie | FAQ 称网页跟踪脚本不使用 cookie | README 称不使用 cookie | 默认跟踪代码会设置第一方 cookie,可在后台强制无 cookie |
| 运行环境 | Docker 或 Node.js | Docker(官方流程) | PHP + Web 服务器,官方也有 Docker 镜像 |
怎么选:手上只想多装“一个应用加一个 PostgreSQL”,Umami 的部署最直接;需要 ClickHouse 的统计引擎可以看 Plausible;习惯 PHP 加 MySQL 的传统环境可以看 Matomo。许可证上,MIT 对二次开发和商用的限制最少,AGPL 和 GPL 有各自的开源义务,用于商业产品前请自己读条款。至于是否需要弹同意提示,请按你所在地区的法规自己判断,官方说“无 cookie”不等于不用考虑合规。
部署
官方安装页面给了几种方式:源码构建、Docker Compose、预构建 Docker 镜像,以及第三方维护的 Kubernetes Helm chart。这里只讲最常用的 Docker Compose。
准备
- 一台装好 Docker 和 Docker Compose 的服务器。
- 一个域名(下文用
stats.example.com),DNS 指向服务器。
第 1 步:生成密钥,写 .env
官方文档里 APP_SECRET 和 TWO_FACTOR_ENCRYPTION_KEY 都给了 openssl rand -hex 32 作为生成办法。数据库密码是我加的,用 openssl rand -hex 16 生成,只含十六进制字符,放进连接地址里不会因为特殊字符出问题(通用做法)。
mkdir -p /opt/umami && cd /opt/umami
echo "POSTGRES_PASSWORD=$(openssl rand -hex 16)" >> .env
echo "APP_SECRET=$(openssl rand -hex 32)" >> .env
echo "TWO_FACTOR_ENCRYPTION_KEY=$(openssl rand -hex 32)" >> .env
chmod 600 .envAPP_SECRET:官方说明是用来保护认证令牌的随机字符串,每个安装都应该有独一无二的值。TWO_FACTOR_ENCRYPTION_KEY:64 位十六进制字符串,用来加密双因素认证的密钥;设置之前没人能启用 2FA。
第 2 步:compose.yaml
下面基于官方仓库的 docker-compose.yml,改动有四处:镜像固定到具体版本;端口只绑定本机;密码和密钥改从 .env 读取;其余(健康检查、PostgreSQL 15 镜像、数据卷)与官方一致。
services:
umami:
image: ghcr.io/umami-software/umami:3.4.1
ports:
- "127.0.0.1:3000:3000"
environment:
DATABASE_URL: postgresql://umami:${POSTGRES_PASSWORD}@db:5432/umami
APP_SECRET: ${APP_SECRET}
TWO_FACTOR_ENCRYPTION_KEY: ${TWO_FACTOR_ENCRYPTION_KEY}
depends_on:
db:
condition: service_healthy
init: true
restart: always
healthcheck:
test: ["CMD-SHELL", "curl http://localhost:3000/api/heartbeat"]
interval: 5s
timeout: 5s
retries: 5
db:
image: postgres:15-alpine
environment:
POSTGRES_DB: umami
POSTGRES_USER: umami
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- umami-db-data:/var/lib/postgresql/data
restart: always
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
interval: 5s
timeout: 5s
retries: 5
volumes:
umami-db-data:关于这几处改动:
- 官方 Compose 里镜像写的是
ghcr.io/umami-software/umami:latest,端口是"3000:3000"(对所有网卡开放)。官方 README 和文档的预构建镜像命令写的是docker.umami.is/umami-software/umami:latest,是同一个项目的另一个镜像地址。我查了 GHCR 的标签列表,3.4.1确实存在;之后升级时请先确认目标标签存在再改。 - 官方 Compose 里
APP_SECRET写的是占位符replace-me-with-a-random-string,PostgreSQL 密码是umami,直接拿去用等于用公开的值,所以我改成从.env读取。 - 数据库容器没有发布任何端口,保持这样。
第 3 步:启动
docker compose up -d
docker compose ps官方说明会创建 PostgreSQL 数据库并启动 Umami,默认监听 3000 端口。第一次启动时会建表,并创建默认管理员账号。
反向代理
官方文档对反向代理只说了一句:需要把请求从你的 Web 服务器代理过来,默认应用在 http://localhost:3000。文档里最接近的 Nginx 示例是“启用 Cloudflare 头”那一页,其中的 proxy_set_header 部分可以参考。下面是我据此写的最小示例(不是官方给的完整配置,证书和细节请按自己环境调整):
server {
listen 443 ssl;
server_name stats.example.com;
ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/privkey.pem;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $host;
proxy_pass http://127.0.0.1:3000;
}
}要点:
- 官方环境变量文档里的
CLIENT_IP_HEADER用来指定读取访客 IP 的请求头,适合代理使用了非标准头的情况。 TRUSTED_PROXIES(多层代理时用)在官方文档里标注的版本是 v3.5.0,比目前最新发布的 v3.4.1 还新,所以本文不展开,用到时请先确认你的版本。- 想要 Cloudflare 提供的地区和城市数据,需要在 Cloudflare 里开启 “Add visitor location headers”,并让代理转发
CF-IPCountry、CF-Region-Code、CF-IPCity。官方提醒:只转发来自可信 Cloudflare 连接的这些头,并限制源站访问,防止客户端伪造。 - 想把 Umami 放在子路径下,官方有
BASE_PATH变量,但它是构建时变量(只在构建过程,包括自建 Docker 镜像时生效),预构建镜像用不上。最省事的办法是用独立的子域名。
第一次使用 / 把统计代码装到网站
- 登录并改密码。 打开
https://stats.example.com,用admin/umami登录。官方登录页的说明:登录后点侧边栏的个人资料按钮,进入 Settings,再到 Profile,点 Change password。 - (建议)开启双因素认证。 在 Settings 的 Security 标签里开启,前提是你已经配置了
TWO_FACTOR_ENCRYPTION_KEY。启用后官方会生成 10 个一次性备份码,只显示一次,要保存好;输错 5 次会锁定 15 分钟。 - 添加网站。 点侧边栏的 Websites,点右上角 Add website,填写名称和域名,点 Save。官方说明:名称随意,通常和域名相同;域名用来在引荐来源里过滤掉你自己网站。
- 拿到跟踪代码。 对要统计的网站点 Edit,在 Tracking code 区域复制代码。
- 贴到网站的
<head>里。 官方给的脚本形式是下面这样(data-website-id是你网站的编号,请复制你后台里显示的那份):
<script defer src="https://stats.example.com/script.js" data-website-id="你的网站ID"></script>- 访问你的网站,数据会很快出现在 Umami 面板里。官方排错提示:没数据时,打开浏览器开发者工具的 Network 标签,看有没有向你的 Umami 实例发出请求、脚本有没有加载报错;广告拦截器可能会阻止脚本。Next.js 要用
next/script组件插入;单页应用不需要额外配置,Umami 会自动统计页面切换。
跟踪脚本还能用 data- 属性配置,常用的有:
data-domains:只在指定域名运行(逗号分隔,按window.location.hostname匹配,注意带不带www),避免预发布环境污染数据。data-host-url:把数据发送到别的地址。data-tag:给事件打标签,用于筛选和 A/B 测试。
更新与卸载
更新
官方文档的 Docker 更新方式是拉新镜像并重建容器:
cd /opt/umami
# 把 compose.yaml 里的镜像标签改成要升级的版本(先确认标签存在)
docker compose pull
docker compose up --force-recreate -d补充几点:
- v3.4.1 的发布说明提到它更新了 Docker 基础镜像(固定为 Node 22.23.4-alpine,含当月 Node.js 安全修复),并说“重新构建或重新拉取镜像”才能得到。所以使用
latest标签的话,隔一段时间也要重新拉一次。 - 官方更新页面还提到:大版本升级(比如升到 v3)会运行数据库迁移,在大实例上可能让 PostgreSQL 的查询规划器统计信息过期,导致面板查询变慢,需要执行
ANALYZE;,官方说这个操作可以在线进行,很快完成。在本文的 Compose 里可以这样执行(用户名和库名取自上面的 Compose,这是我的改写):
docker compose exec db psql -U umami -d umami -c "ANALYZE;"- 备份:官方更新页没有写备份命令。升级前备份 PostgreSQL 数据(比如
pg_dump,或者备份umami-db-data数据卷)是通用建议。
从源码安装的话,官方更新步骤是 git pull、pnpm install、pnpm build,然后重启(用 PM2 的话执行 pm2 restart umami)。
卸载
官方文档没有卸载章节。通用做法:
cd /opt/umami
docker compose down # 停止并删除容器,数据卷保留
# docker compose down -v # 连同 umami-db-data 数据卷一起删除,统计数据会永久丢失别忘了把网站里的 <script> 去掉。
踩坑清单
- 默认账号是
admin/umami,第一次登录就改。 官方在安装页和登录页都强调了这点。部署完先别急着公开域名,尽快改掉密码再对外。 APP_SECRET每个安装都要自己生成。 官方 Compose 里的replace-me-with-a-random-string只是占位符,用openssl rand -hex 32生成并保密。TWO_FACTOR_ENCRYPTION_KEY要保管好。 官方说明:丢失或更换这个密钥,会让已保存的双因素密钥无法读取,受影响的用户需要重新绑定。- v3.4.1 是安全修复版,别一直停在旧版本。 发布说明列出了依赖升级和基础镜像更新,并明确建议所有自托管用户升级。固定版本号方便回滚,但要记得定期看发布说明。
- 文档可能比已发布版本新。 官方环境变量文档里的
TRUSTED_PROXIES、ERRORS_PER_MINUTE标注的版本是 v3.5.0,而最新发布的是 v3.4.1。每个变量旁边都有版本号,用之前对一下你的版本。 - README 和文档对 Node.js 的版本要求不一致。 README 写 Node.js 18.18+,文档站的安装页写 20.19 或更新(推荐 22 LTS)。用 Docker 部署不受影响;从源码构建的话,以文档站为准。
- 只支持 PostgreSQL。 官方 FAQ 和安装页都写的是 PostgreSQL(最低 v12.14)。GHCR 的标签列表里还留着
mysql-v2.x这样的旧标签,属于 v2 时代,网上的老教程不要照抄。文档还建议把 PostgreSQL 配置为 UTC 时区,避免时间戳不一致。 - 官方 Compose 默认把 3000 端口开放给所有网卡。 我改成了
127.0.0.1:3000:3000。Docker 发布的端口会绕过 ufw 之类的防火墙(通用经验),数据库容器也不要发布端口。 - 构建时变量对预构建镜像不生效。 官方把
BASE_PATH、FORCE_SSL、DATABASE_TYPE等列为构建时变量,只在构建(包括自建镜像)时被识别。想用 HTTP 严格传输安全头(FORCE_SSL的作用),用预构建镜像时更现实的办法是在反向代理里加(通用做法)。 - 反向代理要把访客真实 IP 传给 Umami。 否则统计里记录的是代理的地址。非标准头用
CLIENT_IP_HEADER指定。 - 没有 cookie,同一网络下的访客可能被合并。 官方会话文档说明,默认的会话标识由网站 ID、访客 IP、浏览器 User-Agent 和轮换的盐生成,不使用 cookie;官方在
data-distinct-id(v3.4.0)的说明里提到,办公室、学校、VPN 等共享网络下的访客可能有相同 IP 和浏览器。需要精确区分登录用户时,可以用 Distinct ID,但那是你主动发送的数据,官方说明责任在你。 - 默认会做遥测和版本检查。 如果你的服务器不想对外联网,用
DISABLE_TELEMETRY=1、DISABLE_UPDATES=1,要关闭所有外部请求用PRIVATE_MODE=1(网站图标会因此不显示)。这些变量要写进 Compose 的environment。 - 脚本可能被广告拦截器挡住。 官方提供
TRACKER_SCRIPT_NAME(自定义脚本名,默认是script.js)和COLLECT_API_ENDPOINT(自定义上报路径,默认/api/send)来减少被拦截的可能,具体做法见官方的 “Bypass ad blockers” 页面。 - 数据默认永久保留。 官方 FAQ 写明自托管数据除非手动删除,否则一直保留,要留意数据库体积和磁盘。
- 从旧版本升到 v3 之后查询变慢,先试
ANALYZE;。 见上面的更新一节。 - 不要把官方 Compose 里的
postgres:15-alpine随手改成别的大版本。 PostgreSQL 的数据目录不能跨大版本直接复用,换版本要走导出导入(通用经验,Umami 官方文档没有专门写)。
出处
- Umami 仓库 README(Docker 安装、源码安装、更新、MIT 许可证)
- Umami 仓库 LICENSE(MIT)
- 官方仓库 docker-compose.yml
- Umami v3.4.1 发布说明
- 官方文档:Introduction
- 官方文档:Installation
- 官方文档:Getting updates
- 官方文档:Environment variables
- 官方文档:Login(默认账号与改密码)
- 官方文档:Add a website
- 官方文档:Collect data(安装跟踪代码)
- 官方文档:Tracker configuration
- 官方文档:Two-factor authentication
- 官方文档:Enable Cloudflare headers
- 官方文档:Sessions
- 官方文档:FAQ
- 官方文档:Umami Cloud 与自托管对比
有想法或问题?去留言板留言 →