网站部署 运维大乱斗 网站统计 《告别 GA 复杂操作!Umami 为博客添统计,轻量又精准》 Mz Xi 2025-09-14 2025-09-14 项目介绍 Umami 是一种开源、注重隐私的网络分析工具,可作为 Google Analytics 的替代品。 它提供了有关网站流量、用户行为和性能的重要见解,同时优先考虑数据隐私。
与许多传统分析平台不同,Umami 不收集或存储个人数据,从而避免了对 cookie 的需求, 并且符合 GDPR 和 PECR 标准。
Umami 设计为轻量级且易于设置,可以自托管,让用户可以完全控制他们的数据。
项目地址:鲜味软件/鲜味:Umami 是 Google Analytics 的现代、注重隐私的替代品。
详细可看文档,下面来介绍一种最简单的安装办法
Umami安装与部署 使用面板是目前感觉最简单的了,有服务器的情况下最快速
1panel面板安装部署(推荐) 应用商店搜索Umami 后安装即可,默认是3000 端口安装
安装成功后,创建一个域名网站来反向代理这个接口即可使用域名访问了。
使用域名打开网站后,进入服务,添加你需要统计数据的网站即可,到这一步,这个部署的环节就完成了,下面来进行下一步,获取你这个部署的统计网站的API。
有人说为什么刷新没啥用,因为你的网站还没有添加相应的统计代码,简单来说,这个统计网站去统计的数据来源总得有吧?就是将统计代码放入你网站的这一步,懂操作的直接自己拿统计代码放入你网站的相应位置刷新即可,不明白的继续下一步。
Docker安装部署 使用Docker搭建Umami统计,显示近一年的pv、uv数据的API搭建 | 张洪Heo
获取Umami网站的API服务 首先进入Hoppscotch 获取token
请求路径:https://你的地址/api/auth/login
,注意POST
请求
然后访问HeoPVBridge ,下载并修改umami/info.php
更改地址、token和网站id。然后部署到网站的php项目中即可。
1 2 3 4 5 // 配置 Umami API 的凭据 $apiBaseUrl = '你的统计网站的域名'; $token = '你的token'; $websiteId = '你的Umami网站上的添加的网站id';
使用1panel面板 创建一个php项目:
打开站点网站目录,上传php文件,将php文件重命名为index.php
,否则会因为找不到启动文件出现403错误,配置好后访问域名,出现下面这个界面代表成功:
开始修改 如果你都搞定了,那么修改关于页面的正文开始了
这里修改的是Hexo的安知鱼主题 ,其他网站主题请自行修改。
在 themes/anzhiyu/layout/includes/head.pug 添加
1 2 3 4 5 6 7 8 9 10 11 //- 统计配置 if theme.Umami if theme.Umami.umami_url script(async defer src=`${theme.Umami.umami_url_js}` data-website-id=`${theme.Umami.umami_id}`) else script(async defer src=`${theme.Umami.umami_url_js}` data-website-id=`${theme.Umami.umami_id}`)
然后修改 themes/anzhiyu/source/css/_page/about.styl
原文:
1 if (hexo-config ('LA.enable' )) {
修改为:
1 if (hexo-config ('LA.enable' ) || hexo-config ('Umami.enable' )) {
接着修改 themes/anzhiyu/layout/includes/page/about.pug
大概91行,这句代码.author-content
和.author-content-item-group.column.mapAndInfo
这句代码之间全部替换为(只使用Umami统计,不要51统计了):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 if theme.LA.enable || theme.Umami.enable - let cover = item.statistic.cover .about-statistic.author-content-item(style=`background: url(${cover}) top / cover no-repeat;`) .card-content .author-content-item-tips 数据 span.author-content-item-title 访问统计 #statistic .post-tips | 统计信息来自 a(href='https://um.ruom.top', target='_blank', rel='noopener nofollow') Umami统计 .banner-button-group - let link = item.statistic.link - let text = item.statistic.text
继续在这个文件中修改 直接搜 - const ck = theme.LA.ck
把这行代码(不包括这句代码)下面的全部替换:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 if (theme.Umami && theme.Umami .enable ) script (defer). (function ( ) { const umamiApiUrl = "#{url_for(theme.Umami.umami_api)}" ; fetch (umamiApiUrl) .then (res => res.json ()) .then (data => { let title = { "today_uv" : "今日人数" , "today_pv" : "今日访问" , "yesterday_uv" : "昨日人数" , "yesterday_pv" : "昨日访问" , "last_month_pv" : "本月访问" , "last_year_pv" : "本年访问" }; let s = document .getElementById ("statistic" ); for (let key in data) { if (data.hasOwnProperty (key) && title[key]) { s.innerHTML += `<div><span>${title[key]} </span><span id="${key} ">${data[key]} </span></div>` ; } } initCountUp (data, title); }) .catch (error => console .error ('Error:' , error)); })(); script (defer). function initCountUp (data, title ) { const elements = []; for (let key in data) { if (data.hasOwnProperty (key) && title[key]) { const element = document .getElementById (key); if (element) { elements.push ({ id : key, value : data[key], element : element }); } } } const selfInfoContentYearElement = document .getElementById ("selfInfo-content-year" ); if (selfInfoContentYearElement) { elements.push ({ id : "selfInfo-content-year" , value : #{selfInfoContentYear}, element : selfInfoContentYearElement }); } const observer = new IntersectionObserver ((entries ) => { entries.forEach (entry => { if (entry.isIntersecting ) { const target = elements.find (el => el.element === entry.target ); if (target) { const countUp = new CountUp (target.id , 0 , target.value , 0 , 2 , { useEasing : true , useGrouping : target.id === "selfInfo-content-year" ? false : true , separator : "," , decimal : "." , prefix : "" , suffix : "" , }); countUp.start (); observer.unobserve (entry.target ); } } }); }, { threshold : 0 }); elements.forEach (el => observer.observe (el.element )); } script (defer). function initAnimation ( ) { var pursuitInterval = null ; pursuitInterval = setInterval (function ( ) { const show = document .querySelector ("span[data-show]" ); const next = show.nextElementSibling || document .querySelector (".first-tips" ); const up = document .querySelector ("span[data-up]" ); if (up) { up.removeAttribute ("data-up" ); } show.removeAttribute ("data-show" ); show.setAttribute ("data-up" , "" ); next.setAttribute ("data-show" , "" ); }, 2000 ); document .addEventListener ("pjax:send" , function ( ) { pursuitInterval && clearInterval (pursuitInterval); }); var helloAboutEl = document .querySelector (".hello-about" ); helloAboutEl.addEventListener ("mousemove" , evt => { const mouseX = evt.offsetX ; const mouseY = evt.offsetY ; gsap.set (".cursor" , { x : mouseX, y : mouseY, }); gsap.to (".shape" , { x : mouseX, y : mouseY, stagger : -0.1 , }); }); } if (typeof gsap === "object" ) { initAnimation () } else { getScript ("!{url_for(theme.asset.gsap_js)}" ).then (initAnimation); }
最后在主题的配置内添加:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 Umami: enable: true umami_url_js: "你的Umami监控网站域名/script.js" umami_id: "Umami统计服务上的需要监控的网站ID" umami_api: "上方创建的API服务的域名"
效果展示: