Umami 是一款开源、轻量、注重隐私的网站分析工具

GitHub:https://github.com/umami-software/umami(37.5k⭐)

前言

如果想要统计网站的被访问情况,通常有第三方工具(如 Google Analytics)和开源自建(如 Umami、Plausible)两种选择。前者上手快但存在隐私顾虑和网络限制;后者需自行部署,但数据自主可控。综合对比后,我选择了 Umami 作为个人博客网站的分析工具。

Umami 提供官方托管自托管两种方式。官方托管的免费版虽然开箱即用,但存在以下限制:

  • 仅支持监控 1 个网站

  • 数据仅保留过去 6 个月

这两个限制无法满足我的需求,因此本文记录如何通过 Vercel 免费部署 Umami。

想要把服务成功运行起来,需要两个核心组件:

  • 服务端:提供运行环境与可视化管理面板

  • 数据库:用于持久化存储站点的访问数据

下面介绍具体部署步骤。

部署步骤

Fork 仓库

登录 GitHub,Fork Umami 仓库

点击“Create fork”

Vercel 部署

新建项目

如未授权,则需要先在 Vercel 中授权 GitHub。如已授权,则跳过。

导入项目

直接部署

这里会部署失败,是正常的,因为缺少数据库环境变量。接下来去创建数据库,点击“Go to Project”

在左侧列表点击找到“Storage”,找到 Neon 数据库(Umami 要求使用 Postgres 数据库),点击“Create”

点击“Accept and Create”

选择区域、关闭 Auth(Umami 有自己的登录系统,无需 Neon 提供的认证服务)、选择 Free 套餐、最后点击“Continue”

设置数据库名称、最后创建

等待创建完成后,连接到刚才的创建的 umami 项目

连接成功后,点击“Project”,点击刚才部署的 umami 项目

左侧列表点击“Deployments”,找到刚才部署失败的记录,点击“Redeploy”再次部署

在弹框中点击“Redeploy”

等待部署完成后,Vercel 会给一个.vercel.app结尾的后台访问地址,如果你有魔法,那么可以直接在浏览器打开 .vercel.app 结尾的后台访问地址

但该地址在国内已被墙,需要为该服务绑定自定义域名才能保证后续跟踪代码的正常使用。

自定义域名

我已通过腾讯云托管了主域名,因此我只需要为 Umami 创建一个二级域名,让腾讯云可以正常解析即可。

先进入 Umami 项目,点击“Domains”,点击“Add Existing”

填写二级域名

添加后点击“Learn more”展开,记录 Value的值

去腾讯云 DNS 解析,添加记录,主机记录填自定义的二级域名前缀,类型选CNAME,记录值填上一步记录的Value值,最后点确认

返回 Vercel,查看域名是否绑定成功

配置后台

访问后台,进入后第一件事一定要修改密码

提示

初始账号:admin;初始密码:umami

监控目标网站

点击“网站”、点击“添加网站”

输入你想要监控的目标网站

添加成功后,点击编辑按钮

找到跟踪代码并复制,这串代码就是访问统计的核心。之后为任何网站添加访问统计,用到的都是这串代码。我的个人博客由 Hugo 构建,下面就以 Hugo 为例

我用的是 PaperMod主题,因此只需要编辑\layouts\partials\extend_head.html文件

{{- /* Head custom content area start */ -}}
{{- /*     Insert any custom code (web-analytics, resources, etc.) - it will appear in the <head></head> section of every page. */ -}}

/* 添加以下内容 */
{{- /* Umami analytics (production only) */ -}}
{{- if eq (site.Params.env | default hugo.Environment) "production" }}
/* 下面这行替换成你的追踪代码 */
<script defer src="https://你的二级域名/script.js" data-website-id="xxxx"></script>
{{- end }}

{{- /* Head custom content area end */ -}}

此时已经可以通过 Umami 后台面板看到网站的访问统计了。

为博客配置访问统计

