前言
随着Google推进90天证书步伐的加快,已有几家机构发布了调整通知,缩短有效期已经成为了板上钉钉的事。
主流的解决办法是使用证书自动化部署,但受限于部分设备不方便安装ACME以及可能出现的更新失败,还是得搭一个证书监控应用。
也借由这个契机,把一直想做但没做的网站状态监控一并解决了,摆脱掉"网站挂了全靠用户通知"的局面。
几番寻找,发现Uptime Kuma正好符合规定,不止支持监控证书和网站,还支持DNS、Ping、Radis等应用的监控,而且通知方式也多。
美中不足的是不支持接入腾讯的SMS,所以本次部署还会要自己写一个接口来做适配。
计划
通过Docker部署Uptime。
使用Python实现一个WebHook接口,用于发送通知短信。
安装Nginx反代Uptime和WebHook接口,并绑定域名,更加美观。
不使用宝塔等面板程序。
步骤
安装Docker
这里选择使用Lighthouse自带的Docker镜像。
既省去安装的时间,后期也可以在控制台直接看服内得多Docker容器,十分方便。
安装Uptime Kuma
首先,启动docker
service docker start
创建放数据的文件夹
mkdir -p /root/docker/uptime/data
执行命令拉去镜像并部署
docker run -d --restart=always -p 3001:3001 -v uptime-kuma:/root/docker/uptime/data --name uptime-kuma louislam/uptime-kuma:1
UFW放通3001端口
ufw allow 3001
轻量防火墙放通3001端口
这时候,访问:http://[IP]:3001
就能看到uptime的管理页面了
开通并新建短信签名与模板
新建签名
进入短信控制台,点击国内短信
->签名管理
新建一个签名
选择网站
和公众号
最容易过,需要注意的是网站需要是已备案的网站
审核通过后记下签名ID
新建模板
点击正文模板管理
创建一个新的模板,同样的,审核通过后记下模板ID
这里提供一个示例
模板名称: 服务器故障通知
短信内容:
服务器故障通知
监控名称: {1}
故障状态: {2}
故障时间: {3}
故障信息: {4}申请说明:
用于监控程序发送服务器故障提醒,在服务故障时提醒管理员进行排查。
如下为示例:
服务器故障通知
监控名称: 主站
故障状态: 0
故障时间: 2023-11-23 17:23:19
故障信息: 访问超时
注意,
\n
在短信内容中会被当成文本输出
获取应用ID
编写webhook接口对接短信推送
用python写一个接口,用来给uptime做webhook告警推送
import hashlib, hmac, json, time, requests, uvicorn, re
from datetime import datetime
from fastapi import FastAPI,Request短信应用ID
SmsSdkAppId = ""
签名文本
SignName = ""
模板ID
TemplateId = ""
手机号
PhoneNumber = ""
API密钥
SecretId=""
SecretKey=""app = FastAPI()
def qcloud_v3_post(SecretId,SecretKey,service,bodyDict,headersDict):
secret_id = SecretId
secret_key = SecretKeyservice = service algorithm = "TC3-HMAC-SHA256" timestamp = int(time.time()) date = datetime.utcfromtimestamp(timestamp).strftime("%Y-%m-%d") http_request_method = "POST" canonical_uri = "/" canonical_querystring = "" headersDict = {k: v for k, v in sorted(headersDict.items(), key=lambda x: x[0])} signed_headers = "" canonical_headers = "" for dict_key in headersDict: signed_headers = signed_headers + dict_key.lower() + ";" signed_headers = signed_headers[:-1] for dict_value in headersDict: canonical_headers = canonical_headers + dict_value.lower() + ":" + headersDict[dict_value].lower() + "\n" payload = json.dumps(bodyDict) hashed_request_payload = hashlib.sha256(payload.encode("utf-8")).hexdigest() canonical_request = (http_request_method + "\n" + canonical_uri + "\n" + canonical_querystring + "\n" + canonical_headers + "\n" + signed_headers + "\n" + hashed_request_payload) credential_scope = date + "/" + service + "/" + "tc3_request" hashed_canonical_request = hashlib.sha256(canonical_request.encode("utf-8")).hexdigest() string_to_sign = (algorithm + "\n" + str(timestamp) + "\n" + credential_scope + "\n" + hashed_canonical_request) def sign(key, msg): return hmac.new(key, msg.encode("utf-8"), hashlib.sha256).digest() secret_date = sign(("TC3" + secret_key).encode("utf-8"), date) secret_service = sign(secret_date, service) secret_signing = sign(secret_service, "tc3_request") signature = hmac.new(secret_signing, string_to_sign.encode("utf-8"), hashlib.sha256).hexdigest() authorization = (algorithm + " " + "Credential=" + secret_id + "/" + credential_scope + ", " + "SignedHeaders=" + signed_headers + ", " + "Signature=" + signature) headersDict["X-TC-Timestamp"] = str(timestamp) headersDict["Authorization"] = authorization return headersDict
@app.post("/sendsms")
async def sendsms(request: Request):
content_type = request.headers['Content-Type']if content_type != "application/json": return {"code":-1,"msg":"类型不正确"} body = await request.body() try: body_json = json.loads(body) except Exception as e: return {"code":-1,"msg":str(e)} name = body_json["monitor"]["name"] status = body_json["heartbeat"]["status"] time = body_json["heartbeat"]["time"] msg = body_json["msg"] Service = "sms" host = "sms.tencentcloudapi.com" protocol = "https://" apiurl = protocol + host PhoneNumberSet = [PhoneNumber] name = re.sub(r'(\d+).(\d+).\d+.\d+', '*.*.*.*', name) msg = re.sub(r'(\d+).(\d+).\d+.\d+', '*.*.*.*', msg) name = re.sub(r'[^\u4e00-\u9fa5a-zA-Z0-9\[\]\s]', '', name) msg = re.sub(r'[^\u4e00-\u9fa5a-zA-Z0-9\[\]\s]', '', msg) TemplateParamSet = [name,str(status),time,msg] SessionContext = "uptime" payload = { "PhoneNumberSet": PhoneNumberSet, "SmsSdkAppId" : SmsSdkAppId, "SignName" : SignName, "TemplateId" : TemplateId, "TemplateParamSet": TemplateParamSet, "SessionContext" : SessionContext } headersPending = { 'Host': host, 'Content-Type': 'application/json', 'X-TC-Action': 'SendSms', 'X-TC-Version': '2021-01-11', 'X-TC-Region': 'ap-guangzhou', } headersSend = qcloud_v3_post(SecretId,SecretKey,Service,payload,headersPending) r = requests.post(apiurl,json=payload,headers=headersSend) return {"code":200,"msg":"OK"}
if name == 'main':
uvicorn.run(app=app, host="0.0.0.0", port=8080)
部署WebHook接口
安装依赖库
轻量Docker镜像自带了Python 3.8.2,但没有安装pip,所以要先安装下
apt install python3-pip
然后安装依赖库
python3 -m pip install requests fastapi uvicorn
部署
使用nano直接新建一个sms.py文件,把上面的程序粘贴上去
nano sms.py
试运行
python3 sms.py
看到如下结果表示依赖没有问题:
后台运行sms.py
nohup python3 sms.py &
安装并配置Nginx反代
安装Nginx
apt install nginx
service nginx start
安装成功后,在浏览器输入IP可以看到如下网页
配置反向代理
进入Nginx配置文件存放目录
cd /etc/nginx/conf.d
配置uptime的反向代理
新建配置文件
nano uptime.conf
输入如下配置
server
{
listen 80;
server_name [需要绑定到uptime的域名];
location / {
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
配置sms webhook的反向代理
server
{
listen 80;
server_name [需要绑定到webhook的域名];
location / {
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
重启Nginx使配置生效
service nginx restart
测试设置结果
分别访问两个域名,可以看到已经设置成功了
uptime
webhook
因为接口使用的是POST,使用浏览器测试是GET请求,所以显示如下内容是正常的,不影响实际使用
uptime的使用与接入短信通知
新建监控项
登录以后,直接点击左上角新建监控项
这里拿腾讯云举例
在高级
处可以找到证书通知
除了网站,uptime还能监控许多不同类型的服务
设置通知
找到webhook
填入刚才部署的webhook的url
注意不用点右下角的测试,右下角的测试发送的内容不完整,是无法收到信息的
完成设置
保存通知设置和监控项设置
设置完成后即可看到当前网站的监控状态。
点击证书有效期
还能看到网站当前的证书信息
使用体验
相比于CVM,Lighthouse不管是价格还是操作体验上都要舒服得多。
换成CVM,同样的2C2G-3M不限流量要103
换成按量计费0.8元/G,200G要160,还没算配置得38
即使使用共享流量包,按37元/50G算,200G也得148元。
而且操作还麻烦,购买页面和CVM是分开的,你得到VPC里才能找到购买和管理入口
而换成Lighthouse,流量使用状况一目了然,套餐不够用点一下升级重启就完事了
几台Lighthouse之间也不用考虑什么VPC直接默认内网互通,对于普通用户来说十分方便。