自托管网站分析:小型 VPS 选哪种工具?
比较 Plausible、Umami、Matomo、GoatCounter 和 GoAccess:了解 1 GB 内存限制、Postgres 与 ClickHouse 选择、磁盘增长、反向代理配置及广告拦截器造成的数据缺口。
应在 VPS 上运行哪种自托管 Web 分析工具?
自托管 Web 分析工具分为两类。选错类别的代价通常高于选错产品。一类在访问者的浏览器中运行一段小脚本,并存储脚本上报的数据。另一类读取 Web 服务器已经写入的访问日志。数据库类型和所需内存等后续因素,都取决于这个选择。
小型服务器的简短结论如下。GoatCounter 和 Medama 只需 1 GB 内存即可运行,因为它们各自只有一个进程,并使用一个文件。Umami 需要一个 Postgres 容器,但提供了非技术人员也能看懂的仪表板。Plausible Community Edition 和 Rybbit 都运行 ClickHouse,因此应准备 2 GB 或更多内存。Matomo 功能完整,应根据流量为其配置相应规格的服务器。GoAccess 完全不会向页面添加内容,因为它读取的是已经存在的日志。
脚本标签与服务器日志:两者分别能看到什么
脚本标签用于统计浏览器。页面加载后,脚本运行,并向您的收集器发送一个请求。只要这条链路中的任何环节失败,您就无法看到相关数据:用户禁用了 JavaScript、过滤列表阻止了请求、向收集器发送请求失败,或者爬虫根本不运行脚本。
日志解析器用于统计请求。无论您是否安装其他组件,Web 服务器都会为每个请求写入一行日志,因此数据已经保存在磁盘上。它能看到每个爬虫,也能看到对不含脚本标签的文件发起的每次访问。但它无法看到浏览器内部发生了什么,也无法看到由浏览器缓存或您服务器前面的 CDN(内容分发网络)提供的页面,因为这类请求根本没有到达您的服务器。
这两个数字不会一致,但两者都没有错误。Matomo 同时支持这两种方式,并说明了与 JavaScript 跟踪器相比,日志导入会缺少哪些数据:屏幕分辨率和页面标题、事件、内容跟踪、热图、会话录制以及表单分析。使用请求而不是浏览器进行统计,就必须付出这些代价。
爬虫流量是造成差异的另一半原因。基于日志的统计会包含爬虫,除非您对其进行过滤;在普通网站上,爬虫占比通常足以改变您的结论。GoAccess 和 Matomo 的日志导入功能都会过滤已知爬虫。但两者都无法过滤伪造 user agent 的爬虫。因此,任何基于日志的统计都应配合在服务器上阻止 AI 爬虫,并在阻止后而不是阻止前读取日志。
GoAccess:基于现有日志进行分析
请从项目自己的 Debian 和 Ubuntu 软件源安装,因为发行版软件包的版本通常落后于最新发布版本。
wget -O - https://deb.goaccess.io/gnugpg.key | gpg --dearmor | sudo tee /usr/share/keyrings/goaccess.gpg >/dev/null
echo "deb [signed-by=/usr/share/keyrings/goaccess.gpg arch=$(dpkg --print-architecture)] https://deb.goaccess.io/ $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/goaccess.list
sudo apt-get update
sudo apt-get install goaccess然后将日志提供给它,并生成静态报告。
goaccess /var/log/nginx/access.log -o ~/report.html --log-format=COMBINED普通用户运行该命令会因 Permission denied 而失败,因为在 Ubuntu 上,nginx 日志归 root 所有,所属组为 adm。使用 sudo usermod -aG adm $USER 将自己加入该组,然后注销并重新登录,因为组成员资格会在登录时读取。运行 id,确认列表中出现 adm 后再重试。
针对当前日志生成的报告,只包含 logrotate 尚未移动的内容。昨天的请求位于 access.log.1 中,更早的日志已被压缩,因此周报还必须读取轮换后的文件。
zcat /var/log/nginx/access.log.*.gz | goaccess - --log-format=COMBINED -o ~/last-week.htmlGoAccess 还提供实时模式 --real-time-html,该模式通过 WebSocket 更新页面。这需要额外的端口和单独的代理规则。对大多数网站而言,由 cron 每小时生成一次报告就足够了,需要保护的内容也更少。
GoatCounter:一个 Go 二进制文件和一个 SQLite 文件
GoatCounter 以静态编译的二进制文件形式发布,因此无需安装运行时。可以从发布页面获取构建版本并运行,也可以使用镜像。
docker run -p 8080:8080 -v goatcounter-data:/home/goatcounter/goatcounter-data arp242/goatcounter以二进制文件运行时,goatcounter serve监听 8080 端口,并在 ./goatcounter-data/db.sqlite3 创建 SQLite 数据库。实例已位于代理之后时,应通过命令行创建第一个站点,而不是使用 Web 向导。
goatcounter db create site -vhost=stats.example.com -user.email=me@example.com它可以通过 goatcounter serve -listen=:443 -tls=tls,rdr,acme 管理自己的证书,并使用 ACME(自动证书管理环境)。这适用于只运行 GoatCounter 的服务器。如果 nginx 或 Caddy 已占用 443 端口,则让 GoatCounter 继续监听 8080 端口,并将代理请求转发给它。根据项目自身的数据,跟踪脚本大小约为 3.5K;对于不运行 JavaScript 的页面,还提供跟踪像素。如果繁忙站点达到 SQLite 的性能上限,同一个二进制文件也可通过 goatcounter serve -db 'postgresql+dbname=goatcounter' 使用 Postgres。备份只需复制文件,这正是这类工具的实际优势。
Medama:单个声明占用 256 MB 的容器
Medama 是这里介绍的最新单二进制方案。它从设计上不使用 Cookie,项目声明其跟踪器小于 1 KB,并称在内存为 256 MB 的虚拟机上也能运行小型网站。这些是项目公布的声明,不是本指南实测的数据。
docker volume create medama-data
docker run -d -p 127.0.0.1:8080:8080 -v medama-data:/app/data ghcr.io/medama-io/medama:latest官方命令将端口发布为 8080:8080。上面的 loopback 前缀是有意设置的,反向代理一节会解释原因。首次登录使用 admin,密码为 CHANGE_ME_ON_FIRST_LOGIN;该密码的名称就是操作提示。
有一种已记录的故障模式需要特别注意。登录仅可通过 HTTPS 或在 localhost 上进行。因此,如果在证书配置完成前先设置反向代理,表单会拒绝正确的密码,且不会显示原因。先完成 TLS(传输层安全)设置,再登录。
Umami:Postgres,以及用户熟悉的仪表板
git clone https://github.com/umami-software/umami.git
cd umami
docker compose up -d该命令会在 3000 端口启动应用,并同时运行一个 PostgreSQL 容器。文档将 PostgreSQL v12.14 列为最低版本;如果改为从源代码构建,则需要 Node.js 18.18 或更高版本。Umami 提供预构建镜像 docker.umami.is/umami-software/umami:postgresql-latest,但需要将 DATABASE_URL 指向已运行的数据库。
首次登录使用 admin,密码为 umami。在将 DNS 指向此服务器前修改该密码,因为 DNS 记录解析且代理开始响应后,此实例就会立即暴露在互联网中。有关 Compose 配置、环境文件和 restart policy,请参阅 VPS 上的 Docker Compose 堆栈,不要直接复制未经阅读的堆栈配置。
该服务由一个 Node 进程和 Postgres 组成。它比单个二进制程序更占用资源,但比任何运行 ClickHouse 的方案轻量得多。
Plausible Community Edition:ClickHouse 决定最低内存要求
git clone -b v3.2.1 --single-branch https://github.com/plausible/community-edition plausible-ce
cd plausible-ce
touch .env
echo "BASE_URL=https://stats.example.com" >> .env
echo "SECRET_KEY_BASE=$(openssl rand -base64 48)" >> .env
docker compose up -d截至 2026 年 8 月,当前版本为 v3.2.1。克隆命令会固定使用该版本,这是有意为之的。此堆栈由三部分组成:应用、用于存储账户和设置的 Postgres,以及用于存储事件数据的 ClickHouse。SECRET_KEY_BASE 必须至少是一个 64 字节的字符串,openssl 调用会生成符合要求的字符串。
Plausible 官方要求至少 2 GB RAM,以避免 ClickHouse 和应用触发 out of memory killer;同时还要求 CPU 支持 SSE 4.2 或 NEON,这是 ClickHouse 的运行要求。在购买 VPS 前,应先检查第二项要求。这也是选择 ARM 还是 x86 VPS时需要考虑的实际差异之一。ClickHouse 还会使用它认为可用的全部内存,因此在共享服务器上,应按照在 Compose 中限制容器内存中的说明设置上限。
BASE_URL 必须与公网 URL 完全一致。如果不一致,您登录后,应用会将请求重定向到错误的主机;会话 Cookie 也会写入当前浏览器未访问的域名,因此页面会返回登录表单,且不会显示错误消息。
随附的 compose 文件不会发布端口,因为预期是在前面配置代理。请添加一个 override,仅通过 loopback 发布默认应用端口。
cat > compose.override.yml << EOF
services:
plausible:
ports:
- 127.0.0.1:8000:8000
EOFMatomo:完整产品及其所需的服务器
Matomo 基于 PHP,并使用 MySQL 或 MariaDB,因此它属于经典 Web 技术栈,而不是容器技术栈。它也是这里唯一一个按流量发布硬件建议的工具。
The data behind this chart
[
{
"label": "100K/month",
"cpu_cores": 2,
"ram_gb": 2,
"disk_gb": 50
},
{
"label": "1M/month",
"cpu_cores": 4,
"ram_gb": 8,
"disk_gb": 250
},
{
"label": "10M/month",
"cpu_cores": 8,
"ram_gb": 16,
"disk_gb": 400
}
]这些是 Matomo 截至 August 2026 发布的最低配置要求,并非本指南测得的数据。每月页面浏览量不超过 100,000 时,需要 2 个 CPU 核心、2 GB RAM 和 50 GB SSD,应用和数据库可运行在同一台服务器上。在 1M/month 时,需要 8 GB RAM 和 250 GB 磁盘空间。在 10M/month 时,Matomo 建议使用两台服务器;最后一行显示的是数据库服务器配置:16 GB RAM 和 400 GB 磁盘空间。请将这些磁盘空间数据与单二进制文件方案对照查看,因为后者的整个数据集都存储在一个 SQLite 文件中。
归档机制通常最容易被忽略。默认情况下,Matomo 会在用户打开控制面板时生成报告。因此,随着数据增长,控制面板会越来越慢,最终可能超时。文档建议的解决方法是,在常规设置中关闭由浏览器触发的归档,改为通过 cron 运行归档程序,并使用 Matomo 文件所有者账号,从 Matomo 目录执行。
php console core:archive --url=https://analytics.example.comMatomo 还会在已处理的报告表旁保留原始日志表,并可以按计划删除旧的原始数据和旧报告。应在安装时启用此功能,而不是等磁盘空间耗尽后再启用。Matomo 还可以导入服务器访问日志,因此它是这里唯一一个同时覆盖这两类数据的产品。
Rybbit 和较新的技术栈
git clone https://github.com/rybbit-io/rybbit.git
cd rybbit
chmod +x *.sh
./setup.sh your.domain.nameRybbit 是较新的项目,提供现代化的仪表板。安装脚本会写入环境文件,并使用 Docker Compose 启动整个技术栈。它运行 ClickHouse,并自带 Caddy 作为 Web 服务器。Caddy 会占用 443 端口,并为您传入的域名申请证书。如果服务器上的 nginx 已占用 443 端口,脚本将无法绑定该端口。此时应使用项目提供的手动 Compose 部署方式,并将其置于现有反向代理之后。文档要求至少 2 GB RAM,并说明已在 Ubuntu 24 LTS 上进行测试。由于 ClickHouse 的要求,ARM 平台需要使用 ARMv8.2-A 或更高版本。
对于任何较新的项目,都应注意一个实际问题:功能更新很快,破坏性变更也可能随之出现。请固定版本标签,拉取更新前先阅读发行说明,并先备份数据库。
保留期限和磁盘增长:在自己的服务器上测量
磁盘增长取决于工具为每个事件存储的内容。GoatCounter 将访问聚合为计数器,因此其文件增长更多取决于不同页面和天数,而不是原始访问量。Umami 和 Matomo 按事件存储数据行,Matomo 还会在原始数据之上存储处理后的报表表。ClickHouse 按列存储事件,并进行高强度压缩,因此 Plausible 可以应对会让行式存储承受压力的访问量。
本指南不提供每百万次页面浏览对应的 MB 数值,因为没有在您的流量上进行测量。请自行读取数据。根据您自己的 Compose 文件调整服务名和用户名。
du -h goatcounter-data/db.sqlite3
docker compose exec db psql -U umami -d umami -c "SELECT pg_size_pretty(pg_database_size('umami'));"
docker compose exec plausible_events_db clickhouse-client -q "SELECT formatReadableSize(sum(bytes_on_disk)) FROM system.parts WHERE active"记录数值,等待一周后再次记录,然后用两次读数的差值除以仪表板报告的该周页面浏览量。这个数值反映了您的网站和机器人过滤规则,因此比任何公开的平均值都更有参考价值。趁数值还较小时设置保留期限。磁盘已满会导致 VPS 上的所有服务停止运行,而不只是分析服务;这正是应将数据库卷放在 df -h 会提醒您的位置的最有力理由。如果服务器上已经存放了体积较大的内容,就更应重视这一风险,因为自托管照片服务器早在任何分析数据库接近磁盘上限之前,就可能耗尽磁盘空间。
反向代理在子域名后面的工作方式
将收集器部署在被测站点的子域名下,例如 stats.example.com。这样,收集器请求会被视为第一方请求,不会受到浏览器拦截第三方请求的规则影响。
发布容器端口时,应将应用绑定到回环地址。Docker 会在 ufw 之前写入自己的防火墙规则,因此即使 ufw status 显示端口被拒绝,发布为 -p 3000:3000 的容器仍可从互联网访问。使用 curl http://SERVER_IP:3000 从另一台机器进行测试时,您会看到仪表板。发布为 -p 127.0.0.1:3000:3000 时,同样的测试会返回 Connection refused,只有代理可以访问它。这种做法不仅能隐藏仪表板,也是在同一台主机上运行 onion 服务的核心:任何仍在公网接口上响应的服务,都会将隐藏地址与您的 IP 关联起来。采集器端点必须保持可从开放互联网访问,但仪表板不需要;如果您希望通过私有网络读取它,而不是发布第二个子域名,则可通过使用子网路由器将 VPS 网络通告到 tailnet实现,无需开放端口。
server {
listen 443 ssl;
server_name stats.example.com;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}这里的转发标头不是可选项。没有 X-Forwarded-For 时,每次访问都会显示为来自 127.0.0.1,因此国家/地区报告为空,唯一访客数也会趋近于 1。每个项目都会决定信任哪个标头,以及在哪个设置下信任,因此请查看其代理文档,不要自行假设。Caddy 会自动设置这些标头;使用 Caddyfile 完成相同配置只需两行。
stats.example.com {
reverse_proxy 127.0.0.1:3000
}如果您还没有选择代理,nginx、Caddy 和 Traefik 的比较介绍了哪一种适合只有一台主机和几个子域名的场景。
自行托管后,仍需要 Cookie 横幅吗?
自行托管会改变数据由谁持有,但不会改变法律对这些数据的规定。请区分两项规则。ePrivacy 的同意规则针对在访问者设备上存储或读取任何内容。因此,不设置 Cookie 且不写入本地存储的工具,不受这一项具体要求约束。GDPR 针对个人数据处理,而 IP 地址属于个人数据。因此,您仍需要合法依据、保留期限,以及在他人询问您持有哪些关于其数据时作出答复。
Plausible、Umami、GoatCounter 和 Medama 默认不设置 Cookie。但各项目具体推导哪些数据有所不同,且会随版本变化,因此应阅读项目自身的隐私文档,不要只参考概述。Matomo 提供 IP 匿名化功能,以及可在管理界面中启用的退出跟踪端点。
不同国家的监管机构可能得出不同结论。例如,法国 CNIL 会发布受众测量可免于征得同意的适用条件。本节仅作事实性概述,不构成法律建议。对于面向真实用户的实际网站,请咨询您所在司法辖区的律师。
还有一点经常被忽略:访问日志同样属于个人数据。GoAccess 不会向页面添加脚本,但仍会处理 IP 地址,因此基于日志的分析并不会自动排除在相关规定之外。将服务迁移到您自己的服务器,只是转移了暴露面,并未消除暴露面。这也是 自行托管的 SearXNG 实例实际隐藏了什么 只涉及搜索引擎,而查询本身仍会写入您自己的日志的原因。
广告拦截器,以及为什么你的数据会下降
过滤列表会匹配主机名和 URL 模式。托管式分析产品很容易被匹配,因为所有用户都会从同一个知名主机名加载它。将收集器移到自己的子域名后,请求中就不再包含该主机名;从自定义路径提供脚本后,请求中也不再包含那个知名文件名。这两项改动都会改变过滤列表需要匹配的内容。
本文不声称某个拦截率,因为没有进行相关测量。会拦截某种配置的访问者比例取决于受众;开发者受众的拦截比例通常远高于普通受众。请改为测量自己站点的差值。在同一周内,使用 GoAccess 统计访问日志中对 HTML 页面的请求数,再将其与基于脚本的工具报告的 pageview 数进行比较。两者的差值就是本站被拦截的访问,以及由缓存直接提供的页面数量。
从托管产品切换的当天,预计总数会发生变化;同时也要注意,其中一部分变化与拦截无关。不同产品对 pageview 的定义不同:在单页应用中,单个页面内的路由变化是否算作一次 pageview,以及会话何时结束,都可能存在差异。在确认流量下降前,请先比较多周的趋势。
哪个工具适合哪个网站
- 每月页面浏览量大约不超过 50,000 的个人网站或博客:使用 GoatCounter 或 Medama,部署在 1 GB VPS 上,并通过文件复制备份。
- 无法添加脚本的网站,或访问者经常阻止脚本的网站:按计划对现有日志运行 GoAccess。
- 需要由其他人查看仪表板的小型企业网站:使用 Umami 及其 Postgres 容器。
- 需要目标和漏斗分析,且服务器内存为 2 GB 或更多的网站:使用 Plausible Community Edition;如果希望使用更新的仪表板,并能接受项目相对较新,也可以使用 Rybbit。
- 拥有多个网站、多个用户账户,或要求按照自定义保留策略保存原始数据:使用 Matomo,并根据上文发布的指导进行资源配置。
从能够回答实际问题的最小工具开始。以后从 GoatCounter 迁移到 Plausible,代价是新增一个子域名,并处理部分历史数据。以后从 Matomo 迁移到其他工具,则需要执行一次你不会想做的迁移。如果你还在决定同一台服务器上适合部署哪些其他服务,请参阅更全面的自托管服务汇总,其中介绍了适合与之搭配的服务。如果你真正需要的是应用的请求级跟踪,而不是访客数量统计,则应改用自托管可观测性服务。
FAQ
自托管分析后,还需要显示 Cookie 横幅吗?
需要,这两个问题彼此独立。ePrivacy 下的同意规则适用于在访客设备上存储或读取数据,因此不设置 Cookie、也不写入 local storage 的工具,不受该项具体要求约束。GDPR 是另一项规则,适用于个人数据处理;IP 地址属于个人数据。因此,即使不使用 Cookie,您仍需要具备合法处理依据,并设置数据保留期限。自托管会将数据转移到您的服务器上,也使您成为负责处理这些数据的一方。请查阅所在地区监管机构的指南,并针对具体情况咨询律师。
VPS 上的自托管分析需要多少 RAM?
决定资源需求的是数据存储,而不是控制面板。GoatCounter 和 Medama 都以单个进程处理一个文件运行;Medama 文档称,小型网站可运行在 256 MB 的机器上。Umami 会在 Node 应用旁运行一个 Postgres 容器。Plausible Community Edition 和 Rybbit 都运行 ClickHouse,两个项目都声明至少需要 2 GB。Matomo 的官方指南建议,月访问量不超过 100,000 次页面浏览时,起步配置为 2 个 CPU 核心和 2 GB RAM。
为什么我的自托管数据低于之前使用的分析工具?
有两个原因,而且都确实存在。过滤列表会阻止部分采集请求,因此所有基于脚本的工具都会漏掉这些访问。不同产品的统计方式也不同,因为页面浏览的定义和会话结束的时机并不一致。将访问日志中一周的 HTML 页面请求数,与同一周基于脚本统计的页面浏览数进行比较。差值就是被阻止的访问和缓存页面访问;这是根据您自己的网站测量得出的结果,而不是套用他人公布的比例。
我可以在 ARM VPS 上运行 Plausible 或 Rybbit 吗?
两者都运行 ClickHouse,而 ClickHouse 在 x86 上需要 SSE 4.2,在 ARM 上需要 NEON。Plausible 的要求明确说明了这一点,Rybbit 文档则称 ARM 系统需要 ARMv8.2-A 或更高版本。当前的 ARM 服务器核心满足这一要求,较旧的核心则不满足。此时 ClickHouse 会因指令集错误而拒绝启动,错误不会以应用日志中的普通应用错误形式出现。在小型 ARM 主机上,单文件工具可以避开这个问题,因为它们都不运行 ClickHouse。
我应该解析服务器日志,而不是使用跟踪脚本吗?
无法添加脚本、受众群体经常拦截脚本,或需要统计包含爬虫在内的访问量时,可以使用日志解析。GoAccess 读取服务器已经写入的日志,因此不会增加页面体积,也不需要数据库。但这种方式无法统计浏览器内部发生的行为;如果页面由 CDN 或浏览器缓存提供,相关请求不会到达您的服务器,日志解析也无法统计。许多网站会同时运行两种方式,并将它们视为两项不同的测量结果。