我的另一个需求是为 Hugo 博客配置一个访问信息显示在页面底部,但Umami 并没有提供公开的、免认证的统计接口,所有的接口都需要带认证 token,但是我们又不能把 token 直接暴露在前端,因此就需要在 Vercel 创建一个轻量的内部包含登录信息的项目,专门跑代理接口。浏览器需要统计信息时会向代理接口发起请求,代理服务会完成登录并获取 token ,再去请求 Umami 获取数据并返回。

我的博客托管在腾讯云COS,Umami部署在 Vercel,因此整个流程大概是:

话不多说,开始操作。

准备信息

用管理员账号进入 Umami 后台,准备以下信息

变量名获取方式
UMAMI_BASE_URLUmami 后台访问地址
UMAMI_WEBSITE_ID点击已添加的网站 -> 记录Website ID
UMAMI_USERNAME管理员账号
UMAMI_PASSWORD管理员密码

GitHub 创建项目

登录GitHub,创建新项目,随便取个名称,例如umami-stats,权限设置公开或私有均可,创建好后点击新建文件

先输入名称api/site-stats.js

再粘贴以下内容,注意其中第3点关于跨域访问的内容。最后提交改动

// api/site-stats.js

module.exports = async function handler(req, res) {
  try {
    const base = process.env.UMAMI_BASE_URL;

    // 1. 登录,拿 token
    const loginRes = await fetch(`${base}/api/auth/login`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        username: process.env.UMAMI_USERNAME,
        password: process.env.UMAMI_PASSWORD,
      }),
    });

    if (!loginRes.ok) {
      throw new Error('Umami 登录失败,请检查账号密码是否正确');
    }

    const { token } = await loginRes.json();

    // 2. 用 token 查询统计数据(这里取全部历史数据)
    const startAt = 0;
    const endAt = Date.now();
    const statsRes = await fetch(
      `${base}/api/websites/${process.env.UMAMI_WEBSITE_ID}/stats?startAt=${startAt}&endAt=${endAt}`,
      { headers: { Authorization: `Bearer ${token}` } }
    );

    if (!statsRes.ok) {
      throw new Error('获取统计数据失败,请检查 website ID 是否正确');
    }

    const stats = await statsRes.json();

    // 3. 允许你的博客域名跨域访问(先用 * 测试,正式上线建议改成具体域名)
    res.setHeader('Access-Control-Allow-Origin', '*');

    // 4. HTTP 响应缓存:10分钟内的请求直接吃缓存,不会真正触发上面的登录+查询
    res.setHeader('Cache-Control', 's-maxage=600, stale-while-revalidate=59');

    res.status(200).json({
      pageviews: stats.pageviews ?? 0,
      visitors: stats.visitors ?? 0,
    });
  } catch (err) {
    console.error(err);
    res.status(500).json({ error: err.message || '获取数据失败' });
  }
}

Vercel 关联项目

登录 Vercel,新建项目

导入刚才在 GitHub 创建的项目

填入之前准备的环境变量后,点击部署,等待部署完成

绑定自定义域名

参考上面 Umami 部署时的自定义域名步骤。

测试接口

打开浏览器,访问https://your.domain/api/site-stats查看接口是否可以请求成功

在博客模板的 footer 部分(不同静态站生成器工具,文件位置不同,但原理一样),加上下面的代码(可自定义):

<div id="site-stats">
  <span>总访问量 <span id="pv-count">-</span></span>
  ·
  <span>访客数 <span id="uv-count">-</span></span>
</div>

<script>
  fetch('https://Vercel代理接口项目自定义域名.com/api/site-stats')
    .then(res => res.json())
    .then(data => {
      document.getElementById('pv-count').textContent = data.pageviews;
      document.getElementById('uv-count').textContent = data.visitors;
    })
    .catch(() => {
      document.getElementById('pv-count').textContent = '获取失败';
      document.getElementById('uv-count').textContent = '获取失败';
    });
</script>

最后全部成功后,别忘了修改仓库的跨域访问设置,将*换成自己的博客域名。GitHub 提交改动后,Vercel 会自动重新部署。

后记

Umami 中的功能还有很多,一些更高级的功能需要慢慢摸索