为什么我给网站换掉了 Google Analytics
运营个人博客的站长,几乎都装过 Google Analytics。它能告诉你访问量、来源、地域、停留时长,功能确实强大。但用久了,越来越多站长开始动摇:GA 的脚本几十到上百KB,在移动端会明显拖慢首屏;它在国内访问不稳定,经常导致页面卡在加载统计脚本上;更重要的是隐私合规的压力,欧洲需要 Cookie 同意横幅,国内也越来越多用户对"网站到底收集了我什么"敏感。对一个小型内容站来说,为了看几个访问数据而牺牲性能和隐私,性价比实在不高。
于是自建、轻量、注重隐私的统计工具开始流行。它们的共同特点是:脚本极小(多在1-2KB)、不使用 Cookie(用匿名指纹做去重)、数据存在自己的服务器上、不卖给任何第三方。主流选择有 Umami、Plausible、Matomo、GoAccess、还有新一些的 Ackee 和 Counterscale。这篇以 Umami 为主线,讲清楚个人站怎么搭一套完全自主可控的访问统计,同时把 GoAccess 作为最轻量的备选方案一起讲清。
先想清楚:你到底需要统计什么
选工具前别急着装,先问自己三个问题。第一,你要看的是宏观趋势还是微观明细?如果只想知道每天多少人访问、哪些页面最受欢迎、来源大致从哪来,那轻量方案足够,甚至一份 Nginx 日志加 GoAccess 就能满足。第二,你需不需要多站点、多用户、分享报表?如果同时运营好几个站,Umami 的多站点仪表盘会很省事。第三,你对实时性的要求有多高?Umami 和 Plausible 都有实时访客视图,GoAccess 需要自己配 WebSocket 或定时刷新。
把需求想清楚再动手,能省掉大量"装完发现不对"的返工。下面按"最轻量到功能最全"的顺序给三套方案。
方案一:GoAccess——零数据库、纯日志分析
如果你已经有一台跑着 Nginx 的服务器,GoAccess 是上手最快、资源占用最低的选项。它的原理非常朴素:直接解析 Nginx 的 access.log,在内存里聚合出报表,不写数据库、不注入任何前端脚本,对站点运行时性能的影响严格为零。
apt install -y goaccess
goaccess /var/log/nginx/access.log \
--log-format=COMBINED \
--date-format=%d/%b/%Y \
--time-format=%T \
--output=/var/www/report/index.html \
--real-time-html \
--ws-url=wss://report.example.com/ws关键点是把 Nginx 的日志格式和 GoAccess 的 --log-format 对上。如果你的 Nginx 用了自定义日志格式(比如加了 $request_time、$upstream_response_time、$http_user_agent),就要用 --log-format='%h %^[%d:%t %^] "%r" %s %b "%R" "%u" %T' 这样的自定义模板,字段顺序和数量必须和日志完全一致,否则报表会错位。
--real-time-html 配合 --ws-url 能让报表页面实时刷新,WebSocket 走独立端口,建议用 Nginx 反代并配一份自签或 Let's Encrypt 证书(浏览器对混合内容下的 wss 有强制要求)。GoAccess 报表是完全静态的 HTML,不需要 PHP,可以放在一个单独的只有自己能访问的路径下——这点非常重要,因为 access.log 里可能含有后台登录路径、接口参数,给公网看到等于泄露站点结构。
GoAccess 的局限也很明确:它只统计"请求",不懂"访客"。同一个用户刷新十次页面,日志里就是十条记录,它无法像 JS 统计那样区分独立访客、会话、跳出率。所以它适合看流量趋势、热门 URL、状态码分布、爬虫占比,不适合算用户行为指标。
方案二:Umami——轻量 JS 统计的主力方案
如果你要的是正经的访客统计——独立访客、会话数、停留时长、来源、设备、地域,又不想用 GA,Umami 是目前最省心的选择。它是 Node.js 写的,配 PostgreSQL 或 MySQL,官方提供 Docker 镜像,也在新版本里支持直接用 SQLite 单文件存储,对小站极其友好。
用 Docker Compose 启动最简单的 Umami:
version: '3'
services:
umami:
image: ghcr.io/umami-software/umami:postgresql-latest
ports:
- "3000:3000"
environment:
DATABASE_URL: postgresql://umami:umami@db:5432/umami
DATABASE_TYPE: postgresql
APP_SECRET: 换成你自己的随机长字符串
depends_on:
- db
restart: always
db:
image: postgres:15-alpine
environment:
POSTGRES_DB: umami
POSTGRES_USER: umami
POSTGRES_PASSWORD: 换成你自己的强密码
volumes:
- umami-db:/var/lib/postgresql/data
restart: always
volumes:
umami-db:APP_SECRET 一定要换成足够随机的字符串,它用于签名会话 token,用默认值等于把后台暴露给所有人。数据库密码同样别用示例值。启动后访问 http://服务器IP:3000,默认管理员是 admin / umami,第一件事就是改密码。
接下来是接入脚本。Umami 后台"设置 - 网站"里添加你的域名,会得到一个 data-website-id,把下面这段放进所有页面的 <head> 或 </body> 前:
<script async defer
data-website-id="你的-website-id"
src="https://stats.example.com/script.js"></script>注意 stats.example.com 要用你自己的域名反代到 Umami 的 3000 端口。为什么不直接用 IP:3000?两个原因:一是 HTTPS 问题,如果站点是 https,统计脚本也是 https 才不会被浏览器拦截;二是广告拦截器会按域名拦截统计脚本。把统计服务放在自己的子域名下,被拦截的概率会明显降低(虽然不能完全避免,uBlock 等仍会按脚本特征匹配)。
Nginx 反代 Umami 的正确配置
Umami 是单页应用加后端 API,反代时要把 API 和静态资源都转发过去,还要正确传递真实客户端 IP,否则统计到的全是 Nginx 自己或者 CDN 节点的 IP。
server {
listen 443 ssl http2;
server_name stats.example.com;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
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;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}关键在 X-Real-IP 和 X-Forwarded-For。Umami 会读取这些头来识别访客真实 IP,再由 IP 推断地域(它自己带地理库,不需要额外配置)。如果你的站前面还套了 CDN,那么 $remote_addr 拿到的是 CDN 节点 IP,需要改用 CDN 回源时带的真实 IP 头,比如 Cloudflare 的 CF-Connecting-IP:
proxy_set_header X-Real-IP $http_cf_connecting_ip;这一点如果不处理,你会发现统计后台里所有访客都来自同一个 IP,地域分布完全失真。这是自建统计最常见的"数据看起来有但全是错的"陷阱。
方案三:Matomo——要"完整 GA 替代"时选它
如果 Umami 的指标不够,比如你需要事件跟踪、目标转化、电商漏斗、自定义维度、热力图,那 Matomo(原 Piwik)是功能最接近 GA 的自托管方案。它是 PHP + MySQL,正好契合大多数站长已经熟悉的 LAMP/WLNMP 环境,直接丢进现有站点的一个子目录就能跑。
Matomo 的代价是"重":代码库庞大、后台功能繁多,对低配 VPS 有压力,而且它默认会写 Cookie(虽然有隐私模式可以关)。它的优势是生态成熟、插件多、文档全,国内社区也有大量教程。选它之前建议先在测试环境跑一周,观察内存和 CPU 占用,别直接上生产。
性能与隐私的取舍
自建统计最大的好处是"数据是我的、脚本是我控的"。但要用好,得注意两个层面。
性能层面,统计脚本一定要 async(Umami 脚本自带 async),绝不能阻塞渲染。更重要的是,统计服务最好不和你主站同一台机器——如果统计后台挂了或者数据库卡了,不该拖慢主站。个人站长资源有限时,至少把 Umami 的 Node 进程用 systemd 或 Docker 限制 CPU 和内存上限,避免它被爬虫高频请求打爆后连锁影响主站。
隐私层面,Umami 和 Plausible 默认不使用 Cookie、不采集个人身份信息(PII),只保存匿名指纹用于去重,并且支持把 IP 做匿名化处理。这对"不想搞 Cookie 横幅"的站长非常友好——因为不设 Cookie、不跟踪跨站,很多司法辖区下不需要同意横幅。但要注意,匿名化 ≠ 无合规义务,你的隐私政策里仍然应该如实说明"本站使用自建统计,采集匿名访问数据"。
一个真实的迁移复盘
我自己这个博客从 GA 迁到 Umami 的过程,最值得记录的不是安装,而是迁移后的一个反直觉发现。换掉 GA 后,Umami 报出的"独立访客"比 GA 少了将近 30%,最初我以为是配置错了,排查了半天才明白:GA 默认会把会话时长超过 30 分钟的访问重新计入会话来统计,而且 GA 的"用户"指标跨设备、跨会话的判定更宽松;Umami 的会话判定更严格,同 IP 同 UA 短时间内去重更彻底。换句话说,数字变小不代表流量变差,而是两个工具对"访客"的定义本就不同。迁移期最忌讳的就是把两套工具的绝对数字直接对比,正确做法是迁完后以新工具为基准,只看趋势的相对变化。
迁移后的实际收益也很明显:统计脚本从原来 GA 的约 45KB 降到 Umami 的约 2KB,移动端首屏的"Lighthouse 性能分"提高了 8 分;因为不再依赖境外域名的统计请求,页面完全加载时间在一些网络下缩短了数百毫秒。这些收益对一个内容站来说,比多看几个指标维度实在得多。下面是对比:
指标 GA4 Umami 自建
脚本体积 约 45KB 约 2KB
Cookie 需要 不需要
数据位置 境外 自己服务器
国内加载稳定性 偶发失败 稳定
独立访客口径 较宽 较严格(偏低约30%)
多站点支持 需要账号 后台直接切换落地建议
给个人站长一个简单的决策路径。如果只想看流量趋势和热门页面、又完全不想动数据库,直接上 GoAccess,二十分钟搞定。如果你要正经的访客统计、多站点、实时面板,选 Umami,Docker 一条命令起,注意 APP_SECRET 和真实 IP 传递这两个坑。如果你需要事件、目标、漏斗这类进阶分析,选 Matomo,但要先评估服务器性能够不够,别把小站拖慢。
无论选哪个,落地时都记住三条:统计服务用独立子域名并配 HTTPS;后台一定要设强密码和访问限制(可以用 Nginx 的 allow/deny 或 basic auth 再包一层);迁移期不要直接拿新工具的数字和旧工具对比。做到这三点,你就能拥有一个又快、又私密、又完全属于自己的访问统计系统。