不想把网站访问数据交给 Google Analytics,又需要来源渠道、页面转化、事件和电商分析,Matomo 是目前最成熟的自托管方案之一。数据可以留在自己的 VPS 和数据库中,也不会因为第三方统计服务被广告拦截或地区网络影响而完全失去可见性。
但 Matomo 不是启动一个容器就结束。数据库持久化、反向代理、可信域名、后台归档、隐私设置和可恢复备份,少做一项都可能在流量上来后暴露问题。
这篇教程使用官方 matomo:5-apache 镜像和 MariaDB 11.4,通过 Docker Compose 部署,Caddy 负责 HTTPS。Matomo 只监听 VPS 的 127.0.0.1:8080,数据库不开放公网端口,并配置每小时执行的 CLI 归档任务。
这三类工具解决的问题不完全相同。
| 需求 | 更适合的工具 | 主要取舍 |
|---|---|---|
| 需要渠道、目标、事件、电商和详细访客分析 | Matomo | 功能完整,但数据库和归档维护成本更高 |
| 只看页面、来源、设备等轻量指标 | Umami | 界面简单、资源占用更低,深度分析能力较少 |
| 不想运维,接受数据由第三方处理 | Google Analytics | 接入方便,但隐私、数据控制和广告拦截需要单独评估 |
| 合规要求数据保留在自己的基础设施 | Matomo On-Premise | 数据控制更强,但“自托管”不等于自动合规 |
如果只想知道每天多少访客、哪些页面最热门,可以先看VPS 自建 Umami 网站统计。需要目标转化、站内搜索、下载追踪、用户流或更细的数据保留策略,再部署 Matomo 更划算。
Matomo 官方对每月不超过 10 万次页面浏览的单机安装,给出的最低建议是 2 核 CPU、2GB 内存和 50GB SSD。Docker 里还要运行 MariaDB,因此实际购买时建议给内存留余量。
| 月页面浏览量 | 建议配置 | 说明 |
|---|---|---|
| 10 万以内 | 2 核 4GB、50GB SSD | 小型博客、企业站,单机部署最省事 |
| 10 万至 100 万 | 4 核 8GB、200GB SSD 起 | 必须配置 CLI 归档,并持续观察数据库增长 |
| 100 万以上 | 单独压测和规划 | 数据库、归档进程和对象存储可能需要拆分 |
磁盘增长取决于访问量、事件数量、日志保留周期和是否保存原始访问数据,不能只按站点文件大小估算。系统以 Ubuntu 24.04 LTS 为例,提前把 analytics.example.com 的 A / AAAA 记录指向 VPS,只开放 SSH、80 和 443。
按照 Docker 官方仓库安装 Docker Engine 与 Compose 插件,然后确认使用 Compose v2:
docker --version
docker compose version
创建部署和备份目录:
sudo mkdir -p /opt/matomo/backups
sudo chown -R "$USER":"$USER" /opt/matomo
cd /opt/matomo
如果这台 VPS 还运行其他容器,建议先对照VPS Docker Compose 生产环境配置清单,统一日志轮转、健康检查和升级策略。
应用数据库账号和 root 密码必须不同:
openssl rand -hex 32
openssl rand -hex 32
nano .env
chmod 600 .env
把两组随机值写入 /opt/matomo/.env:
MARIADB_ROOT_PASSWORD=替换成第一组随机值
MATOMO_DATABASE_PASSWORD=替换成第二组随机值
不要把 .env 提交到 Git,也不要在 Compose 文件中写明文密码。
创建 /opt/matomo/compose.yaml:
services:
db:
image: mariadb:11.4
container_name: matomo-db
restart: unless-stopped
environment:
MARIADB_ROOT_PASSWORD: "${MARIADB_ROOT_PASSWORD:?set MARIADB_ROOT_PASSWORD in .env}"
MARIADB_DATABASE: matomo
MARIADB_USER: matomo
MARIADB_PASSWORD: "${MATOMO_DATABASE_PASSWORD:?set MATOMO_DATABASE_PASSWORD in .env}"
command:
- --max-allowed-packet=64M
- --innodb-buffer-pool-size=512M
volumes:
- matomo_db:/var/lib/mysql
healthcheck:
test:
- CMD-SHELL
- >-
mariadb-admin ping -h 127.0.0.1 -uroot
-p$$MARIADB_ROOT_PASSWORD --silent
interval: 10s
timeout: 5s
retries: 20
start_period: 30s
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
app:
image: matomo:5-apache
container_name: matomo
restart: unless-stopped
depends_on:
db:
condition: service_healthy
ports:
- "127.0.0.1:8080:80"
environment:
MATOMO_DATABASE_HOST: db
MATOMO_DATABASE_ADAPTER: mysql
MATOMO_DATABASE_TABLES_PREFIX: matomo_
MATOMO_DATABASE_USERNAME: matomo
MATOMO_DATABASE_PASSWORD: "${MATOMO_DATABASE_PASSWORD:?set MATOMO_DATABASE_PASSWORD in .env}"
MATOMO_DATABASE_DBNAME: matomo
PHP_MEMORY_LIMIT: 512M
volumes:
- matomo_data:/var/www/html
healthcheck:
test:
- CMD-SHELL
- >-
php -r '$$c=@fsockopen("127.0.0.1",80,$$e,$$s,5);
exit($$c ? 0 : 1);'
interval: 30s
timeout: 10s
retries: 10
start_period: 60s
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
volumes:
matomo_db:
name: matomo_db
matomo_data:
name: matomo_data
matomo:5-apache 会跟进 Matomo 5 的补丁和小版本,不会因为一次重建直接跨到下个大版本。mariadb:11.4 固定在 11.4 系列,避免生产环境使用会漂移的大标签。2GB 内存机器可以先把 --innodb-buffer-pool-size 改成 256M;不要让数据库缓存挤掉系统和 PHP 所需内存。
启动前让 Compose 展开变量并检查 YAML:
docker compose config >/dev/null
docker compose pull
docker compose up -d
docker compose ps
docker compose logs --tail=100 app
首次初始化会创建数据库和 Matomo 文件。两个服务都显示 healthy 后,再检查本机入口:
curl -I http://127.0.0.1:8080
sudo ss -lntp | grep ':8080'
监听地址必须是 127.0.0.1:8080,不能是 0.0.0.0:8080。MariaDB 没有 ports 配置,公网也不应该看到 3306。
编辑 /etc/caddy/Caddyfile:
analytics.example.com {
encode zstd gzip
reverse_proxy 127.0.0.1:8080
request_body {
max_size 64MB
}
}
检查并加载配置:
sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddy
curl -I https://analytics.example.com
Caddy 会传递 X-Forwarded-For、X-Forwarded-Host 和 X-Forwarded-Proto。Matomo 位于 HTTPS 反向代理后时,还要在安装完成后检查 config/config.ini.php 的 [General] 配置:
[General]
assume_secure_protocol = 1
force_ssl = 1
proxy_ip_read_last_in_list = 0
trusted_hosts[] = "analytics.example.com"
trusted_hosts 是 Matomo 默认启用的主机名保护,不要为了消除警告直接关闭。修改后执行:
docker compose exec app php console config:get General
docker compose exec app php console cache:clear
不熟悉 Caddy 的证书、DNS 和多域名配置,可以参考VPS 用 Caddy 反向代理完全指南。
浏览器打开 https://analytics.example.com。数据库页面填写:
| 字段 | 值 |
|---|---|
| 数据库服务器 | db |
| 登录名 | matomo |
| 密码 | .env 中的 MATOMO_DATABASE_PASSWORD |
| 数据库名 | matomo |
| 表前缀 | matomo_ |
不要填 localhost 或 127.0.0.1,那会指向 Matomo 容器自身,而不是 Compose 网络中的 MariaDB。
向导随后会创建管理员、添加第一个网站并生成 JavaScript 追踪代码。把追踪代码放在网站所有页面的 </head> 前;WordPress、Shopify 或常见 CMS 则优先使用维护中的官方或社区插件,避免主题更新后代码丢失。
安装完成后验证:
docker compose exec app php console diagnostics:run
docker compose exec app php console core:archive --url=https://analytics.example.com
docker compose logs --tail=100 app
再用无痕窗口访问网站,在 Matomo 的“实时访客”里确认出现测试访问。只看到页面正常打开,并不能证明追踪请求和归档任务都工作。
Matomo 会把原始访问数据聚合成报表。小站可以由浏览器请求触发归档,但官方建议访问量超过每天 500 次页面浏览或服务器响应变慢时,改用 CLI 定时归档。生产环境直接配置 Cron,更可预测。
先手动执行一次并确认没有错误:
cd /opt/matomo
docker compose exec -T app php /var/www/html/console core:archive \
--url=https://analytics.example.com
确认 Docker 的绝对路径:
command -v docker
然后编辑 root 的 Cron:
sudo crontab -e
添加一行;如果上一步不是 /usr/bin/docker,替换成实际路径:
5 * * * * cd /opt/matomo && /usr/bin/docker compose exec -T app php /var/www/html/console core:archive --url=https://analytics.example.com >> /var/log/matomo-archive.log 2>&1
CLI 归档稳定运行后关闭浏览器触发归档:
docker compose exec app php console config:set General enable_browser_archiving = 0
docker compose exec app php console config:get General enable_browser_archiving
定期检查日志,避免 Cron 因路径、证书或数据库问题连续失败:
sudo tail -n 100 /var/log/matomo-archive.log
自托管只代表你控制基础设施,不代表网站自动满足 GDPR、CCPA 或本地隐私法规。至少在“管理 → 隐私”检查这些项目:
- IP 地址匿名化建议掩码 2 或 3 个字节,并在首次收集真实流量前启用;
- 设置原始访问日志和历史报表的保留周期,别无限保存没有业务价值的数据;
- 不需要跨会话识别用户时,使用无 Cookie 追踪,并验证统计准确度变化;
- 启用用户退出统计的机制,并在隐私政策中说明收集目的和保存期限;
- 不把邮箱、姓名、订单备注等个人信息塞进 URL、页面标题或自定义维度;
- 根据所在地区、追踪方式和用途判断是否需要同意管理平台,不要把“Matomo”当成免 Cookie 横幅的万能结论。
Matomo 默认提供 IP 匿名化能力,但最终配置和法律依据仍由站点运营者负责。调整前先让法务或隐私负责人确认业务需要。
完整备份至少包括 MariaDB 和 matomo_data 卷。数据库保存站点、访问和报表数据,数据卷中则有 config/config.ini.php、插件和应用文件。
创建数据库备份:
cd /opt/matomo
mkdir -p backups
docker compose exec -T db sh -c \
'mariadb-dump --single-transaction --quick --routines --triggers \
--databases "$MARIADB_DATABASE" -uroot -p"$MARIADB_ROOT_PASSWORD"' \
| gzip > "backups/matomo-db-$(date +%F-%H%M).sql.gz"
备份 Matomo 数据卷:
docker run --rm \
-v matomo_data:/source:ro \
-v "$PWD/backups:/backup" \
alpine sh -c 'tar -C /source -czf /backup/matomo-data.tar.gz .'
备份文件不能只放在同一台 VPS。把它加密同步到对象存储或另一台机器,并定期做恢复演练。可以直接沿用VPS 备份恢复演练教程中的异地备份与校验流程。
恢复时先停止 Matomo 写入,恢复数据卷,再把 SQL 导回新的 MariaDB,最后启动服务并运行:
docker compose exec app php console core:update
docker compose exec app php console diagnostics:run
docker compose exec app php console core:archive --url=https://analytics.example.com
恢复验收要同时检查管理员登录、历史报表、实时访问、追踪脚本和 Cron 归档,不能只确认首页能打开。
Matomo 处理访客数据和管理员账号,安全更新不要长期拖延。升级前先阅读 Matomo 发布说明和镜像变更,再执行:
cd /opt/matomo
docker compose config >/dev/null
# 先完成并验证数据库、matomo_data 两类备份
docker compose pull
docker compose up -d
docker compose exec app php console core:update
docker compose exec app php console diagnostics:run
docker compose ps
升级后至少验证:
- HTTPS 首页和管理后台可访问;
- 新的实时访问能够进入 Matomo;
- 历史报表没有消失;
core:archive手动运行成功;- Caddy、Matomo 和 MariaDB 日志没有持续报错。
不要用 latest 标签跨大版本自动升级,也不要只备份 Compose 文件。真正不可替代的是数据库、配置和你安装的插件。
先检查数据库是否 healthy:
docker compose ps
docker compose logs --tail=200 db
docker compose exec app getent hosts db
安装向导中的主机名必须是 db,账号、密码和数据库名要与 Compose 完全一致。修改已初始化数据库的 .env 不会自动重置数据库账号。
确认访问入口只有 https://analytics.example.com,Caddy 正确传递转发头,并设置 assume_secure_protocol 与 force_ssl。不要同时让 CDN、Caddy 和 Matomo 各做一套互相冲突的 HTTP 跳转。
手动运行 core:archive,检查 /var/log/matomo-archive.log。访问量增长后,优先确认归档是否正常、磁盘是否足够、MariaDB 是否出现慢查询,再考虑盲目加 CPU。
确认 Caddy 的 X-Forwarded-For,并按照实际代理链配置 proxy_client_headers、proxy_host_headers 和 proxy_ip_read_last_in_list。如果前面还有 Cloudflare,必须只信任明确的代理来源,不能把任意客户端提交的头当成真实 IP。
在浏览器开发者工具的 Network 中搜索 matomo.php,确认请求不是 404、403 或被内容安全策略拦截。再检查网站 ID、Matomo 地址、广告拦截器和“排除自己的访问”设置。
- Matomo 只监听
127.0.0.1:8080,MariaDB 不映射公网端口 - 域名、HTTPS、可信主机和反向代理配置一致
- 管理员使用强密码,并启用可用的双因素认证
- 测试访问能出现在实时访客中
- 每小时 CLI 归档成功,日志可观察
- IP 匿名化、Cookie、数据保留和退出统计策略已确认
- 数据库与
matomo_data都有异地备份 - 已完成一次恢复演练,并记录恢复时间
- 升级前有备份,升级后验证追踪和归档
完成这些步骤后,这套 Matomo 才不只是“页面能打开”,而是具备 HTTPS、持久化、隐私控制、自动归档和可恢复能力的生产环境。对于真正重视一方数据和网站转化的团队,这些运维成本就是换取数据控制权的价格。
