人人都知道的默认密码
这些工具里有一款,在全世界每一次安装时都使用同一套默认管理员凭据;其他几款则是谁先注册谁就拥有所有权。主机名一旦 TLS 生效,就会立刻被发布到证书透明度日志里。登录、修改凭据、关闭注册——都要在最初五分钟内完成,不要等到明天。

分析工具是大多数人留到最后才移除的第三方标签,也是唯一一个能看到全部信息的标签:每一页、每一位读者、每一个小时,全都运行在一个你既不拥有也无法审计的系统上。六个步骤,把它换成一台你自己的计数器——Umami、Plausible Community Edition、Matomo,或者仅凭服务器日志——运行在无需身份证件即可租用的北欧机器上。默认无 Cookie,无需为横幅争论,读者数据也不会转移到第三国。每月低至 $3.90。已在 Debian 12 上测试。
选择
四款工具,一张诚实的表
配置
一个子域名,三个端口
部署
Compose、Caddy 与首次登录
埋点
一个标签,以及第一方路径
合规
两条法律,不是一条
Keep
保留期限、备份,以及被遗忘的日志
统计访客确实有用,想要这么做也没有任何不良动机。你需要知道这次改版到底有没有效果,哪篇文章读者真正看完了,哪个来源带来的是真正的读者而不是秒跳的访客,昨晚的部署有没有在某个浏览器上悄悄弄坏了结算流程。这些问题每一个都能在一张页面浏览量表里找到答案,而每一个也都是进行统计的正当理由。
真正值得正视的,是几乎所有人为了得到这些答案而接受的那套安排。标准的分析标签是一段由一家广告公司编写的代码,你把它放在网站的每一页上,让它在你读者的浏览器里运行。它读取页面地址、来源、屏幕、语言、设备信息;它在设备上设置或读取一个标识符;它把这一切都发送到一个你无法检查的系统里,发到一个你并未选择其规则的国家;然后把生成的那份档案交给一家靠了解人们的行为来赚钱的公司。站点主人得到的是一个仪表盘。而仪表盘只是这笔交易里较小的那一半。
账单分四次到来,而其中只有一次是显而易见的。首先是同意横幅,它几乎完全是因为这一个标签才存在,它在门口就让你损失一部分可以量化的访客,而你随后还要另外付钱给第二家厂商来管理它。其次是传输问题,因为你读者的数据被发送到了第三国,最终总得有人写清楚这为什么是合法的。再有数据本身,也就是你的读者,被存放在一个你无法直接查询、只能通过对方提供的报表来查看的数据库里。最后是依赖性:这款产品会在别人的时间表上被下架、改名或重组,而上一次发生这种事的时候,旧的统计数据也随之一并消失。
自建能一次性去掉这四项问题,而且工作量并不大。软件本身成熟、免费又平淡无奇;机器每月只要几美元;工作量是一个晚上。你换回来的是一张你自己拥有的表,跑在你自己选定司法辖区里的硬件上,没有第三方需要披露,而且——对大多数配置来说——也没有横幅需要争论。四种了解有多少人读过你网站的方法,以及每一种各自的代价:
| 属性 | 那个免费的大型分析标签 | 一款隐私优先的分析型 SaaS | 同样的软件,你自己的 VPS |
|---|---|---|---|
| 谁掌握着读者数据表 | 一家广告公司 | 一家签约供应商 | 你自己,就在磁盘上 |
| 需要同意横幅 | 是的,实际上总是如此 | 通常不会 | 通常不会——参见步骤 05 |
| 数据流出 EEA | 是的,这是设计上的考虑 | 取决于供应商 | 只有选择境外机器才会 |
| 需要披露的第三方 | 至少一个,外加其次级处理者 | 一个处理者 | 无 |
| 被过滤名单拦截 | 重度依赖 | 通常按主机名区分 | 一旦成为第一方,就很少发生 |
| 你可获取的原始数据 | 不会——只生成报表 | 通过 API,且需要付费 | 是你自己的数据库 |
| 100k 次浏览量对应的月成本 | 金钱成本为零 | 几十美元,随流量增长 | $3.90–$7.90,固定价格 |
| 适合选择它的情形 | 你需要广告平台集成,并接受其余的一切 | 你想要合乎伦理,却不想自己运维任何东西 | 读者是你的,这张表也是你的 |
第三栏是一个真实的答案,不是一个用来反驳的稻草人:对于那些本就不该自己运维服务器的人来说,一家托管型、隐私优先的厂商能消除大部分同样的问题,付费用这样的服务,也好过继续留着那个广告标签。本指南针对的情形,是你已经租了一台机器,或者本来就打算租一台。
这四款工具并不是同一样东西的四种口味。它们的区别在于把数据存放在什么里面,而正是这一个选择,决定了内存占用、磁盘增长速度、升级风险,以及报表的深度。先看存储那一栏,再看功能那一栏;实际做决定时,顺序就是这样的。
| 工具 | 技术栈与存储 | 合理的档位 | 适合选择它的理由 |
|---|---|---|---|
| Umami | Node 应用 + PostgreSQL 或 MySQL。两个容器。 | Sentinel · $3.90 | 默认之选。轻量、清晰易懂、无 Cookie、支持多站点,MIT 许可证。 |
| Plausible Community Edition | Elixir 应用 + PostgreSQL + ClickHouse。四个容器。 | Garrison · $7.90 | 目标转化、转化路径与公开仪表盘;高数据量下的快速查询。 |
| Matomo | PHP 应用 + MariaDB,外加一个定时归档任务。 | Garrison · $7.90 | 与现有方案功能对等——细分、群组分析、电商、日志导入。 |
| GoAccess | 一个读取网络服务器访问日志的二进制程序。没有数据库。 | 沿用你已经在用的 | 完全没有 JavaScript——静态站点、文档、API。 |
Umami 是首选方案,除非你有理由不选它。它是一个运行在单一关系型数据库之上的 Node 应用,一 GB 内存就能让它满足,其数据库结构只是几张你自己也能查询的表,报表覆盖了大多数人打开仪表盘想看的内容:页面、来源、国家、设备,以及需要时的自定义事件。它默认不使用 Cookie,也不需要你为此做任何配置。
Plausible Community Edition 是托管产品的可自建版本,多出来的部件是 ClickHouse——一种列式存储数据库,能让针对数千万行数据的聚合查询快得几乎瞬时完成,同时它会用掉你允许它用的所有内存。当月访问量达到数百万以上时,这笔交易是划算的;低于这个量级则显得有些奇怪。部署之前请阅读该项目的许可条款:社区版的设计目的是运行你自己的分析服务,而不是转售为一项服务。
Matomo 是四者之中唯一真正逐项功能替代现有方案的工具,而这句话的诚实之处是双向的:你会获得细分、转化路径、群组分析、电商归因、通过插件实现的热图,以及导入自有服务器日志的能力;但你同时也要面对一个体量庞大的 PHP 应用——它的原始数据表增长很快,报表则由一个你必须自行调度的归档任务预先计算生成。无论如何,有两点值得关注:它可以配置为不设置任何 Cookie,而且它的受众统计配置也曾出现在监管机构公布的、豁免同意要求的工具名单上——请查证当前的名单,而不是某篇博客文章,但这在纸面上确实是一项真正的优势。
GoAccess 是那种没人会主动推荐、却有不少人该用的选项。它读取网络服务器本来就会写入的访问日志,并将其渲染成终端报告或一份独立的 HTML 页面。浏览器中不运行任何代码,设备上不存储任何数据,也不存在同意与否的问题,因为除了请求本身之外没有任何额外的收集。你放弃的是页面内部发生的一切,以及统计“人”而非“请求”的任何可能性。对于文档站点或静态博客而言,这通常是一笔划算的交易——而且它更适合与其他工具搭配使用,而不是取而代之。
如果你说不出自己需要 Plausible 或 Matomo 的哪个具体功能,那你需要的就是 Umami。花二十分钟部署它,运行一个月,让你发现自己回答不了的那个问题来告诉你是否需要换。以后再迁移,代价只是历史数据,而你会失去的历史数据也就是一个月而已。
下单购买 VPS,并根据你的读者所在位置,以及你希望数据落在哪里,来选择堡垒机房——斯德哥尔摩、赫尔辛基、奥斯陆或雷克雅未克全都身处 EEA 之内,这正是重点所在。然后在其他任何操作触碰这台机器之前,先完成首小时加固流程:仅密钥登录的 SSH、更改默认端口、默认拒绝的防火墙、无人值守更新。这套流程在本系列每一篇指南里都是同样的四十分钟,而在一台将承载某个人一整年读者数据的机器上,这一步绝不是可选项。
接下来要把主机名定下来,因为它会被写死在你统计的每个站点每一页的跟踪代码片段里,之后再改就意味着要把它们全部编辑一遍,而在此期间旧名字依然会收到访问请求。两种方案都可行。一种是你所统计站点的一个专用子域名——分析机器上的反向代理负责应答,这是最简单、也最管用的方式。另一种是使用属于它自己域名下的一个中性名字,适用于一个实例要服务多个互不相关站点、而你不希望每个站点的源码把其他站点暴露出来的情形。在继续下一步之前,先创建好这条记录并让它能够解析:代理在首次启动时会向证书颁发机构申请证书,而对方会从外部检查这个名字。
dig +short stats.example.com # must return the VPS address before you deploy
ufw default deny incoming
ufw allow 47222/tcp # administrative SSH, moved off 22
ufw allow 80/tcp # ACME challenge and the redirect to 443
ufw allow 443/tcp # the dashboard and the collection endpoint
ufw enable && ufw status numbered
只开三个端口,不多不少。数据库绝不能对外发布:它只存在于 Docker 内部网络里,只有应用容器能访问到,公网上任何人都访问不到。这是一台自建分析机器最终出现在扫描结果里的头号常见原因——PostgreSQL 或 MySQL 的端口被绑定到了公网地址,因为某个教程里的 Compose 文件本来是为本地开发准备的端口映射,被原样搬了过来。
关于配置大小,要克制住买大一点总没错的冲动。一台Sentinel——2 vCPU、4 GB、120 GB NVMe,每月 $3.90——运行 Umami 加 Postgres 绰绰有余,对于一个月访问量达到六位数的站点,也足够容纳好几年的事件数据。如果你选择了 Plausible,就升级到Garrison——4 vCPU、8 GB、240 GB——因为 ClickHouse 在那里会更舒服;选择 Matomo 也一样,因为归档任务需要更多核心。每一档的带宽都不限量,而分析流量在其中只是一个几乎可以忽略的小数目:每次访问只有几百字节。
下面给出的参考部署方案是 Umami,因为它是大多数读者应该使用的那一款,而且这套结构具有普遍性:一个应用容器,一个只有它自己能访问、别人都访问不到的数据库容器,以及一个持有证书的反向代理。Plausible 和 Matomo 的区别只在于容器数量和变量名称,结构上并无不同——拿它们各自官方的 Compose 文件,套用同样这三条规则即可。
这三条规则,按忽视它们所要付出的代价从高到低排列。把每个镜像都锁定到一个确定的标签,绝不要用浮动标签:一套分析技术栈,如果在一次无关的重启过程中悄悄拉取了一个新的主版本,那就等于给你安排了一次你自己都没计划过的数据库结构迁移。用真正的随机源生成应用密钥并妥善保管——它用来加密会话数据,事后更换它,最好的结果也是让所有人都被登出。不要发布数据库端口:两个容器共享一个网络,这就是它们所需要的全部访问控制。
mkdir -p /srv/analytics && cd /srv/analytics
openssl rand -base64 32 > .app_secret # keep this file; back it up with the database
openssl rand -base64 24 > .db_password
chmod 600 .app_secret .db_password
Compose 文件。两个服务,一个私有网络,一个用于数据库的具名卷,没有发布任何一个端口——只有代理能与外部世界通信:
services:
umami:
image: ghcr.io/umami-software/umami:postgresql-v2.x.y # an exact tag, never :latest
environment:
DATABASE_URL: postgresql://umami:CHANGE_ME@db:5432/umami
APP_SECRET: CHANGE_ME # the openssl output above
depends_on: [db]
restart: unless-stopped
db:
image: postgres:16-alpine
environment:
POSTGRES_DB: umami
POSTGRES_USER: umami
POSTGRES_PASSWORD: CHANGE_ME
volumes:
- umami-db:/var/lib/postgresql/data
restart: unless-stopped
volumes:
umami-db:
Caddy 是在这里搭建正确 TLS 配置最快的路径:两行配置,证书的获取和续期都不需要 cron 任务,而且默认设置本身就足够现代,不用你另外去研究。如果这台机器上已经在跑 nginx,就继续用 nginx——这里的要求是前面要有一个代理,而不是必须是某一款特定的代理。无论用哪一种,分析应用本身都绝不能直接监听 443 端口。
# Caddyfile — Caddy runs as a third service in the same Compose project, so
# "umami" resolves on the internal network. It is the only service that
# publishes ports (80 and 443).
stats.example.com {
encode zstd gzip
reverse_proxy umami:3000
}
把它跑起来,然后立刻做那一件真正分秒必争的事。执行 docker compose up -d,等待迁移完成,打开仪表盘。这几款工具无一例外,要么带有一个写在文档里的默认管理员账户,要么就是一个开放的首次注册页面;而主机名在证书签发的那一刻就已经公开,因为证书透明度日志是公开的,并且会被持续抓取。在第一次成功加载后的几分钟之内就修改默认密码并关闭注册,不要拖到明天。
docker compose up -d
docker compose logs -f umami # wait for the schema migration to finish
docker compose ps # both services healthy, no published ports listed
ss -tlnp | grep -E ':(5432|3306)' # must print nothing at all
Umami 自带一个写在文档里的管理员账户,全世界每一次安装的密码都一样。Plausible 则是谁第一个访问就成为所有者,除非在环境变量里禁用了注册。Matomo 会引导第一个访问者走完一个创建超级用户的安装流程。这三种情况下,“证书已经生效”和“你已经登录”之间的这段窗口期,都是别人可以趁机登录进去的窗口——而且他们根本不需要猜主机名,因为这个名字已经替他们公开好了。先登录,修改凭据,然后把注册开关设为关闭,再刷新页面确认设置生效。
在仪表盘里注册站点,复制它给你的标识符,然后在模板里放入一个延迟加载的脚本标签——放在 head 里还是 body 末尾都无所谓,但无论放在哪里都要延迟加载,这样它就绝不会拖慢页面。这就是全部的集成工作。没有标签管理器,没有容器,没有数据层,也没有同意模式的接线逻辑,而这种没有正是你想要的大部分东西。
<script defer src="https://stats.example.com/script.js"
data-website-id="00000000-0000-0000-0000-000000000000"></script>
加载站点的一个页面,然后查看仪表盘:这次访问应该在几秒钟之内就出现。如果没有出现,浏览器控制台和网络面板能在一分钟之内告诉你原因——两种常见故障分别是标识符打错了,这会产生一个被接受但随后被丢弃的请求;以及请求根本没有发出去,这说明是被某个浏览器扩展拦掉了。在开始查看数字之前,先排除自己产生的流量,否则你自己的刷新会在接下来一整周里都是排名第一的来源。
现在到了值得认真考虑的决定。上面这段代码片段会向一个不属于站点自身的主机名发起请求,而你的一部分访客运行着按规则模式拦截此类请求的软件。这些名单会拦下那些人尽皆知的文件名——任何以厂商自己的脚本名结尾的文件——以及那些人尽皆知的托管域名,无论它们实际指向哪台服务器。解决办法分两部分:把脚本文件和收集端点重命名成一个听起来不像跟踪器的名字,这几款工具全都支持这么做;再让它们从站点自身的源上提供,走一条你现有代理会转发的路径。这样一来,就没有任何第三方请求可供拦截了。
# On the site's own web server — the two paths the tracker needs, first-party:
example.com {
handle /p/s.js { reverse_proxy https://stats.example.com { header_up Host stats.example.com } }
handle /p/collect { reverse_proxy https://stats.example.com { header_up Host stats.example.com } }
# ... the rest of the site
}
有两个细节决定了这套方案是完全管用,还是只管用一半。代理必须把访客地址放进一个分析应用信任的请求头里转发过去,否则每一次访问都会被归到你自己的网络服务器名下,国家分布报表就会只剩一根柱子。另外还必须告诉这个跟踪脚本该把数据发到哪里,在这三款工具里,这都是脚本标签上的一个 data 属性——只重命名文件而不重新指向端点,得到的就是一个能加载、却什么都上报不出去的脚本。
这也是统计这件事诚实的终点。一位关闭了 JavaScript 的访客,或者一位启用了严格名单再加上针对第一方的外观规则的访客,都不会被计入统计,而且不应该投入任何工程力气去追着他们不放——网络层级的过滤是一种明确表达出来的偏好,礼貌的应对方式就是服务器日志,它能统计到这些访客,却不会额外收集任何东西。事件和单页应用是埋点工作的另一半:每款工具都提供一个用于自定义事件的小函数,而且每一款都需要在路由切换时显式调用它,因为一个在不触发导航的情况下切换视图的框架,不会产生任何页面加载事件让脚本察觉到。
人们对于分析工具到底是否需要横幅争论不休,原因在于他们把两条不同的规则当成了一条来吵。把它们分开,答案就变得清晰可辨。《电子隐私指令》第 5(3) 条——已经被转化进每个成员国的国内法,也是 Cookie 横幅真正的法律来源——规定,在订户的终端设备上存储信息,或读取该设备上已经存储的信息,都需要事先取得其同意,除非这是提供其明确要求的服务所严格必需的。请注意它没有说什么:它没有说Cookie,也没有说个人数据。它同样约束 localStorage,也约束设备指纹识别,而且即便是一个不能识别任何人身份的值,它也同样适用。
GDPR 是第二条规则,管辖的是另一个问题:一旦你拿到了个人数据,你可以对它做什么。它适用于你的分析系统,无论你是否在设备上存储了任何内容,因为一次网络请求本身就会带来一个 IP 地址,而欧洲法院在 Breyer 案(C-582/14)中已经裁定,在网站运营者手中,IP 地址可以构成个人数据。于是这两条规则叠加在一起:5(3) 问的是你是否写入了设备,GDPR 问的是你对到手的数据做了什么。
一台无 Cookie 的分析服务器,正是为了在最小范围内回答这两个问题而设计的。它不在设备上存储任何东西——没有 Cookie,没有 localStorage 记录,没有任何形式的标识符——这就使 5(3) 完全不适用,因为既没有存储,也没有对存储的访问。它会取用自己必然会收到的 IP 地址,将其与用户代理、站点以及一个每天轮换的密钥盐值组合起来,计算出哈希值,保留哈希、丢弃原始地址。这个哈希能让工具在一天之内区分两位访客,而一旦密钥盐值轮换,它就立刻失效——这正是为什么同一个人明天会被算作一次新的访问。这里确实存在处理行为,但它已经小到处理行为能有的最小程度。
剩下的问题,就是为这项范围狭窄的处理活动找到一个合法依据,实践中运营者通常依据第 6(1)(f) 条所规定的正当利益,并配以一份简短的利益平衡评估——之所以简短,是因为事实很简单:没有画像、没有共享、没有跨站跟踪、一个每天失效的匿名标识、一个明确的保留期限。若干监管机构更进一步,公布了具体标准,规定在严格限定范围内的纯粹受众统计可以完全豁免同意要求——各国标准不尽相同,而且会不断更新,真正对你有意义的是你自己所在辖区的那一份。这不构成法律意见。它只是一张标明哪些法律文本适用的地图,这样你去寻求的建议才能针对你自己的具体情况,而不是停留在这个问题的一般轮廓上。
| 问题 | 广告技术分析标签 | 无 Cookie,在 EEA 内自建 |
|---|---|---|
| 是否会写入访客设备? | 会——因此适用第 5(3) 条的同意要求 | 不会——不会触发 5(3) 条 |
| 是否保留持久标识符? | 几个月到几年,跨站点 | 每日过期的加盐哈希 |
| 是否需要记录第三国传输? | 是的,需要维持一套传输机制 | 没有——机器本身就在 EEA 境内 |
| 需要列明并签约的处理者 | 该厂商及其次级处理者 | 只有你的主机商,仅限于硬件层面,没有其他人 |
| 谁能够回应数据主体访问请求 | 你自己,通过现有的任意导出功能 | 你自己,用 SQL 查询——而且往往什么都查不出来 |
档案里还应该再加上一行,因为这正是做这一切的隐性理由。把欧洲访客的数据发送给美国的分析服务是否合法,这个问题已经被诉讼了十年:欧洲法院在 2020 年通过Schrems II 案(C-311/18)推翻了此前的传输框架,多个国家的监管机构在 2022 年据此裁定标准分析标签违规——奥地利在一月,法国在二月,意大利在六月,其后又有其他国家跟进——而一项新的充分性认定,即欧盟—美国数据隐私框架,在 2023 年 7 月重新开通了一条传输通道,但这项认定本身也正受到挑战。你不需要对这件事最终会如何收场持有自己的看法。一台放在赫尔辛基的机器,能把这个问题从你的档案里永久移除,而这比在当下这个问题上站在正确的一方更有价值。
在第一天就设定好保留期限,趁它还只是一个抽象的数字,而不是一年你已经舍不得删的数据。这几款工具都能按计划删除原始事件、同时保留汇总数据;十二个月的明细数据对几乎任何用途来说都已经很宽裕,这也意味着面对“你保留数据多久”这个问题,诚实的答案是一个具体数字,而不是“无限期”。这样做还能在磁盘问题发生之前就把它解决掉,这一点对 Matomo 尤其重要,因为它的原始数据表正是增长最快的部分。
把数据库备份到这台机器之外的地方,并在传出时加密——完整做法见备份指南,简而言之就是每晚做一次转储,通过管道写入另一台机器上的一个仅追加(append-only)仓库,最好放在第二个司法辖区。同时备份应用密钥:一个能恢复的数据库,配上一个恢复不了的密钥,等于一个谁都登录不进去的仪表盘。然后在真正需要之前,主动在一台临时 VPS 上完整恢复一次。
docker compose exec -T db pg_dump -U umami umami | zstd -q -o /srv/backup/umami-$(date -u +%F).sql.zst
restic -r sftp:backup@bastion-2:/srv/repo backup /srv/backup /srv/analytics/.app_secret
restic -r sftp:backup@bastion-2:/srv/repo forget --keep-daily 7 --keep-weekly 8 --prune
升级这件事值得比普通的容器版本提升多花一点心思,因为这些应用都拥有自己的数据库结构。把你要跨过的每个主版本的发布说明都读一遍,先备份、再升级,而不是反过来;然后改动锁定的标签,把服务启动起来,同时盯着日志看——一次中途失败的迁移,靠昨晚的备份就能恢复过来,没有备份就会非常难受。完全没必要在新版本刚发布的那一周就冲上去用,而且有充分的理由不这么做。
你刚刚部署的这套技术栈,刻意做到了从不存储 IP 地址。可就在两米之外,你的反向代理正把每一位访客的完整 IP 地址,以明文形式写进一份访问日志,并按默认的轮转策略保留下来——无论是在分析机器上,还是在你实际站点前面的网络服务器上,都是如此。这份日志是一个比分析数据库更庞大、更敏感的数据集,是一项你必须为之负责的处理活动,而几乎没有人会记得它的存在。决定好它到底是为了什么:如果只是用来调试,就在日志格式里截断或遮蔽最后一段地址并加快轮转频率;如果你想把它用于基于日志的统计,就在政策里说明这一点,并给它一个真实的保留期限。你唯一不能做的,就是保持默认设置不变,却对外宣称自己的网站不收集 IP 地址。
最后,还有一些局限性值得诚实面对,因为一台自建的计数器并不是你所替换掉的那个东西的严格意义上的升级版。你会失去跨设备、跨天的身份识别,所以回访读者这个说法的含义会比以前狭窄。你会失去广告平台的集成,如果你购买流量,这一点很重要;如果你不买流量,这就无关紧要——搜索控制台的数据是另一个独立的产品,不受影响。你要自己承担升级和备份的工作,这是一项以晚上的时间计价的真实的持续成本。而这台机器本身也变成了一件值得认真保护的东西:它保存着你的读者数据,并且暴露在公网上,加固清单,加上一条通往仪表盘的私有线路,是让它持续保持平淡无奇的两件事。
这些工具里有一款,在全世界每一次安装时都使用同一套默认管理员凭据;其他几款则是谁先注册谁就拥有所有权。主机名一旦 TLS 生效,就会立刻被发布到证书透明度日志里。登录、修改凭据、关闭注册——都要在最初五分钟内完成,不要等到明天。
为笔记本电脑写的 Compose 文件会把 5432 或 3306 端口发布出去,方便作者用图形界面工具连接。把这样的文件原样搬到一台公网机器上,读者数据表就只隔一次密码猜测的距离。应用容器通过内部网络就能访问数据库;除了代理之外,什么都不需要对外发布。
把软件搬到自己的机器上,解决的是数据传输的问题和数据处理者的问题。但如果你随后又打开了某个会写入设备的功能,它并不能解决第 5(3) 条的问题,也不会替你写好隐私政策。豁免与否取决于配置本身,而不是取决于自建这件事。
如果反向代理不转发客户端地址,每一次访问看起来都像是来自代理本身。仪表盘照常被填满,总数看起来也没问题,但地理位置和唯一性这两栏数据其实早已悄悄失真。请在第一天就检查国家分布情况,而不是等到季度复盘的时候。
选择这套技术栈的理由是它从不存储 IP 地址。但它前面的代理默认会以明文形式存储每一个 IP 地址,你实际站点前面的网络服务器同样如此。要有意识地对它们做遮蔽或轮换处理,并在政策里说明这一点——否则就别再宣称自己不收集这些数据。
新的总数不会和旧的对得上,也没有任何配置能让它们对上。计数规则不同,被拦截的比例不同,而且也没有横幅在过滤样本。花两周时间摸清自己的换算比例,然后把新的数字当作基准,不要再费心对齐两套不同的定义。
在实际操作中会遇到的十一个问题——从那个几乎人人都会在两个方向上都搞错的问题开始。
通常是可以的,而理由比“自建就没问题”要精确得多。这里涉及两条独立的规则。《电子隐私指令》第 5(3) 条——也就是大家常说的“Cookie 法”——要求,除非是访客所要求的服务严格必需,否则在其设备上存储信息,或读取其设备上的信息,都需要事先取得同意。它适用于 Cookie,也同样适用于 localStorage、sessionStorage 以及你在设备上留下的任何其他东西,而且无论这些数据是否属于个人数据都同样适用。一款完全不向设备写入任何内容的工具,根本不会触发这条规则。GDPR 是第二条规则,它并不会因此就不适用:每一次请求你依然会收到一个 IP 地址和一个用户代理字符串,而 IP 地址在网站运营者手中就是个人数据(欧洲法院,Breyer 案,C-582/14)。一台无 Cookie 的分析服务器所做的,是用一个每天轮换的盐值对这个 IP 进行哈希处理,然后丢弃原始地址,于是最终落入数据库的,是一个按天、按站点区分的匿名标识,而不是一个人。这是一种范围很窄、有充分文档记录的处理活动,大多数运营者据此主张正当利益作为依据,也有若干监管机构公布过纯粹的受众统计豁免同意要求的具体标准。这是一个站得住脚的立场,但不是一句万能咒语:把你收集了什么、为什么收集、保留多长时间都写下来,并去阅读你所在辖区监管机构自己发布的指引,而不是某个厂商的宣传页面。本页内容不构成法律意见。
Umami。它是一个单独的 Node 应用加一个 PostgreSQL 数据库,1 GB 内存就能舒服运行,仪表盘第一次打开就看得懂,开箱即无 Cookie,而且一个实例就能愉快地服务你名下的所有站点。对于绝大多数想替换掉博客、文档站点、店铺或公司网站上 Google Analytics 的人来说,这就是正确答案,另外三款工具的争论根本没必要参与。如果你想要转化路径、收入目标,以及更强的公开仪表盘展示效果,并且愿意为此运行 ClickHouse,那就选 Plausible Community Edition。如果你真的需要 Google Analytics 那一整套功能——细分、群组分析、自定义报表、电商归因、原始日志导入——并且能接受自己运维一个带定时归档任务的大型 PHP 应用,那就选 Matomo。如果你想让页面上彻底没有 JavaScript,那就选 GoAccess。
因为它们统计的本来就是不同的东西,而且差距同时朝两个方向拉开。往高的方向:挂在同意横幅后面的 Google Analytics,只能看到点了“接受”的那部分访客,在欧洲这通常只剩一半,而一个没有横幅、无 Cookie 的计数器则能看到所有人。再往高的方向:你的新端点在自己的域名下,不在那些丢弃对知名跟踪器请求的过滤名单上。往低的方向:每日轮换的哈希无法在明天认出同一个人,所以一位在周一和周四分别访问的读者会被算成两位访客,而不是一位回访读者——会话只在一天之内拼接,从不跨天、也不跨设备。再往低的方向:大多数自建工具自带一套保守的机器人过滤规则,也没有Discover式的流量灌水。实际的建议是别再费心对账了。两个系统并行跑两周,摸清自己的换算比例,写在便利贴上,然后删掉 Google 的标签,把新的数字当作新的基准来用。真正影响决策的是趋势的走向,以及页面和来源之间的相对排名,而这两者在迁移之后都完好无损。
部分有效,而且值得弄清楚具体是怎么回事,因为这套机制比大家以为的要笨得多。大型过滤名单依赖的是模式匹配:托管服务的主机名,以及一批知名的文件名和路径名——任何以 plausible.js、umami.js 或 matomo.php 结尾的请求都能被识别出来,不管它实际指向哪台服务器。就算你把软件搬到 stats.example.com,只要还用着默认文件名,仍然会流失一部分懂技术的访客。这里有两个真正管用的办法,而且可以叠加使用。把脚本和收集端点重命名成一个听起来不像跟踪器的名字——这几款工具都支持,只需要一行配置。让它们从站点自身的源提供,走你主域名下一条由反向代理转发的路径,这样就没有第三方请求可供拦截了。两者结合,能挽回大部分损失。但你不会全部挽回,而且也不该指望全部挽回:一位启用了严格名单、又关闭了 JavaScript 的访客,这本身就是一种选择,对此正确的应对方式是服务器日志,而不是一场没有尽头的攻防战。
这个问题问得有道理,而答案取决于拦截工具原本在保护什么。过滤名单只有一种粗暴的工具,却对应着两种截然不同的目标:一种是跨越上万个站点追踪一个人、建立画像的广告技术网络;另一种是只是告诉某个站点主人“昨天这篇文档被读了四百次”的计数器。拦截第一种,是一个人在为自己抵御监控。拦截第二种,则是一条无法区分两者的规则所造成的附带损害。把自己的计数器架设在自己的域名下,并不是把一个跟踪器偷偷带过防线;而是移除了一个本来就不该存在的第三方请求,同一次访问依然会在你的访问日志里留下一条记录,不会有任何变化。这种做法不再站得住脚的临界点,是你代理的东西不再是本文描述的这种东西的那一刻——如果你加入了跨站标识符、指纹识别,或者接入了广告平台的数据管道,那拦截工具就是对的,而这个代理就是一句谎言。有一个简单的测试,值得对自己应用一次:你能不能公开发一页文字,准确说明这个端点到底收集了什么,而读者看完只会耸耸肩?如果能,那就代理它。如果不能,问题就不在代理本身。
比你担心的要小得多,只有一个例外。Umami 是一个 Node 进程加一个 Postgres 数据库:对于普通站点,它的内存占用能稳定在 1 GB 以内,数据库每一次页面浏览大约只增长一行文本的大小,所以一台 Sentinel——2 vCPU、4 GB、120 GB NVMe,每月 $3.90——有着好几年的余量。GoAccess 的占用几乎可以忽略。Matomo 处于中间位置:PHP 和 MariaDB 平时并不吃资源,直到归档任务运行时才会出现你必须为之预留规格的 CPU 峰值,而且它的原始数据表比其他工具增长得更快,因为它每次访问都保存更多信息。例外是 Plausible Community Edition,而原因在于 ClickHouse,不在 Plausible 本身:列式存储数据库的设计思路就是用内存换查询速度,你放着不管的内存,它都会拿去用。如果你在默认配置里限制它的缓存,它可以在 4 GB 下运行,在 8 GB 下则相当舒适——这也是为什么每月 $7.90 的 Garrison 档,对这一款来说才是合理的起点。不管是哪一种情况,最终逼着你升级的数字都是磁盘,而不是内存,步骤 06 就是教你如何遏制这一点。
可以,而且这本来就是运行这些工具的常规方式。这三款 JavaScript 工具在设计上都支持多站点:你在仪表盘里逐个注册每个域名,各自获得自己的标识符,而同一个脚本端点会接受它们全部的访问数据,同时把报表分开保存。一台机器,一张证书,一份备份,一次升级——二十个站点。随着站点列表增长,有两件事要留意。报表是按站点分开的,所以如果你在为客户管理站点,应该使用工具自带的用户和团队权限体系,而不是把管理员账户交给每一个人;而且在合同里同意共享一个实例之前,先弄清楚这意味着什么:你将成为掌握着他们访客数据的那一方。另外,跟踪端点使用的是一个共享的名字,这意味着提供这个端点的域名会出现在列表上每一个站点的源码里——这一点值得提醒那些竞争对手会去看页面源码的客户,也是步骤 04 中提到的第一方路径的一个理由。
对于很大一类网站来说,日志就已经足够,而且它是目前最诚实的统计方式:它不会额外收集任何东西,因为这些记录本来就已经存在。GoAccess 读取网络服务器的访问日志,生成一份终端报告或一个独立的 HTML 仪表盘——热门页面、来源、状态码、带宽、响应时间、用户代理——对于一个静态站点、一套文档或一个 API 来说,这基本涵盖了脚本标签原本能告诉你的大部分内容。有两个限制决定了它对你是否够用。日志看不到页面内部发生的事情:没有滚动深度,没有站外链接点击,没有按钮事件,也没有单页应用的路由切换,因为这些都不会触达服务器。而且日志统计的是请求,而不是人,所以你会受制于缓存,也会受制于如今已占原始流量大多数的机器人流量——过滤是一项永久性的维护工作,而不是一次性的配置步骤。这里还有一个方向恰好相反、出乎意料的隐私陷阱,步骤 06 会讲到:你正在分析的这份日志保存着完整的 IP 地址,这比你拒绝使用的那款 JavaScript 工具所保留的个人数据还要多。
实际情况是不能,而围绕这一点提前做好规划,比硬拗要好得多。Matomo 是四款工具里唯一有正儿八经导入方案的一个,但即便如此,可行的路径也是导入你自己的网络服务器日志,以及使用老版本 Matomo 实例的迁移工具,而不是把 Google 已经处理好的报表干净地搬过来。Umami 和 Plausible Community Edition 都可以通过各自的 API 接受批量导入,前提是你愿意自己写映射逻辑,但那等于是在用聚合导出的数据凭空编造会话和访客,结果得到的图表看起来是连续的,实际上在拼接处根本没有可比性。真正管用的做法是:在这个属性被删除之前,把你关心的报表——月度总量、热门页面、热门来源、转化次数——从 Google 导出成 CSV,和你的其他记录放在一起保存,然后让新工具从一个你写下来的日期开始,作为全新的基准起点。你大概会在第一年里查阅这份旧导出两次,之后就再也不会用到了,而且里面的每一个数字本来就是按另一套定义测量出来的。
比你想象的要少,而“短”正是重点——一段你自己能站得住脚辩护的文字,胜过一整页照抄来的内容。说明这是什么工具,以及是你自己在运行它;写明服务器所在的地点和法律运营主体,因为能够说出“运行在我们租用的一台芬兰机器上”正是这么做的全部意义所在。说明每次访问会记录什么:页面、来源、国家、设备与浏览器类别,以及一个由 IP 地址和用户代理、加上每天变化的盐值推导出的匿名标识符,且原始 IP 无法从中还原。说明不会记录什么:没有 Cookie,没有跨站标识符,没有画像,不出售或共享任何数据。写明你所依据的法律依据和保留期限,并确保你写下的数字与工具实际配置的数字一致。如果你的反向代理保留访问日志,那是另一项独立的处理活动,有它自己的保留期限——要把它写出来,因为这正是大家最容易忘记的一点。然后让这段文字始终与实际配置保持同步:一份描述两年前配置的政策,比一份含糊其辞的政策更糟糕。
因为“只是页面浏览量”这种说法低估了一个分析数据库究竟是什么。按一年时间累积起来,它就是你网站的读者画像:哪些页面、按什么顺序、来自哪些国家、在哪些时段、通过哪些链接进入——对一个小型出版方或小众店铺来说,这一张表就等于一份商业计划书加一份客户来源清单。从司法管辖的角度看,这恰恰也是对手会向服务商索要、而不是直接向你索要的那类数据。由此引出两个特性。机器所在的位置决定了哪种法律程序可以触及它:一台位于斯德哥尔摩、赫尔辛基、奥斯陆或雷克雅未克的机器身处 EEA 范围之内,这就把跨境传输问题完全排除在你的合规档案之外,同时也身处四个拥有深厚新闻自由传统的宪政体制之内。而账户上署的是谁的名字,则决定了账户本身会暴露什么:在 NordBastion 上,没有身份证件、没有法定姓名、没有银行卡,账单以 Monero 或 Bitcoin 结算,承载你读者数据的机器不会是某个客户数据库里绑着你护照信息的一行记录。司法辖区指南详细介绍了这四地各自的法律底线。
Sentinel——2 vCPU、4 GB 和 120 GB NVMe,每月 $3.90,机房位于赫尔辛基、斯德哥尔摩、奥斯陆或雷克雅未克——运行 Umami 和它的数据库还绰绰有余,足够容纳好几年的事件数据。如果你选择了 Plausible 或 Matomo,就升级到每月 $7.90 的 Garrison。注册无需邮箱,无需身份证件,无需银行卡,也没有第三方掌握着所有读过你网站的人的名单。
最后审核 · 2026-10-12 · 来源 · Umami、Plausible Community Edition、Matomo 与 GoAccess 官方文档;《电子隐私指令》2002/58/EC 第 5(3) 条;(欧盟)第 2016/679 号条例;欧洲法院对 Breyer 案(C-582/14)及 Schrems II 案(C-311/18)的判决;2023 年 7 月的欧盟—美国数据隐私框架充分性认定 · 周期 · 每年
This guide is one spoke of a larger series. The pillar walks the three privacy layers end to end — the sibling spokes below dive into the specifics.
Three independent layers — signup, payment, network — explained, legal context included, common mistakes flagged.
Bitwarden-compatible password vault under your own control.
Files, calendar, contacts, photos — owned, not rented.
Postfix, Dovecot, SPF/DKIM/DMARC — deliverability included.
A meta search engine that does not log you — because you own it.
私密托管,源自北欧。