首页
归档
友链
留言
关于
更多
投稿
捐赠
搜索
1
TP-link路由器使用SSH登录并获得root权限
2,844 阅读
2
ubuntu wget:unable to resolve host address解决方法
521 阅读
3
更新系统后出现“你没有权限在此位置保存文件请与管理员联系”解决办法
490 阅读
4
Onedrive云盘程序OneManager登录界面美化
480 阅读
5
Joe For Typecho主题实现自动更新
423 阅读
站点运维
系统运维
编程源码
工具分享
学习资料
设计技艺
业余无线电
生活碎记
登录
搜索
标签搜索
代码
json
typecho
添加
维护
全站
怪怪的科长
累计撰写
33
篇文章
累计收到
13
条评论
首页
栏目
站点运维
系统运维
编程源码
工具分享
学习资料
设计技艺
业余无线电
生活碎记
页面
归档
友链
留言
关于
投稿
捐赠
搜索到
19
篇与
» 站点运维
的结果
2026-04-29
Cloudflare R2 免费额度监控:自动推送额度告警,避免超量付费
作为大善人的忠实用户,R2 存储的免费额度(虽然只有10G)确实香,但总担心用量超标产生额外费用(其实完全没必要担心),手动每天查用量又太繁琐,于是动手搭建了一套自动监控系统,支持 Bark 实时推送、企业微信、飞书多渠道告警,全程零成本、零服务器,部署完彻底省心,实测稳定运行,今天把操作步骤做好记录,仅供需要的人参考。一、监控核心功能✅ 每日自动检测:配置凌晨1点定时执行,无需手动操作,后台静默运行;✅ 多渠道推送:支持 Bark 、企业微信、飞书,按需开启,填了变量就发、不填不发;✅ 防重复告警:解决同渠道重复推送问题,一次检测只发1条提醒;✅ 异常容错:API 调用失败、无 R2 桶均不会崩溃,日志可查问题;✅ 安全轻量:仅读取 R2 用量,无任何写入操作,API 令牌仅给只读权限,最小权限更安全。二、前置准备(3样东西,提前准备好)无需复杂工具,只要你有 Cloudflare 大善人账号,跟着准备以下3个核心内容即可:Cloudflare 账号 + 账号 ID(登录后可查,下文有具体路径)R2 只读权限 API Token(专门用于读取用量,不涉及修改/删除,安全可控)推送渠道(三选一或全选或不选):Bark:iPhone 端,需获取完整 Bark 推送 URL(格式:https://api.day.app/你的设备密钥)企业微信:需创建机器人,获取 Webhook Key飞书:创建自定义机器人,获取 Hook Key三、完整部署步骤步骤1:创建 Cloudflare Workers登录 Cloudflare 后台,找到「Workers \& Pages」,点击「创建应用程序」选择「从 Hello World\! 开始」,给 Worker 起个好记的名字(比如 r2-usage-monitor),名字仅用于识别,不影响功能点击「部署」,进入代码编辑界面(此时默认是 Hello World 代码,后续替换成我们的监控脚本)步骤2:创建 R2 只读 API TokenAPI Token 是脚本读取 R2 用量的凭证,必须只给只读权限,避免泄露后造成风险,步骤如下:访问 Cloudflare API Token 页面:https://dash.cloudflare.com/profile/api-tokens点击右上角「创建令牌」,选择「创建自定义令牌」→「开始使用」权限配置(重点):令牌名称:自定义即可权限类型:账户 → Workers R2 存储 → 读取权限等级:读取(仅读取,其他全部保持默认不用动)资源配置:帐户资源:选择你自己的 Cloudflare 账号有效期(TTL):不用设置有效期,避免后续过期需要重新创建点击「继续以显示摘要」,确认权限无误后,点击「创建令牌」生成 Token 后,立刻复制保存(仅显示一次,丢失需重新创建)步骤3:配置环境变量环境变量用于存储敏感信息(账号 ID、API Token、推送密钥),无需写在代码里,后续可随时修改,步骤如下:回到创建好的 Worker 详情页,找到「变量和机密」,点击「+ 添加」按以下列表添加变量,每个变量单独添加:变量名是否必填填写说明CLOUDFLARE_ACCOUNT_ID✅ 必填Cloudflare 账号 ID,登录后在地址栏中域名后的那一串字符CLOUDFLARE_API_TOKEN✅ 必填步骤2中创建的 R2 只读 API TokenWECOM_WEBHOOK_KEY❌ 可选企业微信机器人 Webhook 链接中「key=」后面的部分(不填则不推送)BARK_URL❌ 可选iPhone Bark 完整推送 URL(格式:https://api.day.app/设备密钥,不填则不推送)LARK_WEBHOOK_KEY❌ 可选飞书机器人 Hook 链接中「/hook/」后面的部分(不填则不推送)添加完成后,点击「保存」,环境变量配置完毕。步骤4:替换监控脚本回到 Worker 代码编辑界面,删除默认的 Hello World 代码,复制下面的代码,粘贴后点击「保存并部署」:export default { async scheduled(event, env, ctx) { ctx.waitUntil(r2UsageCheck(env, true)); }, async fetch(request, env) { // 拦截CF预检OPTIONS请求,杜绝一次访问两次执行 if (request.method === "OPTIONS") { return new Response(null, { status: 204 }); } const result = await r2UsageCheck(env, false); return new Response(result, { headers: { "Content-Type": "text/plain;charset=utf-8" } }); } }; const CONFIG = { freeLimitGB: 10, // R2免费总额度(默认10GB,无需修改) warnThresholdGB: 9 // 预警阈值(超过9GB触发推送,可自行调整) }; // 全局简易防重(单实例短时间防重复) let lastRunTime = 0; const COOLDOWN_MS = 5000; async function r2UsageCheck(env, isSchedule) { const now = Date.now(); // 5秒内重复执行直接拦截,彻底杜绝双击/双请求重复推送 if (now - lastRunTime < COOLDOWN_MS) { return "⏸️ 短时间内重复请求已拦截,防止重复推送"; } lastRunTime = now; const { CLOUDFLARE_ACCOUNT_ID, CLOUDFLARE_API_TOKEN } = env; if (!CLOUDFLARE_ACCOUNT_ID || !CLOUDFLARE_API_TOKEN) { return "❌ 缺少必要环境变量"; } try { const res = await fetch( `https://api.cloudflare.com/client/v4/accounts/${CLOUDFLARE_ACCOUNT_ID}/r2/buckets`, { headers: { Authorization: `Bearer ${CLOUDFLARE_API_TOKEN}` } } ); const data = await res.json(); if (!data.success) return "❌ API权限错误:" + JSON.stringify(data.errors); const buckets = Array.isArray(data.result) ? data.result : []; let totalBytes = 0; for (const bucket of buckets) { try { const usageRes = await fetch( `https://api.cloudflare.com/client/v4/accounts/${CLOUDFLARE_ACCOUNT_ID}/r2/buckets/${bucket.name}/usage`, { headers: { Authorization: `Bearer ${CLOUDFLARE_API_TOKEN}` }, signal: AbortSignal.timeout(3000) } ); const usage = await usageRes.json(); if (usage.success && usage.result?.size) { totalBytes += usage.result.size; } } catch (e) {} } const totalGB = totalBytes / 1073741824; const msg = `【R2存储用量告警】 当前已用:${totalGB.toFixed(2)} GB 免费额度:${CONFIG.freeLimitGB} GB 预警阈值:${CONFIG.warnThresholdGB} GB`; // 单次流程里 每个渠道只执行一次 if (totalGB >= CONFIG.warnThresholdGB) { if (env.BARK_URL) await sendBark(env.BARK_URL, msg); if (env.WECOM_WEBHOOK_KEY) await sendWeCom(env.WECOM_WEBHOOK_KEY, msg); if (env.LARK_WEBHOOK_KEY) await sendLark(env.LARK_WEBHOOK_KEY, msg); } return "✅ 执行成功\n" + msg; } catch (err) { return "❌ 监控异常:" + err.message; } } async function sendBark(barkUrl, text) { try { await fetch(`${barkUrl}/R2存储提醒/${encodeURIComponent(text)}`, { method: "GET" }); } catch {} } async function sendWeCom(key, text) { try { await fetch(`https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=${key}`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ msgtype: "text", text: { content: text } }) }); } catch {} } async function sendLark(key, text) { try { await fetch(`https://open.feishu.cn/open-apis/bot/v2/hook/${key}`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ msg_type: "text", content: { text } }) }); } catch {} }步骤5:配置定时触发器脚本部署完成后,需要配置定时任务,让它每天自动检测,步骤如下:在 Worker 详情页,找到「触发事件」,点击「+ 添加」触发器类型:选择「Cron 触发器」Cron 表达式:填写 0 1 \* \* \*(每天凌晨1点自动执行,可自行调整时间)点击「保存」,定时触发器配置完成四、常见问题排查(我踩过的坑)问题1:访问 Worker 地址超时(ERR\_CONNECTION\_TIMED\_OUT)原因:Cloudflare Workers 自带的 *.workers.dev 域名被墙了,属于正常现象,不影响定时任务执行。解决:无需处理,定时任务会在 Cloudflare 云端正常运行,若想本地测试,可尝试使用手机流量访问,或给 Worker 绑定自定义域名。问题2:日志空白,访问后无记录原因:网络拦截导致请求未到达 Cloudflare 服务器,或 API Token 权限错误。解决:切换手机流量访问 Worker 地址,同时检查 API Token 权限是否仅为 R2 读取,账号 ID 是否填写正确。问题3:同渠道收到两条重复通知原因:Cloudflare Workers 访问时会触发 OPTIONS 预检请求 + 正式请求,导致脚本执行两次。解决:本文提供的最终版代码已拦截预检请求,并添加了5秒冷却防重(可自己延长或缩短时间),无需额外操作。问题4:推送失败(Bark/企业微信收不到消息)排查步骤:检查环境变量是否填写正确(BARK\_URL 需完整,且不需要跟/,企业微信仅填 Key);查看 Worker 日志,是否有推送失败提示;用本文提供的测试代码(强制推送),验证推送渠道是否正常;五、测试方法(确保监控正常运行)部署完成后,可通过以下方式测试,确保功能正常:把脚本中的warnThresholdGB: 9改为0,访问 Worker 地址,查看 Bark/企业微信是否收到推送;测试完成后,将参数恢复即可;查看 Worker 日志(Observability → 实时日志),确认脚本执行成功。六、总结这套 R2 监控系统,全程零成本、零服务器,部署一次,终身省心。每天自动检测用量,超标后实时推送提醒,再也不用手动登录 Cloudflare 查用量,避免不小心超标产生费用(虽然对于小破站来讲并不会超标)。核心优势:配置简单、安全轻量、多渠道推送、防重复告警,新手也能轻松上手(最主要是不用花钱)如果你在部署过程中遇到任何问题,欢迎在评论区交流!
2026年04月29日
7 阅读
0 评论
0 点赞
2023-03-23
升级到Typecho v1.2.0后台提示版本更新去除方法
不得不说Typecho的轻量和坚挺,时隔多年终于有了新版本了,Typecho迎来了v1.2.0版本的迭代,今天我也是终于决定将博客版本更新,但是按官方给定的操作流程更新后在后台还是看到提示升级。 当然,有问题就找办法解决问题,Typecho的这个Bug官方也给出了去除的办法,只需要修改代码的判断逻辑即可解决。 文件路径: /var/Widget/Ajax.php 判断位置: 第 62 行 修改内容: 将 >= 改为 > 错误代码:/* 错误代码 */ if ( isset($json['release']) && preg_match("/^[0-9\.]+$/", $json['release']) && version_compare($json['release'], $version, '>=') ) 更正代码:/* 更正代码 */ if ( isset($json['release']) && preg_match("/^[0-9\.]+$/", $json['release']) && version_compare($json['release'], $version, '>') ) 原因在于按照正常的判断逻辑来讲,只有当发行版本号大于当前版本号时才进行提醒,而不是大于或等于当前版本号都需要提醒。 至此,更新提示问题解决完毕,记录下来供大家参考。
2023年03月23日
212 阅读
0 评论
0 点赞
2023-03-22
一键开启跳转Typecho博客维护状态
前言 因为经常捣鼓网站,有时候会直接在服务器上热更新,这样会导致用户体验很不好所以就想到了设置一个维护通知页面,告知访问的用户正在维护,防止用户因无法访问放弃访问本站。效果展示操作步骤 本教程基于Joe主题,当然其他Typecho主题也可以使用,代码是固定的,但是方法是灵活的,期待您的灵感大爆发!增加开关 在主题目录下的 functions.php 里添加以下代码(因为我引入了自定义配置文件,所以我是放在 public/custom.php 文件里的)添加代码$Maintain = new Typecho_Widget_Helper_Form_Element_Select( 'Maintain', array( 'off' => '关闭(默认)', 'on' => '开启', ), 'off', '是否开启全站维护功能', '介绍:开启后,全站进入维护状态' ); $Maintain->setAttribute('class', 'joe_content joe_global'); $form->addInput($Maintain->multiMode());添加全局跳转因为我一般更新都是整站屏蔽的,所以我这里是添加的全局跳转,直接在public/header.php顶部添加以下代码如果你只想某些页面跳转,比如只想跳转首页,你可以在index.php添加下面的代码<!-- 维护跳转 --> <?php if(Helper::options()->Maintain === 'on') { header("Location: Maintain.html"); exit; } ?>上传维护页面将404/维护单页上传到Typecho主程序的根目录,记得把文件名改为Maintain.html(区分大小写)。
2023年03月22日
216 阅读
0 评论
0 点赞
2023-03-21
提高后台入口安全避免爆破之Typecho后台入口修改方法
{card-describe title="前言"} 众所周知,通常网站的后台入口均为/admin,Typecho也不例外,但默认路径的网站后台容易被他人尝试爆破,所以为了提高网站后台的安全性,建议定期修改后台地址以及后台账号和密码避免被暴露。{/card-describe}修改步骤 通过ftp进入虚拟主机/服务器,修改admin文件夹的名称(若想通过http(s)://yourdomain/xx-login访问来登录后台),则可以把admin文件夹重命名成xx-login。 在网站根目录下找到config.inc.php文件,并修改大概在第20行的后台路径(相对路径),只要将__TYPECHO_ADMIN_DIR__常量的值改成你想要的就行了。 例如你想通过访问http(s)://yourdomain/xx-login来登录后台,你就可以将define('TYPECHO_ADMIN_DIR','/admin/'); 用这行代码换掉:define('TYPECHO_ADMIN_DIR','/xx-login/'); 至此,Typecho后台入口路径修改成功,可以使用新入口登录后台(当然你还可以做一个admin路径的蜜獾页面迷惑别人)。
2023年03月21日
2 阅读
0 评论
0 点赞
2023-03-20
Typecho博客图床CDN变更后如何批量更换全站博文插图链接
由于本站的所有图片均存储在Github,之前一直都是用jsDelivr的CDN来作为静态资源服务器(主要是免费、超快),结果前段时间发现来自Github的文章插图均已失效,通过搜索得知原来是2021年12月20日jsDelivr在大陆的CDN节点被关闭,而且ICP备案已经被注销,在2022年4月28日又遭到DNS污染,自此大陆无法正常访问jsDelivr,从而导致大批网站工作失常,很不幸我的小破站就是其中一个~ 据说很多小伙伴的博客还因为缺失CSS文件直接导致网站排版错乱。 ::(滑稽) 那么这种问题该如何解决呢?我找到了几种办法:解决办法使用cdn.jsdelivr.net未受污染的子域子域名提供来源fastly.jsdelivr.net由 Fastly 提供gcore.jsdelivr.net由 G-Core 提供testingcf.jsdelivr.net由 CloudFlare 提供国内的云存储/资源库资源平台备注七牛云域名需要备案又拍云域名需要备案阿里云域名需要备案多吉云域名需要备案本地存储 将所有资源下载后存储到本地空间/服务器。方案选择 第一种最为简单,只需将博客中所有的文件中的cdn.jsDelivr.net替换为子域名即可; 第二种对于我来讲弊端相当明显,那就是域名需要备案,直接放弃; 第三种是将所有文件存储到本地端,然后替换为本地路径,但是把所有文件存储到本地相应就会增加空间占用。 最终决定选择简单的,第一种直接替换博客中的域名,那么全站那么多文章一篇一篇修改那不是慢且麻烦,如何批量修改文章中那么多的图片地址呢?phpMyAdmin管理工具 由于本站使用虚拟主机,所以可以登录数据库管理phpMyAdmin进行修改。 首先我们需要确定要更换的地址,比如原本使用的地址是https://cdn.jsdelivr.net/gh/@用户名/仓库名/文件夹名/文件名.jpg,那么只需要批量将原本的https://cdn.jsdelivr.net/gh/@用户名/仓库名/文件夹名修改为https://gcore.jsdelivr.net/gh/@用户名/仓库名/文件夹名即可。 打开数据库管理工具,选择Typecho的数据库,选择typecho_contents表,点击SQL,执行下列sql语句。/* 更改文章内图片 */ UPDATE typecho_contents SET text = REPLACE(text,'旧域名地址','新域名地址');/* 更改封面图片 */ UPDATE typecho_fields SET str_value = REPLACE(str_value,'旧域名地址','新域名地址'); 执行后即显示批量更改成功,此时就可以回到博客的文章中查看图片链接是否正确、图片是否正常显示了~知识延伸修改 typecho_options 表将网站的设置里的域名替换成新的域名:UPDATE `typecho_options` SET `value` = '新域名地址' WHERE `typecho_options`.`name` = 'siteUrl' AND `typecho_options`.`user` =0;修改 typecho_users 表将管理员的个人网站进行替换:UPDATE `typecho_users` SET `url` = REPLACE(`url`,'旧域名地址','新域名地址');修改 typecho_comments 表对评论中的管理员的域名,和评论中的旧域名进行替换:UPDATE `typecho_comments` SET `url` = REPLACE(`url`,'旧域名地址','新域名地址');UPDATE `typecho_comments` SET `text` = REPLACE(`text`,'旧域名地址','新域名地址');如果使用域名邮箱也可以进行更换:UPDATE `typecho_comments` SET `mail` = REPLACE(`mail`,'旧域名地址','新域名地址');
2023年03月20日
132 阅读
0 评论
0 点赞
1
2
...
4