大部分内容转自https://apepine.com/archives/273 和哪吒官方WIKI
选个国际互联稍好的小机安装探针面板
1、更新系统:
1
| apk update && apk upgrade
|
2、cloudflare解析域名 开启小黄云
3、先安装工具,安装wget,sudo等
1
| apk add curl wget sudo unzip
|
4、哪吒面板安装
1
| curl -L https://raw.githubusercontent.com/nezhahq/scripts/refs/heads/main/install.sh -o nezha.sh && chmod +x nezha.sh && sudo ./nezha.sh
|
5、安装nginx
在文件路径etc/nginx 中找到nginx.config文件,全部替换,替换以下代码,只修改自己哪吒监控网站域名(刚刚解析域名)
进入文件目录:cd /etc/nginx 创建并编辑文件:nano nginx.conf 删除里面内容ctrl+k
nginx配置文件:
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
| #user nobody; worker_processes 1;
#error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info;
#pid logs/nginx.pid;
events { worker_connections 1024; }
http { include mime.types; default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" ' # '$status $body_bytes_sent "$http_referer" ' # '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on; #tcp_nopush on;
#keepalive_timeout 0; keepalive_timeout 65;
#gzip on;
server { listen [::]:80; #监听端口 IPv6 listen [::]:443 ssl; #监听端口 带SSL iPv6 #listen 80; #ipv4 #listen 443 ssl; #ipv4 server_name nezha.apepine.top; #填写监控网站域名 index index.php index.html index.htm default.php default.htm default.html; root /home/web/nezha; #index root部分随便写 没用的 #SSL-START SSL相关配置,请勿删除或修改下一行带注释的404规则 #error_page 404/404.html; ssl_certificate /etc/ssl/private/fullchain.cer; #SSL证书文件 ssl_certificate_key /etc/ssl/private/private.key; #SSL密钥文件 ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3; ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; add_header Strict-Transport-Security "max-age=31536000"; error_page 497 https://$host$request_uri; #以下是反代内容 如果有特别设置端口记得修改 location / { proxy_pass http://127.0.0.1:8008; proxy_set_header Host $host; proxy_set_header Origin https://$host; proxy_set_header nz-realip $http_CF_Connecting_IP; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; } location ~ ^/(ws|terminal/.+|file/.+)$ { proxy_pass http://127.0.0.1:8008; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; proxy_set_header Host $http_host; } } }
|
6、打开cloudflaer,在解析域名设置那里,打开网络,WebSockets打开 gRPC打开
打开ssl设置,选择源服务器,创建证书,把证书和密钥保存备用
打开概述 配置ssl为完全严格 边缘证书 始终使用 HTTPS
进入文件管理,路径/etc/ssl/private 命令:
创建证书文件名fullchain.cer,粘贴刚刚申请证书 命令:
创建私钥文件名private.key 粘贴刚刚申请密钥 命令:
重启nginx
1
| rc-service nginx restart && rc-service nginx status
|
Nginx 开机自启
7、现在,可以成功访问域名,登录哪吒后台 改密码
Agent对接地址【域名/IP:端口】:需要用IP:端口,且下面Agent使用TLS连接,不能勾选,只有这样才能解决服务器装上探针之后后台不显示服务器的问题
8、复制对应系统命令,到被监控端粘贴回车
如果监控端服务器为纯ipv6,那么被监控端也需要ipv6,可以添加wrap,添加ipv6出口
安装wrap
1
| wget -N https://gitlab.com/fscarmen/warp/-/raw/main/menu.sh && bash menu.sh [option] [lisence/url/token]
|
9、检查哪吒监控是否启动
Alpine系统的检查输入命令查看一下面板有没有启动:
1
| rc-service nezha-dashboard status
|
如果没有启动就输入命令启动服务:
1
| rc-service nezha-dashboard start
|
10.界面美化
管理后台-系统设置-自定义代码(样式和脚本)
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 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
| <script> /* 这部分这几个挂在 window 下的变量是哪吒内置的, 详见 https://nezha.wiki/guide/settings.html#%E8%87%AA%E5%AE%9A%E4%B9%89%E4%BB%A3%E7%A0%81 */ window.CustomBackgroundImage = ''; /* PC 端背景图 */ window.CustomMobileBackgroundImage = 'p'; /* 移动端背景图 */ window.CustomLogo = ''; /* 页面左上角和标题栏展示的 Logo */ window.CustomDesc = '机不在多 够用就好'; /* 页面左上角副标题 */ window.ShowNetTransfer = true; /* 服务器卡片是否显示上下行流量, 默认不显示 */ /* window.DisableAnimatedMan = true; */ window.CustomIllustration = 'https://s2.loli.net/2024/12/24/fj3EXY7umsyR9NW.webp'; window.FixedTopServerName = true; /* 是否固定顶部显示服务器名称, 默认不固定 */ window.CustomLinks = '[{\"link\":\"https://www.digs.eu.org/\",\"name\":\"首页\"},{\"link\":\"https://www.digs.eu.org/\",\"name\":\"博客\"}]'; /* 自定义导航栏链接 */
/* 自定义字体, 注意需要同步修改下方 CSS 中的 font-family */ var link = document.createElement('link'); link.rel = 'stylesheet'; link.href = 'https://font.sec.miui.com/font/css?family=MiSans:400,700:MiSans'; // MiSans // link.href = 'https://npm.elemecdn.com/lxgw-wenkai-screen-webfont@1.7.0/style.css'; // 霞鹜文楷, font-family: 'LXGW WenKai Screen' document.head.appendChild(link); </script> <style> /* 自定义字体 */ * { font-family: 'MiSans'; } h1, h2, h3, h4, h5 { font-family: 'MiSans', sans-serif; }
/* 背景压暗和模糊, 开了背景图建议开启 */ .dark .bg-cover::after { content: ''; position: absolute; inset: 0; backdrop-filter: blur(2px); background-color: rgba(0, 0, 0, 0.1); } .light .bg-cover::after { content: ''; position: absolute; inset: 0; backdrop-filter: blur(2px); background-color: rgba(255, 255, 255, 0); }
footer { display: none; } </style> <script> window.FixedTopServerName = true; /* 是否固定顶部显示服务器名称, 默认不固定 */ setInterval(function() { function formatFileSize(bytes) { if (bytes === 0) return { value: '0', unit: 'B' }; const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB']; let unitIndex = 0; let size = bytes; while (size >= 1024 && unitIndex < units.length - 1) { size /= 1024; unitIndex++; } let decimalPlaces = 1; if (unitIndex === 0) decimalPlaces = 0; return { value: size.toFixed(decimalPlaces), unit: units[unitIndex] }; } function calculatePercentage(used, total) { if (typeof used === 'string') used = Number(used); if (typeof total === 'string') total = Number(total); if (used > 1e15 || total > 1e15) { used = used / 1e10; total = total / 1e10; } return (used / total * 100).toFixed(1); } fetch('/api/v1/service') .then(response => response.json()) .then(data => { if (data.success) { const trafficData = data.data.cycle_transfer_stats; const serverMap = new Map(); for (const cycleId in trafficData) { const cycle = trafficData[cycleId]; if (cycle.server_name && cycle.transfer) { for (const serverId in cycle.server_name) { const serverName = cycle.server_name[serverId]; const transfer = cycle.transfer[serverId]; const max = cycle.max; if (serverName && transfer !== undefined && max) { serverMap.set(serverName, { id: serverId, // 服务器ID transfer: transfer, // 已使用流量(字节) max: max, // 最大流量(字节) name: cycle.name // 流量包名称 }); } } } } serverMap.forEach((serverData, serverName) => { const targetElement = Array.from(document.querySelectorAll('section.grid.items-center.gap-2')).find(el => el.textContent.trim().includes(serverName)); if (targetElement) { const usedFormatted = formatFileSize(serverData.transfer); const totalFormatted = formatFileSize(serverData.max); const percentage = calculatePercentage(serverData.transfer, serverData.max); const uniqueClassName = 'traffic-stats-for-server-' + serverData.id; const insertedElement = targetElement.parentNode.querySelector('.' + uniqueClassName); if (insertedElement) { const usedSpan = insertedElement.querySelector('.used-traffic'); const usedUnitSpan = insertedElement.querySelector('.used-unit'); const totalSpan = insertedElement.querySelector('.total-traffic'); const totalUnitSpan = insertedElement.querySelector('.total-unit'); const percentageSpan = insertedElement.querySelector('.percentage-value'); const progressBar = insertedElement.querySelector('.progress-bar'); if (usedSpan) usedSpan.textContent = usedFormatted.value; if (usedUnitSpan) usedUnitSpan.textContent = usedFormatted.unit; if (totalSpan) totalSpan.textContent = totalFormatted.value; if (totalUnitSpan) totalUnitSpan.textContent = totalFormatted.unit; if (percentageSpan) percentageSpan.textContent = percentage + '%'; if (progressBar) progressBar.style.width = percentage + '%'; return; } let currentElement = targetElement; for (let i = 0; i < 2; i++) { currentElement = currentElement.nextElementSibling; if (!currentElement) { currentElement = targetElement; currentElement = currentElement.nextElementSibling; } } const newElement = document.createElement('div'); newElement.classList.add('space-y-1.5', 'new-inserted-element', uniqueClassName); newElement.style.width = '100%'; newElement.innerHTML = ` <div class="flex items-center justify-between"> <div class="flex items-baseline gap-1"> <span class="text-sm font-medium text-neutral-800 dark:text-neutral-200 used-traffic">${usedFormatted.value}</span> <span class="text-sm font-medium text-neutral-800 dark:text-neutral-200 used-unit">${usedFormatted.unit}</span> <span class="text-xs text-neutral-500 dark:text-neutral-400">/ </span> <span class="text-xs text-neutral-500 dark:text-neutral-400 total-traffic">${totalFormatted.value}</span> <span class="text-xs text-neutral-500 dark:text-neutral-400 total-unit">${totalFormatted.unit}</span> </div> <span class="text-xs font-medium text-neutral-600 dark:text-neutral-300 percentage-value">${percentage}%</span> </div> <div class="relative h-1.5"> <div class="absolute inset-0 bg-neutral-100 dark:bg-neutral-800 rounded-full"></div> <div class="absolute inset-0 bg-emerald-500 rounded-full transition-all duration-300 progress-bar" style="width: ${percentage}%;"></div> </div> `; currentElement.insertAdjacentElement('afterend', newElement); } else { console.log(`没有找到服务器 ${serverName}(ID: ${serverData.id}) 的元素`); } }); } else { console.log('API请求成功但返回数据不正确'); } }) .catch(error => { console.error('获取流量数据失败:', error); }); }, 3000); </script>
|
11.通知
通知方式示例
Telegram 示例
获取 URL 参数
获取机器人 Token:与 @BotFather 对话,发送 /newbot 创建新机器人,获取 Token。
获取用户 ID:与 @userinfobot 对话,获取你的用户 ID。
与机器人对话:先与新创建的机器人发送一条消息,确保机器人可以发送消息给你。
通知配置:
名称:Telegram
1
| URL:https://api.telegram.org/bot<你的机器人Token>/sendMessage?chat_id=<你的用户ID>&text=#NEZHA#
|
请求方式:GET
请求类型:默认
Body:空
注意:将 <你的机器人Token> 和 <你的用户ID> 替换为实际值。
警报规则示例
离线通知:
名称:离线通知
规则:
1 2
| json [{"type": "offline", "duration": 10}]
|
启用:√
CPU 和内存监控:
名称:CPU+内存
规则:
1 2 3 4 5
| json [ {"type": "cpu", "min": 0, "max": 50, "duration": 10}, {"type": "memory", "min": 20, "max": 0, "duration": 20} ]
|
启用:√
记得先登录到后台,系统设置-分组-通知 添加一条通知组,否则telegram通知不生效。