我的博客想看访问数据——多少人来了、从哪来、看了哪些页面,最好页面底部还能显示个总数。第三方统计要么数据在别人那,要么国内加载慢。最后我用 Umami 跑在自己的 NAS 上,数据落本地硬盘,后台面板开箱可用,也没花额外的钱。这篇是我的实操步骤。


这套东西能给你什么

装完之后你会得到两样:

  • 后台分析面板:PV/UV、来源、国家、设备、实时在线,都有现成图表
  • 前台数字:在自己网站底部显示「本站总浏览量 X 次」这种计数

数据全部存在你自己的设备上,不经第三方。Umami 不用 cookie,所以也不用给网站加隐私弹窗。

一个 Umami 实例能管多个网站,每个站分一个 ID,各贴一段 JS 就行。

做完之后,网站底部会显示这样一行实时计数(数字到秒在跳):

页脚访问统计

整体结构

访客浏览器
   ↓ 加载 Umami 统计脚本
统计域名(比如 stats.你的域名.com)
   ↓ Cloudflare Tunnel 反代
NAS:Umami 容器 + PostgreSQL(数据在硬盘上)

Cloudflare 在这里只当网络通道,不碰你的数据内容。

第 1 步:在 NAS 上跑起 Umami

我用 Docker Compose 一次起两个容器:Umami 本体 + PostgreSQL 数据库。

新建一个 docker-compose.yml,内容类似这样(按你的实际情况改端口和密码):

services:
  umami:
    image: ghcr.io/umami-software/umami:postgresql-latest
    ports:
      - "36439:3000"   # 左边是宿主机(NAS)端口,右边是容器内端口
    environment:
      DATABASE_URL: postgresql://umami:你的密码@db:5432/umami
      DATABASE_TYPE: postgresql
      APP_SECRET: 换成随机字符串
    depends_on:
      db:
        condition: service_healthy   # 等数据库就绪再启动 Umami
  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_DB: umami
      POSTGRES_USER: umami
      POSTGRES_PASSWORD: 你的密码
    volumes:
      - ./data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U umami"]
      interval: 10s
      timeout: 5s
      retries: 5

healthcheck 那段建议留着。不加的话,PostgreSQL 还没完全启动 Umami 就去连,容易启动失败或者连上又断——重启 NAS 后尤其容易遇到。

在 NAS 的 Docker 管理界面里粘贴这段(各家 NAS 都有“项目 / Compose”这种入口),启动。

端口别记混:上面把容器的 3000 映射成了 36439,所以内网访问要开 http://NAS的IP:36439。直接按 3000 打开是打不开的,那是容器内部的端口。

启动后浏览器打开这个地址,用默认账号登录(Umami 默认 admin / umami),进去第一件事是改密码。

第 2 步:让它能从外网访问

家里或内网的 NAS 没有公网 IP,用 Cloudflare Tunnel 穿出来:

  1. 进 Cloudflare Zero Trust 后台,创建一个 Tunnel,会拿到一串 Token
  2. 在 NAS 上跑 cloudflared(Docker 或装二进制都行),把 Token 配上
  3. 给这个 Tunnel 加一条 Public Hostname,比如 stats.你的域名.com,回源指向 http://localhost:36439(或容器名 http://umami:3000)

配好之后,你从任何地方打开 stats.你的域名.com 就能进后台了,而且是 HTTPS,不用自己申请证书。

第 3 步:给网站加上统计脚本

在 Umami 后台添加你的网站,会生成一段 tracking 代码和一个 website ID。把这段脚本贴到网站的 <head> 里:

<script defer src="https://stats.你的域名.com/script.js" data-website-id="你的websiteID"></script>

静态博客一般贴在公共布局文件里(我的是 BaseLayout.astro),全站页面就都带上了。

脚本文件名有两种:新版本是 script.js,老一点的版本叫 umami.js,功能一样。不确定就直接复制后台给你生成的那段代码,别自己拼。

等几分钟回后台看,有访客进来就能看到数据了。

第 4 步:在页面底部显示访问数

后台有了,前台也想显示个总数。Umami 支持“公开分享”——在后台给网站开一个分享链接,会得到一个 share ID,靠它就能调接口拿数字。

流程是两步:

① 用 share ID 换一个临时 token:

GET https://stats.你的域名.com/api/share/{shareId}

返回里有个 token 和 websiteId。

② 带这个 token 去查统计:

GET https://stats.你的域名.com/api/websites/{websiteId}/stats?startAt=0&endAt=当前时间戳

请求头带上:

x-umami-share-token: 刚才换到的 token
x-umami-share-context: share

返回的是访问量和访客数,前端渲染成「本站总浏览量 X 次」就行。

我博客上是个 Astro 组件做这件事:进页面时先显示上次缓存在 localStorage 的数字(不等接口),后台同时去拉最新值,拉到再更新。这样访客不会看到空白或者等半天才出数字。

分享 ID 本来就是只读的,拿它只能查统计,改不了数据也进不了后台,所以放在前端代码里没问题。

第 5 步:记得备份

数据都在 PostgreSQL 里,定期导出一下比较稳妥。我是每天跑一次 pg_dump 并保留 7 天:

pg_dump -U umami umami > backup_$(date +%F).sql

丢进定时任务里就行。NAS 一般都有“计划任务”功能,配个每天凌晨执行。

关于速度

这套架构下,访客的请求路径是:浏览器 → Cloudflare 边缘 → Tunnel → 你的 NAS。国内访问因为要绕一圈,加载统计脚本会比纯 CDN 慢一些,但对统计这种后台数据来说影响不大(它不阻塞页面显示)。

如果你特别在意国内打开速度,可以再租个国内轻量云做反代,或者用 DNS 分线路解析——不过那是后话了,先用起来再说。


写在最后

自己搭统计最有价值的地方不是省多少钱,而是数据在自己手上:想查什么自己写 SQL,想导出去随时能导,也不用担心哪天第三方服务关停就没了。

装好之后我每天会瞄一眼后台的实时在线,看到有人正在读自己写的东西,那种感觉还挺实在的。你要是也想给自己的站点加一套,可以照着这个流程走一遍。

评论

评论加载中…