/test | 测试是否为只读系统 |
70 |
71 | ## 在 Glitch 部署重点
72 |
73 | 这里只作重点的展示,更详细可以参考项目: https://github.com/fscarmen2/X-for-Glitch
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 | ## 在 Daki 部署重点
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 | ## ttyd webssh / filebrowser webftp 的部署
98 |
99 | * 原理
100 | ```
101 | +---------+ argo +---------+ http +--------+ ssh +-----------+
102 | | browser | <==========> | CF edge | <==========> | ttyd | <=======> | ssh server|
103 | +---------+ argo +---------+ websocket +--------+ ssh +-----------+
104 |
105 | +---------+ argo +---------+ http +--------------+ ftp +-----------+
106 | | browser | <==========> | CF edge | <==========> | filebrowser | <=======> | ftp server|
107 | +---------+ argo +---------+ websocket +--------------+ ftp +-----------+
108 |
109 | ```
110 |
111 | * 使用 Json 方式建的隧道
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 | ## 鸣谢下列作者的文章和项目:
122 | * 前端 JS 在大佬 Nike Jeff 的项目 基础上,为了通用性和扩展功能作修改,https://github.com/hrzyang/glitch-trojan
123 | * 后端全部原创,如转载须注明来源。
124 |
125 | ## 免责声明:
126 | * 本程序仅供学习了解, 非盈利目的,请于下载后 24 小时内删除, 不得用作任何商业用途, 文字、数据及图片均有所属版权, 如转载须注明来源。
127 | * 使用本程序必循遵守部署免责声明。使用本程序必循遵守部署服务器所在地、所在国家和用户所在国家的法律法规, 程序作者不对使用者任何不当行为负责。
--------------------------------------------------------------------------------
/entrypoint.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # 设置各变量,WS 路径前缀。(注意:伪装路径不需要 / 符号开始,为避免不必要的麻烦,请不要使用特殊符号.)
4 | WSPATH=${WSPATH:-'argo'}
5 | UUID=${UUID:-'de04add9-5c68-8bab-950c-08cd5320df18'}
6 | WEB_USERNAME=${WEB_USERNAME:-'admin'}
7 | WEB_PASSWORD=${WEB_PASSWORD:-'password'}
8 |
9 | # 哪吒4个参数,ssl/tls 看是否需要,不需要的话可以留空,删除或在这4行最前面加 # 以注释
10 | NEZHA_SERVER="$NEZHA_SERVER"
11 | NEZHA_PORT="$NEZHA_PORT"
12 | NEZHA_KEY="$NEZHA_KEY"
13 | NEZHA_TLS="$NEZHA_TLS"
14 |
15 | # Argo 固定域名隧道的两个参数,这个可以填 Json 内容或 Token 内容,不需要的话可以留空,删除或在这三行最前面加 # 以注释
16 | ARGO_AUTH=''
17 | ARGO_DOMAIN="$ARGO_DOMAIN"
18 |
19 | # ttyd / filebrowser argo 域名
20 | SSH_DOMAIN="$SSH_AUTH"
21 | FTP_DOMAIN="$FTP_AUTH"
22 |
23 | # 安装系统依赖
24 | check_dependencies() {
25 | DEPS_CHECK=("wget" "unzip" "ss" "tar")
26 | DEPS_INSTALL=(" wget" " unzip" " iproute2" "tar")
27 | for ((i=0;i<${#DEPS_CHECK[@]};i++)); do [[ ! $(type -p ${DEPS_CHECK[i]}) ]] && DEPS+=${DEPS_INSTALL[i]}; done
28 | [ -n "$DEPS" ] && { apt-get update >/dev/null 2>&1; apt-get install -y $DEPS >/dev/null 2>&1; }
29 | }
30 |
31 | # 生成 X 配置文件
32 | generate_config() {
33 | cat > config.json << EOF
34 | {
35 | "log":{
36 | "access":"/dev/null",
37 | "error":"/dev/null",
38 | "loglevel":"none"
39 | },
40 | "inbounds":[
41 | {
42 | "port":8080,
43 | "protocol":"vless",
44 | "settings":{
45 | "clients":[
46 | {
47 | "id":"${UUID}",
48 | "flow":"xtls-rprx-vision"
49 | }
50 | ],
51 | "decryption":"none",
52 | "fallbacks":[
53 | {
54 | "dest":3001
55 | },
56 | {
57 | "path":"/${WSPATH}-vless",
58 | "dest":3002
59 | },
60 | {
61 | "path":"/${WSPATH}-vmess",
62 | "dest":3003
63 | },
64 | {
65 | "path":"/${WSPATH}-trojan",
66 | "dest":3004
67 | },
68 | {
69 | "path":"/${WSPATH}-shadowsocks",
70 | "dest":3005
71 | }
72 | ]
73 | },
74 | "streamSettings":{
75 | "network":"tcp"
76 | }
77 | },
78 | {
79 | "port":3001,
80 | "listen":"127.0.0.1",
81 | "protocol":"vless",
82 | "settings":{
83 | "clients":[
84 | {
85 | "id":"${UUID}"
86 | }
87 | ],
88 | "decryption":"none"
89 | },
90 | "streamSettings":{
91 | "network":"ws",
92 | "security":"none"
93 | }
94 | },
95 | {
96 | "port":3002,
97 | "listen":"127.0.0.1",
98 | "protocol":"vless",
99 | "settings":{
100 | "clients":[
101 | {
102 | "id":"${UUID}",
103 | "level":0
104 | }
105 | ],
106 | "decryption":"none"
107 | },
108 | "streamSettings":{
109 | "network":"ws",
110 | "security":"none",
111 | "wsSettings":{
112 | "path":"/${WSPATH}-vless"
113 | }
114 | },
115 | "sniffing":{
116 | "enabled":true,
117 | "destOverride":[
118 | "http",
119 | "tls",
120 | "quic"
121 | ],
122 | "metadataOnly":false
123 | }
124 | },
125 | {
126 | "port":3003,
127 | "listen":"127.0.0.1",
128 | "protocol":"vmess",
129 | "settings":{
130 | "clients":[
131 | {
132 | "id":"${UUID}",
133 | "alterId":0
134 | }
135 | ]
136 | },
137 | "streamSettings":{
138 | "network":"ws",
139 | "wsSettings":{
140 | "path":"/${WSPATH}-vmess"
141 | }
142 | },
143 | "sniffing":{
144 | "enabled":true,
145 | "destOverride":[
146 | "http",
147 | "tls",
148 | "quic"
149 | ],
150 | "metadataOnly":false
151 | }
152 | },
153 | {
154 | "port":3004,
155 | "listen":"127.0.0.1",
156 | "protocol":"trojan",
157 | "settings":{
158 | "clients":[
159 | {
160 | "password":"${UUID}"
161 | }
162 | ]
163 | },
164 | "streamSettings":{
165 | "network":"ws",
166 | "security":"none",
167 | "wsSettings":{
168 | "path":"/${WSPATH}-trojan"
169 | }
170 | },
171 | "sniffing":{
172 | "enabled":true,
173 | "destOverride":[
174 | "http",
175 | "tls",
176 | "quic"
177 | ],
178 | "metadataOnly":false
179 | }
180 | },
181 | {
182 | "port":3005,
183 | "listen":"127.0.0.1",
184 | "protocol":"shadowsocks",
185 | "settings":{
186 | "clients":[
187 | {
188 | "method":"chacha20-ietf-poly1305",
189 | "password":"${UUID}"
190 | }
191 | ],
192 | "decryption":"none"
193 | },
194 | "streamSettings":{
195 | "network":"ws",
196 | "wsSettings":{
197 | "path":"/${WSPATH}-shadowsocks"
198 | }
199 | },
200 | "sniffing":{
201 | "enabled":true,
202 | "destOverride":[
203 | "http",
204 | "tls",
205 | "quic"
206 | ],
207 | "metadataOnly":false
208 | }
209 | }
210 | ],
211 | "dns":{
212 | "servers":[
213 | "https+local://8.8.8.8/dns-query"
214 | ]
215 | },
216 | "outbounds":[
217 | {
218 | "protocol":"freedom"
219 | },
220 | {
221 | "tag":"WARP",
222 | "protocol":"wireguard",
223 | "settings":{
224 | "secretKey":"YFYOAdbw1bKTHlNNi+aEjBM3BO7unuFC5rOkMRAz9XY=",
225 | "address":[
226 | "172.16.0.2/32",
227 | "2606:4700:110:8a36:df92:102a:9602:fa18/128"
228 | ],
229 | "peers":[
230 | {
231 | "publicKey":"bmXOC+F1FxEMF9dyiK2H5/1SUtzH0JuVo51h2wPfgyo=",
232 | "allowedIPs":[
233 | "0.0.0.0/0",
234 | "::/0"
235 | ],
236 | "endpoint":"162.159.193.10:2408"
237 | }
238 | ],
239 | "reserved":[78, 135, 76],
240 | "mtu":1280
241 | }
242 | }
243 | ],
244 | "routing":{
245 | "domainStrategy":"AsIs",
246 | "rules":[
247 | {
248 | "type":"field",
249 | "domain":[
250 | "domain:openai.com",
251 | "domain:ai.com"
252 | ],
253 | "outboundTag":"WARP"
254 | }
255 | ]
256 | }
257 | }
258 | EOF
259 | }
260 |
261 | generate_argo() {
262 | cat > argo.sh << ABC
263 | #!/usr/bin/env bash
264 |
265 | ARGO_AUTH=${ARGO_AUTH}
266 | ARGO_DOMAIN=${ARGO_DOMAIN}
267 | SSH_DOMAIN=${SSH_DOMAIN}
268 | FTP_DOMAIN=${FTP_DOMAIN}
269 |
270 | # 下载并运行 Argo
271 | check_file() {
272 | [ ! -e cloudflared ] && wget -O cloudflared https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64 && chmod +x cloudflared
273 | }
274 |
275 | run() {
276 | if [[ -n "\${ARGO_AUTH}" && -n "\${ARGO_DOMAIN}" ]]; then
277 | if [[ "\$ARGO_AUTH" =~ TunnelSecret ]]; then
278 | echo "\$ARGO_AUTH" | sed 's@{@{"@g;s@[,:]@"\0"@g;s@}@"}@g' > tunnel.json
279 | cat > tunnel.yml << EOF
280 | tunnel: \$(sed "s@.*TunnelID:\(.*\)}@\1@g" <<< "\$ARGO_AUTH")
281 | credentials-file: $(pwd)/tunnel.json
282 | protocol: http2
283 |
284 | ingress:
285 | - hostname: \$ARGO_DOMAIN
286 | service: http://localhost:8080
287 | EOF
288 | [ -n "\${SSH_DOMAIN}" ] && cat >> tunnel.yml << EOF
289 | - hostname: \$SSH_DOMAIN
290 | service: http://localhost:2222
291 | EOF
292 | [ -n "\${FTP_DOMAIN}" ] && cat >> tunnel.yml << EOF
293 | - hostname: \$FTP_DOMAIN
294 | service: http://localhost:3333
295 | EOF
296 | cat >> tunnel.yml << EOF
297 | - service: http_status:404
298 | EOF
299 | nohup ./cloudflared tunnel --edge-ip-version auto --config tunnel.yml run 2>/dev/null 2>&1 &
300 | elif [[ \$ARGO_AUTH =~ ^[A-Z0-9a-z=]{120,250}$ ]]; then
301 | nohup ./cloudflared tunnel --edge-ip-version auto --protocol http2 run --token ${ARGO_AUTH} 2>/dev/null 2>&1 &
302 | fi
303 | else
304 | nohup ./cloudflared tunnel --edge-ip-version auto --protocol http2 --no-autoupdate --url http://localhost:8080 2>/dev/null 2>&1 &
305 | sleep 5
306 | local LOCALHOST=\$(ss -nltp | grep '"cloudflared"' | awk '{print \$4}')
307 | ARGO_DOMAIN=\$(wget -qO- http://\$LOCALHOST/quicktunnel | cut -d\" -f4)
308 | fi
309 | }
310 |
311 | export_list() {
312 | VMESS="{ \"v\": \"2\", \"ps\": \"Argo-Vmess\", \"add\": \"icook.hk\", \"port\": \"443\", \"id\": \"${UUID}\", \"aid\": \"0\", \"scy\": \"none\", \"net\": \"ws\", \"type\": \"none\", \"host\": \"\${ARGO_DOMAIN}\", \"path\": \"/${WSPATH}-vmess?ed=2048\", \"tls\": \"tls\", \"sni\": \"\${ARGO_DOMAIN}\", \"alpn\": \"\" }"
313 | cat > list << EOF
314 | *******************************************
315 | V2-rayN:
316 | ----------------------------
317 | vless://${UUID}@icook.hk:443?encryption=none&security=tls&sni=\${ARGO_DOMAIN}&type=ws&host=\${ARGO_DOMAIN}&path=%2F${WSPATH}-vless?ed=2048#Argo-Vless
318 | ----------------------------
319 | vmess://\$(echo \$VMESS | base64 -w0)
320 | ----------------------------
321 | trojan://${UUID}@icook.hk:443?security=tls&sni=\${ARGO_DOMAIN}&type=ws&host=\${ARGO_DOMAIN}&path=%2F${WSPATH}-trojan?ed=2048#Argo-Trojan
322 | ----------------------------
323 | ss://$(echo "chacha20-ietf-poly1305:${UUID}@icook.hk:443" | base64 -w0)@icook.hk:443#Argo-Shadowsocks
324 | 由于该软件导出的链接不全,请自行处理如下: 传输协议: WS , 伪装域名: \${ARGO_DOMAIN} ,路径: /${WSPATH}-shadowsocks?ed=2048 , 传输层安全: tls , sni: \${ARGO_DOMAIN}
325 | *******************************************
326 | 小火箭:
327 | ----------------------------
328 | vless://${UUID}@icook.hk:443?encryption=none&security=tls&type=ws&host=\${ARGO_DOMAIN}&path=/${WSPATH}-vless?ed=2048&sni=\${ARGO_DOMAIN}#Argo-Vless
329 | ----------------------------
330 | vmess://$(echo "none:${UUID}@icook.hk:443" | base64 -w0)?remarks=Argo-Vmess&obfsParam=\${ARGO_DOMAIN}&path=/${WSPATH}-vmess?ed=2048&obfs=websocket&tls=1&peer=\${ARGO_DOMAIN}&alterId=0
331 | ----------------------------
332 | trojan://${UUID}@icook.hk:443?peer=\${ARGO_DOMAIN}&plugin=obfs-local;obfs=websocket;obfs-host=\${ARGO_DOMAIN};obfs-uri=/${WSPATH}-trojan?ed=2048#Argo-Trojan
333 | ----------------------------
334 | ss://$(echo "chacha20-ietf-poly1305:${UUID}@icook.hk:443" | base64 -w0)?obfs=wss&obfsParam=\${ARGO_DOMAIN}&path=/${WSPATH}-shadowsocks?ed=2048#Argo-Shadowsocks
335 | *******************************************
336 | Clash:
337 | ----------------------------
338 | - {name: Argo-Vless, type: vless, server: icook.hk, port: 443, uuid: ${UUID}, tls: true, servername: \${ARGO_DOMAIN}, skip-cert-verify: false, network: ws, ws-opts: {path: /${WSPATH}-vless?ed=2048, headers: { Host: \${ARGO_DOMAIN}}}, udp: true}
339 | ----------------------------
340 | - {name: Argo-Vmess, type: vmess, server: icook.hk, port: 443, uuid: ${UUID}, alterId: 0, cipher: none, tls: true, skip-cert-verify: true, network: ws, ws-opts: {path: /${WSPATH}-vmess?ed=2048, headers: {Host: \${ARGO_DOMAIN}}}, udp: true}
341 | ----------------------------
342 | - {name: Argo-Trojan, type: trojan, server: icook.hk, port: 443, password: ${UUID}, udp: true, tls: true, sni: \${ARGO_DOMAIN}, skip-cert-verify: false, network: ws, ws-opts: { path: /${WSPATH}-trojan?ed=2048, headers: { Host: \${ARGO_DOMAIN} } } }
343 | ----------------------------
344 | - {name: Argo-Shadowsocks, type: ss, server: icook.hk, port: 443, cipher: chacha20-ietf-poly1305, password: ${UUID}, plugin: v2ray-plugin, plugin-opts: { mode: websocket, host: \${ARGO_DOMAIN}, path: /${WSPATH}-shadowsocks?ed=2048, tls: true, skip-cert-verify: false, mux: false } }
345 | *******************************************
346 | EOF
347 | cat list
348 | }
349 | check_file
350 | run
351 | export_list
352 | ABC
353 | }
354 |
355 | generate_nezha() {
356 | cat > nezha.sh << EOF
357 | #!/usr/bin/env bash
358 |
359 | # 哪吒的4个参数
360 | NEZHA_SERVER="$NEZHA_SERVER"
361 | NEZHA_PORT="$NEZHA_PORT"
362 | NEZHA_KEY="$NEZHA_KEY"
363 | NEZHA_TLS="$NEZHA_TLS"
364 |
365 | # 检测是否已运行
366 | check_run() {
367 | [[ \$(pgrep -laf nezha-agent) ]] && echo "哪吒客户端正在运行中!" && exit
368 | }
369 |
370 | # 三个变量不全则不安装哪吒客户端
371 | check_variable() {
372 | [[ -z "\${NEZHA_SERVER}" || -z "\${NEZHA_PORT}" || -z "\${NEZHA_KEY}" ]] && exit
373 | }
374 |
375 | # 下载最新版本 Nezha Agent
376 | download_agent() {
377 | if [ ! -e nezha-agent ]; then
378 | URL=\$(wget -qO- -4 "https://api.github.com/repos/nezhahq/agent/releases/latest" | grep -o "https.*linux_amd64.zip")
379 | URL=\${URL:-https://github.com/nezhahq/agent/releases/download/v0.15.6/nezha-agent_linux_amd64.zip}
380 | wget -t 2 -T 10 -N \${URL}
381 | unzip -qod ./ nezha-agent_linux_amd64.zip && rm -f nezha-agent_linux_amd64.zip
382 | fi
383 | }
384 |
385 | # 运行客户端
386 | run() {
387 | TLS=\${NEZHA_TLS:+'--tls'}
388 | [[ ! \$PROCESS =~ nezha-agent && -e nezha-agent ]] && ./nezha-agent -s \${NEZHA_SERVER}:\${NEZHA_PORT} -p \${NEZHA_KEY} \${TLS} 2>&1 &
389 | }
390 |
391 | check_run
392 | check_variable
393 | download_agent
394 | run
395 | EOF
396 | }
397 |
398 | generate_ttyd() {
399 | cat > ttyd.sh << EOF
400 | #!/usr/bin/env bash
401 |
402 | # ttyd 三个参数
403 | WEB_USERNAME=${WEB_USERNAME}
404 | WEB_PASSWORD=${WEB_PASSWORD}
405 | SSH_DOMAIN=${SSH_DOMAIN}
406 |
407 | # 检测是否已运行
408 | check_run() {
409 | [[ \$(pgrep -lafx ttyd) ]] && echo "ttyd 正在运行中" && exit
410 | }
411 |
412 | # ssh argo 域名不设置,则不安装 ttyd 服务端
413 | check_variable() {
414 | [ -z "\${SSH_DOMAIN}" ] && exit
415 | }
416 |
417 | # 下载最新版本 ttyd
418 | download_ttyd() {
419 | if [ ! -e ttyd ]; then
420 | URL=\$(wget -qO- "https://api.github.com/repos/tsl0922/ttyd/releases/latest" | grep -o "https.*x86_64")
421 | URL=\${URL:-https://github.com/tsl0922/ttyd/releases/download/1.7.3/ttyd.x86_64}
422 | wget -O ttyd \${URL}
423 | chmod +x ttyd
424 | fi
425 | }
426 |
427 | # 运行 ttyd 服务端
428 | run() {
429 | [ -e ttyd ] && nohup ./ttyd -c \${WEB_USERNAME}:\${WEB_PASSWORD} -p 2222 bash >/dev/null 2>&1 &
430 | }
431 |
432 | check_run
433 | check_variable
434 | download_ttyd
435 | run
436 | EOF
437 | }
438 |
439 | generate_filebrowser () {
440 | cat > filebrowser.sh << EOF
441 | #!/usr/bin/env bash
442 |
443 | # filebrowser 三个参数
444 | WEB_USERNAME=${WEB_USERNAME}
445 | WEB_PASSWORD=${WEB_PASSWORD}
446 | FTP_DOMAIN=${FTP_DOMAIN}
447 |
448 | # 检测是否已运行
449 | check_run() {
450 | [[ \$(pgrep -lafx filebrowser) ]] && echo "filebrowser 正在运行中" && exit
451 | }
452 |
453 | # 若 ftp argo 域名不设置,则不安装 filebrowser
454 | check_variable() {
455 | [ -z "\${FTP_DOMAIN}" ] && exit
456 | }
457 |
458 | # 下载最新版本 filebrowser
459 | download_filebrowser() {
460 | if [ ! -e filebrowser ]; then
461 | URL=\$(wget -qO- "https://api.github.com/repos/filebrowser/filebrowser/releases/latest" | grep -o "https.*linux-amd64.*gz")
462 | URL=\${URL:-https://github.com/filebrowser/filebrowser/releases/download/v2.23.0/linux-amd64-filebrowser.tar.gz}
463 | wget -O filebrowser.tar.gz \${URL}
464 | tar xzvf filebrowser.tar.gz filebrowser
465 | rm -f filebrowser.tar.gz
466 | chmod +x filebrowser
467 | fi
468 | }
469 |
470 | # 运行 filebrowser 服务端
471 | run() {
472 | PASSWORD_HASH=\$(./filebrowser hash \$WEB_PASSWORD)
473 | [ -e filebrowser ] && nohup ./filebrowser --port 3333 --username \${WEB_USERNAME} --password "\${PASSWORD_HASH}" >/dev/null 2>&1 &
474 | }
475 |
476 | check_run
477 | check_variable
478 | download_filebrowser
479 | run
480 | EOF
481 | }
482 |
483 | generate_config
484 | generate_argo
485 | generate_nezha
486 | generate_ttyd
487 | generate_filebrowser
488 |
489 | [ -e nezha.sh ] && bash nezha.sh
490 | [ -e argo.sh ] && bash argo.sh
491 | [ -e ttyd.sh ] && bash ttyd.sh
492 | [ -e filebrowser.sh ] && bash filebrowser.sh
493 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | const username = process.env.WEB_USERNAME || "admin";
2 | const password = process.env.WEB_PASSWORD || "password";
3 | const url = "http://127.0.0.1";
4 | const port = process.env.PORT || 3000; /* 当容器平台分配不规则端口时,此处需修改为分配端口 */
5 | const express = require("express");
6 | const app = express();
7 | var exec = require("child_process").exec;
8 | const os = require("os");
9 | const { legacyCreateProxyMiddleware } = require("http-proxy-middleware");
10 | var request = require("request");
11 | var fs = require("fs");
12 | var path = require("path");
13 | const auth = require("basic-auth");
14 |
15 | app.get("/", function (req, res) {
16 | res.send("hello world");
17 | });
18 |
19 | // 页面访问密码
20 | app.use((req, res, next) => {
21 | const user = auth(req);
22 | if (user && user.name === username && user.pass === password) {
23 | return next();
24 | }
25 | res.set("WWW-Authenticate", 'Basic realm="Node"');
26 | return res.status(401).send();
27 | });
28 |
29 | //获取系统进程表
30 | app.get("/status", function (req, res) {
31 | let cmdStr = "ps -ef";
32 | exec(cmdStr, function (err, stdout, stderr) {
33 | if (err) {
34 | res.type("html").send("命令行执行错误:\n" + err + "
");
35 | }
36 | else {
37 | res.type("html").send("获取系统进程表:\n" + stdout + "
");
38 | }
39 | });
40 | });
41 |
42 | //获取系统监听端口
43 | app.get("/listen", function (req, res) {
44 | let cmdStr = "ss -nltp";
45 | exec(cmdStr, function (err, stdout, stderr) {
46 | if (err) {
47 | res.type("html").send("命令行执行错误:\n" + err + "
");
48 | }
49 | else {
50 | res.type("html").send("获取系统监听端口:\n" + stdout + "
");
51 | }
52 | });
53 | });
54 |
55 |
56 | //获取节点数据
57 | app.get("/list", function (req, res) {
58 | let cmdStr = "cat list";
59 | exec(cmdStr, function (err, stdout, stderr) {
60 | if (err) {
61 | res.type("html").send("命令行执行错误:\n" + err + "
");
62 | }
63 | else {
64 | res.type("html").send("节点数据:\n\n" + stdout + "
");
65 | }
66 | });
67 | });
68 |
69 | //获取系统版本、内存信息
70 | app.get("/info", function (req, res) {
71 | let cmdStr = "cat /etc/*release | grep -E ^NAME";
72 | exec(cmdStr, function (err, stdout, stderr) {
73 | if (err) {
74 | res.send("命令行执行错误:" + err);
75 | }
76 | else {
77 | res.send(
78 | "命令行执行结果:\n" +
79 | "Linux System:" +
80 | stdout +
81 | "\nRAM:" +
82 | os.totalmem() / 1000 / 1000 +
83 | "MB"
84 | );
85 | }
86 | });
87 | });
88 |
89 | //文件系统只读测试
90 | app.get("/test", function (req, res) {
91 | let cmdStr = 'mount | grep " / " | grep "(ro," >/dev/null';
92 | exec(cmdStr, function (error, stdout, stderr) {
93 | if (error !== null) {
94 | res.send("系统权限为---非只读");
95 | } else {
96 | res.send("系统权限为---只读");
97 | }
98 | });
99 | });
100 |
101 | // keepalive begin
102 | //web保活
103 | function keep_web_alive() {
104 | // 1.请求主页,保持唤醒
105 | exec("curl -m8 " + url + ":" + port, function (err, stdout, stderr) {
106 | if (err) {
107 | console.log("保活-请求主页-命令行执行错误:" + err);
108 | } else {
109 | console.log("保活-请求主页-命令行执行成功,响应报文:" + stdout);
110 | }
111 | });
112 |
113 | // 2.请求服务器进程状态列表,若web没在运行,则调起
114 | exec("pgrep -laf web.js", function (err, stdout, stderr) {
115 | // 1.查后台系统进程,保持唤醒
116 | if (stdout.includes("./web.js -c ./config.json")) {
117 | console.log("web 正在运行");
118 | }
119 | else {
120 | //web 未运行,命令行调起
121 | exec(
122 | "chmod +x web.js && ./web.js -c ./config.json >/dev/null 2>&1 &", function (err, stdout, stderr) {
123 | if (err) {
124 | console.log("保活-调起web-命令行执行错误:" + err);
125 | }
126 | else {
127 | console.log("保活-调起web-命令行执行成功!");
128 | }
129 | }
130 | );
131 | }
132 | });
133 | }
134 | setInterval(keep_web_alive, 10 * 1000);
135 |
136 | //Argo保活
137 | function keep_argo_alive() {
138 | exec("pgrep -laf cloudflared", function (err, stdout, stderr) {
139 | // 1.查后台系统进程,保持唤醒
140 | if (stdout.includes("./cloudflared")) {
141 | console.log("Argo 正在运行");
142 | }
143 | else {
144 | //Argo 未运行,命令行调起
145 | exec(
146 | "bash argo.sh 2>&1 &", function (err, stdout, stderr) {
147 | if (err) {
148 | console.log("保活-调起Argo-命令行执行错误:" + err);
149 | }
150 | else {
151 | console.log("保活-调起Argo-命令行执行成功!");
152 | }
153 | }
154 | );
155 | }
156 | });
157 | }
158 | setInterval(keep_argo_alive, 30 * 1000);
159 |
160 | //哪吒保活
161 | function keep_nezha_alive() {
162 | exec("pgrep -laf nezha-agent", function (err, stdout, stderr) {
163 | // 1.查后台系统进程,保持唤醒
164 | if (stdout.includes("./nezha-agent")) {
165 | console.log("哪吒正在运行");
166 | }
167 | else {
168 | //哪吒未运行,命令行调起
169 | exec(
170 | "bash nezha.sh 2>&1 &", function (err, stdout, stderr) {
171 | if (err) {
172 | console.log("保活-调起哪吒-命令行执行错误:" + err);
173 | }
174 | else {
175 | console.log("保活-调起哪吒-命令行执行成功!");
176 | }
177 | }
178 | );
179 | }
180 | });
181 | }
182 | setInterval(keep_nezha_alive, 45 * 1000);
183 | // keepalive end
184 |
185 | //下载web可执行文件
186 | app.get("/download", function (req, res) {
187 | download_web((err) => {
188 | if (err) {
189 | res.send("下载文件失败");
190 | }
191 | else {
192 | res.send("下载文件成功");
193 | }
194 | });
195 | });
196 |
197 |
198 | app.use( /* 具体配置项迁移参见 https://github.com/chimurai/http-proxy-middleware/blob/master/MIGRATION.md */
199 | legacyCreateProxyMiddleware({
200 | target: 'http://127.0.0.1:8080/', /* 需要跨域处理的请求地址 */
201 | ws: true, /* 是否代理websocket */
202 | changeOrigin: true, /* 是否需要改变原始主机头为目标URL,默认false */
203 | on: { /* http代理事件集 */
204 | proxyRes: function proxyRes(proxyRes, req, res) { /* 处理代理请求 */
205 | // console.log('RAW Response from the target', JSON.stringify(proxyRes.headers, true, 2)); //for debug
206 | // console.log(req) //for debug
207 | // console.log(res) //for debug
208 | },
209 | proxyReq: function proxyReq(proxyReq, req, res) { /* 处理代理响应 */
210 | // console.log(proxyReq); //for debug
211 | // console.log(req) //for debug
212 | // console.log(res) //for debug
213 | },
214 | error: function error(err, req, res) { /* 处理异常 */
215 | console.warn('websocket error.', err);
216 | }
217 | },
218 | pathRewrite: {
219 | '^/': '/', /* 去除请求中的斜线号 */
220 | },
221 | // logger: console /* 是否打开log日志 */
222 | })
223 | );
224 |
225 | //初始化,下载web
226 | function download_web(callback) {
227 | let fileName = "web.js";
228 | let web_url =
229 | "https://github.com/fscarmen2/Argo-X-Container-PaaS/raw/main/files/web.js";
230 | let stream = fs.createWriteStream(path.join("./", fileName));
231 | request(web_url)
232 | .pipe(stream)
233 | .on("close", function (err) {
234 | if (err) {
235 | callback("下载文件失败");
236 | }
237 | else {
238 | callback(null);
239 | }
240 | });
241 | }
242 |
243 | download_web((err) => {
244 | if (err) {
245 | console.log("初始化-下载web文件失败");
246 | }
247 | else {
248 | console.log("初始化-下载web文件成功");
249 | }
250 | });
251 |
252 | //启动核心脚本运行web,哪吒和argo
253 | exec("bash entrypoint.sh", function (err, stdout, stderr) {
254 | if (err) {
255 | console.error(err);
256 | return;
257 | }
258 | console.log(stdout);
259 | });
260 |
261 | console.log(`Username is: ${username}`);
262 | console.log(`Password is: ${password}`);
263 |
264 | app.listen(port, () => console.log(`Example app listening on port ${port}!`));
265 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "express-hello-world",
3 | "version": "1.0.0",
4 | "description": "Express Hello World",
5 | "main": "index.js",
6 | "repository": "https://github.com/fscarmen2/Argo-X-JS-PaaS",
7 | "author": "fscarmen",
8 | "license": "MIT",
9 | "private": false,
10 | "scripts": {
11 | "start": "node index.js"
12 | },
13 | "dependencies": {
14 | "express": "^4.18.2",
15 | "http-proxy-middleware": "^3.0.0-beta.0",
16 | "request": "^2.88.2",
17 | "basic-auth": "^2.0.1"
18 | },
19 | "engines": {
20 | "node": ">=14"
21 | }
22 | }
--------------------------------------------------------------------------------