├── Dockerfile ├── README.md ├── files ├── entrypoint.sh ├── package.json ├── server.js └── web.js └── tasks.json /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:latest 2 | EXPOSE 3000 3 | WORKDIR /app 4 | COPY files/* /app/ 5 | 6 | RUN apt-get update &&\ 7 | apt-get install -y iproute2 &&\ 8 | npm install -r package.json &&\ 9 | npm install -g pm2 &&\ 10 | wget -O cloudflared.deb https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb &&\ 11 | dpkg -i cloudflared.deb &&\ 12 | rm -f cloudflared.deb &&\ 13 | chmod +x web.js 14 | 15 | ENTRYPOINT [ "node", "/app/server.js" ] 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # X for CodeSandBox 2 | 3 | * * * 4 | 5 | # 目录 6 | 7 | - [项目特点](README.md#项目特点) 8 | - [部署](README.md#部署) 9 | - [Argo Json 的获取](README.md#argo-json-的获取) 10 | - [Argo Token 的获取](README.md#argo-token-的获取) 11 | - [TTYD webssh 的部署](README.md#ttyd-webssh-的部署) 12 | - [鸣谢下列作者的文章和项目](README.md#鸣谢下列作者的文章和项目) 13 | - [免责声明](README.md#免责声明) 14 | 15 | * * * 16 | 17 | ## 项目特点: 18 | * 使用 CloudFlare 的 Argo 隧道,同时兼容 Json / token / 临时 三种方式认证,使用TLS加密通信,可以将应用程序流量安全地传输到Cloudflare网络,提高了应用程序的安全性和可靠性。此外,Argo Tunnel也可以防止IP泄露和DDoS攻击等网络威胁 19 | * 解锁 chatGPT 20 | * 在浏览器查看系统各项信息,方便直观 21 | * 集成哪吒探针,可以自由选择是否安装,支持 SSL/TLS 模式,适配 Nezha over Argo 项目: https://github.com/fscarmen2/Argo-Nezha-Service-Container 22 | * uuid,WS 路径既可以自定义,又或者使用默认值 23 | * 前端 js 定时和 pm2 配合保活,务求让恢复时间减到最小 24 | * 节点信息以 V2rayN / Clash / 小火箭 链接方式输出 25 | * 可以使用浏览器访问,使用 ttyd,ssh over http2 26 | * 项目路径 `https://github.com/fscarmen2/X-for-CodeSandBox` 27 | 28 | ## 部署: 29 | * 注册 [CodeSandbox](https://codesandbox.io/signin?utm_source=landingpage) ,支持 GitHub / Google / Apple 账号进行登录,请使用以下地址注册并进行登录。 30 | 31 | * PaaS 平台设置的环境变量 32 | | 变量名 | 是否必须 | 默认值 | 备注 | 33 | | ------------ | ------ | ------ | ------ | 34 | | UUID | 否 | de04add9-5c68-8bab-950c-08cd5320df18 | 可在线生成 https://www.zxgj.cn/g/uuid | 35 | | WSPATH | 否 | argo | 勿以 / 开头,各协议路径为 `/WSPATH-协议`,如 `/argo-vless`,`/argo-vmess`,`/argo-trojan`,`/argo-shadowsocks` | 36 | | NEZHA_SERVER | 否 | | 哪吒探针与面板服务端数据通信的IP或域名 | 37 | | NEZHA_PORT | 否 | | 哪吒探针服务端的端口 | 38 | | NEZHA_KEY | 否 | | 哪吒探针客户端专用 Key | 39 | | NEZHA_TLS | 否 | | 哪吒探针是否启用 SSL/TLS 加密 ,如不启用不要该变量,如要启用填"1" | 40 | | ARGO_AUTH | 否 | | Argo 的 Token 或者 json 值 | 41 | | ARGO_DOMAIN | 否 | | Argo 的域名,须与 ARGO_DOMAIN 必需一起填了才能生效 | 42 | | WEB_USERNAME | 否 | admin | 网页和 webssh 的用户名 | 43 | | WEB_PASSWORD | 否 | password | 网页和 webssh 的密码 | 44 | | SSH_DOMAIN | 否 | | webssh 的域名,用户名和密码就是 | 45 | 46 | * 路径(path) 47 | | 命令 | 说明 | 48 | | ---- |------ | 49 | | /list | 查看节点数据 | 50 | | /status | 查看后台进程 | 51 | | /listen | 查看后台监听端口 | 52 | 53 | ![image](https://user-images.githubusercontent.com/92626977/235288393-4d48f122-1eec-40a0-a84d-bdb666bd1291.png) 54 | 55 | ![image](https://user-images.githubusercontent.com/92626977/235288429-6e253f76-4bab-43c3-b953-8a91e0225cde.png) 56 | 57 | ``` 58 | ARGO_AUTH="" 59 | ARGO_DOMAIN="" 60 | NEZHA_SERVER="" 61 | NEZHA_PORT="" 62 | NEZHA_KEY="" 63 | NEZHA_TLS="" 64 | UUID="" 65 | WSPATH="" 66 | WEB_USERNAME="" 67 | WEB_PASSWORD="" 68 | SSH_DOMAIN="" 69 | ``` 70 | 71 | ![image](https://user-images.githubusercontent.com/92626977/235289409-392ccb73-55d9-4e00-a995-26fc765516b0.png) 72 | 73 | * 下载项目文件到本地压缩:`https://github.com/fscarmen2/X-for-CodeSandBox/archive/refs/heads/main.zip`,除 `README.md` 外的所有文件和目录上传到 `.codesandbox` 文件夹下 74 | 75 | ![image](https://user-images.githubusercontent.com/92626977/235289852-cb0b4af0-a033-4f48-b17a-8e431b2c87d5.png) 76 | 77 | ![image](https://user-images.githubusercontent.com/92626977/235289911-f2a96ba2-80f1-46c0-91e0-08d694e8a477.png) 78 | 79 | ![image](https://user-images.githubusercontent.com/92626977/235289999-ef07a216-1a2c-4127-928f-f600150ed521.png) 80 | 81 | 82 | ## Argo Json 的获取 83 | 84 | 用户可以通过 Cloudflare Json 生成网轻松获取: https://fscarmen.cloudflare.now.cc 85 | 86 | image 87 | 88 | 如想手动,可以参考,以 Debian 为例,需要用到的命令,[Deron Cheng - CloudFlare Argo Tunnel 试用](https://zhengweidong.com/try-cloudflare-argo-tunnel) 89 | 90 | 91 | ## Argo Token 的获取 92 | 93 | 详细教程: [群晖套件:Cloudflare Tunnel 内网穿透中文教程 支持DSM6、7](https://imnks.com/5984.html) 94 | 95 | image 96 | 97 | image 98 | 99 | image 100 | 101 | 102 | ## TTYD webssh 的部署 103 | 104 | * 原理 105 | ``` 106 | +---------+ argo +---------+ http +--------+ ssh +-----------+ 107 | | browser | <==========> | CF edge | <==========> | ttyd | <=======> | ssh server| 108 | +---------+ argo +---------+ websocket +--------+ ssh +-----------+ 109 | ``` 110 | 111 | * 只能使用 Json 方式建的隧道,不能使用 Token 112 | 113 | image 114 | 115 | image 116 | 117 | image 118 | 119 | image 120 | 121 | 122 | ## 鸣谢下列作者的文章和项目: 123 | 124 | * Nike Jeff 的 trojan 项目: https://github.com/hrzyang/glitch-trojan 125 | * Hifeng 的博客: https://www.hicairo.com/post/62.html 126 | 127 | ## 免责声明: 128 | * 本程序仅供学习了解, 非盈利目的,请于下载后 24 小时内删除, 不得用作任何商业用途, 文字、数据及图片均有所属版权, 如转载须注明来源。 129 | * 使用本程序必循遵守部署免责声明。使用本程序必循遵守部署服务器所在地、所在国家和用户所在国家的法律法规, 程序作者不对使用者任何不当行为负责。 -------------------------------------------------------------------------------- /files/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # 设置各变量 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 | generate_config() { 10 | cat > /app/config.json << EOF 11 | { 12 | "log":{ 13 | "access":"/dev/null", 14 | "error":"/dev/null", 15 | "loglevel":"none" 16 | }, 17 | "inbounds":[ 18 | { 19 | "port":8080, 20 | "protocol":"vless", 21 | "settings":{ 22 | "clients":[ 23 | { 24 | "id":"${UUID}", 25 | "flow":"xtls-rprx-vision" 26 | } 27 | ], 28 | "decryption":"none", 29 | "fallbacks":[ 30 | { 31 | "dest":3001 32 | }, 33 | { 34 | "path":"/${WSPATH}-vless", 35 | "dest":3002 36 | }, 37 | { 38 | "path":"/${WSPATH}-vmess", 39 | "dest":3003 40 | }, 41 | { 42 | "path":"/${WSPATH}-trojan", 43 | "dest":3004 44 | }, 45 | { 46 | "path":"/${WSPATH}-shadowsocks", 47 | "dest":3005 48 | } 49 | ] 50 | }, 51 | "streamSettings":{ 52 | "network":"tcp" 53 | } 54 | }, 55 | { 56 | "port":3001, 57 | "listen":"127.0.0.1", 58 | "protocol":"vless", 59 | "settings":{ 60 | "clients":[ 61 | { 62 | "id":"${UUID}" 63 | } 64 | ], 65 | "decryption":"none" 66 | }, 67 | "streamSettings":{ 68 | "network":"ws", 69 | "security":"none" 70 | } 71 | }, 72 | { 73 | "port":3002, 74 | "listen":"127.0.0.1", 75 | "protocol":"vless", 76 | "settings":{ 77 | "clients":[ 78 | { 79 | "id":"${UUID}", 80 | "level":0 81 | } 82 | ], 83 | "decryption":"none" 84 | }, 85 | "streamSettings":{ 86 | "network":"ws", 87 | "security":"none", 88 | "wsSettings":{ 89 | "path":"/${WSPATH}-vless" 90 | } 91 | }, 92 | "sniffing":{ 93 | "enabled":true, 94 | "destOverride":[ 95 | "http", 96 | "tls" 97 | ], 98 | "metadataOnly":false 99 | } 100 | }, 101 | { 102 | "port":3003, 103 | "listen":"127.0.0.1", 104 | "protocol":"vmess", 105 | "settings":{ 106 | "clients":[ 107 | { 108 | "id":"${UUID}", 109 | "alterId":0 110 | } 111 | ] 112 | }, 113 | "streamSettings":{ 114 | "network":"ws", 115 | "wsSettings":{ 116 | "path":"/${WSPATH}-vmess" 117 | } 118 | }, 119 | "sniffing":{ 120 | "enabled":true, 121 | "destOverride":[ 122 | "http", 123 | "tls" 124 | ], 125 | "metadataOnly":false 126 | } 127 | }, 128 | { 129 | "port":3004, 130 | "listen":"127.0.0.1", 131 | "protocol":"trojan", 132 | "settings":{ 133 | "clients":[ 134 | { 135 | "password":"${UUID}" 136 | } 137 | ] 138 | }, 139 | "streamSettings":{ 140 | "network":"ws", 141 | "security":"none", 142 | "wsSettings":{ 143 | "path":"/${WSPATH}-trojan" 144 | } 145 | }, 146 | "sniffing":{ 147 | "enabled":true, 148 | "destOverride":[ 149 | "http", 150 | "tls" 151 | ], 152 | "metadataOnly":false 153 | } 154 | }, 155 | { 156 | "port":3005, 157 | "listen":"127.0.0.1", 158 | "protocol":"shadowsocks", 159 | "settings":{ 160 | "clients":[ 161 | { 162 | "method":"chacha20-ietf-poly1305", 163 | "password":"${UUID}" 164 | } 165 | ], 166 | "decryption":"none" 167 | }, 168 | "streamSettings":{ 169 | "network":"ws", 170 | "wsSettings":{ 171 | "path":"/${WSPATH}-shadowsocks" 172 | } 173 | }, 174 | "sniffing":{ 175 | "enabled":true, 176 | "destOverride":[ 177 | "http", 178 | "tls" 179 | ], 180 | "metadataOnly":false 181 | } 182 | } 183 | ], 184 | "dns":{ 185 | "servers":[ 186 | "https+local://8.8.8.8/dns-query" 187 | ] 188 | }, 189 | "outbounds":[ 190 | { 191 | "protocol":"freedom" 192 | }, 193 | { 194 | "tag":"WARP", 195 | "protocol":"wireguard", 196 | "settings":{ 197 | "secretKey":"cKE7LmCF61IhqqABGhvJ44jWXp8fKymcMAEVAzbDF2k=", 198 | "address":[ 199 | "172.16.0.2/32", 200 | "fd01:5ca1:ab1e:823e:e094:eb1c:ff87:1fab/128" 201 | ], 202 | "peers":[ 203 | { 204 | "publicKey":"bmXOC+F1FxEMF9dyiK2H5/1SUtzH0JuVo51h2wPfgyo=", 205 | "endpoint":"162.159.193.10:2408" 206 | } 207 | ] 208 | } 209 | } 210 | ], 211 | "routing":{ 212 | "domainStrategy":"AsIs", 213 | "rules":[ 214 | { 215 | "type":"field", 216 | "domain":[ 217 | "domain:openai.com", 218 | "domain:ai.com" 219 | ], 220 | "outboundTag":"WARP" 221 | } 222 | ] 223 | } 224 | } 225 | EOF 226 | } 227 | 228 | generate_argo() { 229 | cat > /app/argo.sh << ABC 230 | #!/usr/bin/env bash 231 | 232 | argo_type() { 233 | if [[ -n "\${ARGO_AUTH}" && -n "\${ARGO_DOMAIN}" ]]; then 234 | [[ \$ARGO_AUTH =~ TunnelSecret ]] && echo \$ARGO_AUTH > /app/tunnel.json && cat > /app/tunnel.yml << EOF 235 | tunnel: \$(cut -d\" -f12 <<< \$ARGO_AUTH) 236 | credentials-file: /app/tunnel.json 237 | protocol: h2mux 238 | 239 | ingress: 240 | - hostname: \$ARGO_DOMAIN 241 | service: http://localhost:8080 242 | EOF 243 | 244 | [ -n "\${SSH_DOMAIN}" ] && cat >> /app/tunnel.yml << EOF 245 | - hostname: \$SSH_DOMAIN 246 | service: http://localhost:2222 247 | EOF 248 | 249 | cat >> /app/tunnel.yml << EOF 250 | originRequest: 251 | noTLSVerify: true 252 | - service: http_status:404 253 | EOF 254 | 255 | else 256 | ARGO_DOMAIN=\$(cat /app/argo.log | grep -o "info.*https://.*trycloudflare.com" | sed "s@.*https://@@g" | tail -n 1) 257 | fi 258 | } 259 | 260 | export_list() { 261 | 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\": \"\" }" 262 | 263 | cat > /app/list << EOF 264 | ******************************************* 265 | V2-rayN: 266 | ---------------------------- 267 | 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 268 | ---------------------------- 269 | vmess://\$(echo \$VMESS | base64 -w0) 270 | ---------------------------- 271 | trojan://${UUID}@icook.hk:443?security=tls&sni=\${ARGO_DOMAIN}&type=ws&host=\${ARGO_DOMAIN}&path=%2F${WSPATH}-trojan?ed=2048#Argo-Trojan 272 | ---------------------------- 273 | ss://$(echo "chacha20-ietf-poly1305:${UUID}@icook.hk:443" | base64 -w0)@icook.hk:443#Argo-Shadowsocks 274 | 由于该软件导出的链接不全,请自行处理如下: 传输协议: WS , 伪装域名: \${ARGO_DOMAIN} ,路径: /${WSPATH}-shadowsocks?ed=2048 , 传输层安全: tls , sni: \${ARGO_DOMAIN} 275 | ******************************************* 276 | 小火箭: 277 | ---------------------------- 278 | vless://${UUID}@icook.hk:443?encryption=none&security=tls&type=ws&host=\${ARGO_DOMAIN}&path=/${WSPATH}-vless?ed=2048&sni=\${ARGO_DOMAIN}#Argo-Vless 279 | ---------------------------- 280 | 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 281 | ---------------------------- 282 | 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 283 | ---------------------------- 284 | ss://$(echo "chacha20-ietf-poly1305:${UUID}@icook.hk:443" | base64 -w0)?obfs=wss&obfsParam=\${ARGO_DOMAIN}&path=/${WSPATH}-shadowsocks?ed=2048#Argo-Shadowsocks 285 | ******************************************* 286 | Clash: 287 | ---------------------------- 288 | - {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} 289 | ---------------------------- 290 | - {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} 291 | ---------------------------- 292 | - {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} } } } 293 | ---------------------------- 294 | - {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 } } 295 | ******************************************* 296 | EOF 297 | cat /app/list 298 | } 299 | 300 | argo_type 301 | export_list 302 | ABC 303 | } 304 | 305 | generate_nezha() { 306 | cat > /app/nezha.sh << EOF 307 | #!/usr/bin/env bash 308 | 309 | # 检测是否已运行 310 | check_run() { 311 | [[ \$(pgrep -lafx nezha-agent) ]] && echo "哪吒客户端正在运行中" && exit 312 | } 313 | 314 | # 三个变量不全则不安装哪吒客户端 315 | check_variable() { 316 | [[ -z "\${NEZHA_SERVER}" || -z "\${NEZHA_PORT}" || -z "\${NEZHA_KEY}" ]] && exit 317 | } 318 | 319 | # 下载最新版本 Nezha Agent 320 | download_agent() { 321 | if [ ! -e /app/nezha-agent ]; then 322 | URL=\$(wget -qO- "https://api.github.com/repos/nezhahq/agent/releases/latest" | grep -o "https.*linux_amd64.zip") 323 | URL=\${URL:-https://github.com/nezhahq/agent/releases/download/v0.15.6/nezha-agent_linux_amd64.zip} 324 | wget -P /app/ \${URL} 325 | unzip -qod /app/ /app/nezha-agent_linux_amd64.zip 326 | rm -f /app/nezha-agent_linux_amd64.zip 327 | fi 328 | } 329 | 330 | check_run 331 | check_variable 332 | download_agent 333 | EOF 334 | } 335 | 336 | generate_ttyd() { 337 | cat > /app/ttyd.sh << EOF 338 | #!/usr/bin/env bash 339 | 340 | # 检测是否已运行 341 | check_run() { 342 | [[ \$(pgrep -lafx ttyd) ]] && echo "ttyd 正在运行中" && exit 343 | } 344 | 345 | # ssh argo 域名不设置,则不安装 ttyd 服务端 346 | check_variable() { 347 | [ -z "\${SSH_DOMAIN}" ] && exit 348 | } 349 | 350 | # 下载最新版本 ttyd 351 | download_ttyd() { 352 | if [ ! -e /app/ttyd ]; then 353 | URL=\$(wget -qO- "https://api.github.com/repos/tsl0922/ttyd/releases/latest" | grep -o "https.*x86_64") 354 | URL=\${URL:-https://github.com/tsl0922/ttyd/releases/download/1.7.3/ttyd.x86_64} 355 | wget -O /app/ttyd \${URL} 356 | chmod +x /app/ttyd 357 | fi 358 | } 359 | 360 | check_run 361 | check_variable 362 | download_ttyd 363 | EOF 364 | } 365 | 366 | generate_pm2_file() { 367 | if [[ -n "${ARGO_AUTH}" && -n "${ARGO_DOMAIN}" ]]; then 368 | [[ $ARGO_AUTH =~ TunnelSecret ]] && ARGO_ARGS="tunnel --edge-ip-version auto --config /app/tunnel.yml run" 369 | [[ $ARGO_AUTH =~ ^[A-Z0-9a-z=]{120,250}$ ]] && ARGO_ARGS="tunnel --edge-ip-version auto --protocol h2mux run --token ${ARGO_AUTH}" 370 | else 371 | ARGO_ARGS="tunnel --edge-ip-version auto --protocol h2mux --no-autoupdate --logfile /app/argo.log --loglevel info --url http://localhost:8080" 372 | fi 373 | 374 | TLS=${NEZHA_TLS:+'--tls'} 375 | 376 | cat > /app/ecosystem.config.js << EOF 377 | module.exports = { 378 | "apps":[ 379 | { 380 | "name":"web", 381 | "script":"/app/web.js run" 382 | }, 383 | { 384 | "name":"argo", 385 | "script":"cloudflared", 386 | "args":"${ARGO_ARGS}" 387 | EOF 388 | 389 | [[ -n "${NEZHA_SERVER}" && -n "${NEZHA_PORT}" && -n "${NEZHA_KEY}" ]] && cat >> /app/ecosystem.config.js << EOF 390 | }, 391 | { 392 | "name":"nezha", 393 | "script":"/app/nezha-agent", 394 | "args":"-s ${NEZHA_SERVER}:${NEZHA_PORT} -p ${NEZHA_KEY} ${TLS}" 395 | EOF 396 | 397 | [ -n "${SSH_DOMAIN}" ] && cat >> /app/ecosystem.config.js << EOF 398 | }, 399 | { 400 | "name":"ttyd", 401 | "script":"/app/ttyd", 402 | "args":"-c ${WEB_USERNAME}:${WEB_PASSWORD} -p 2222 bash" 403 | EOF 404 | 405 | cat >> /app/ecosystem.config.js << EOF 406 | } 407 | ] 408 | } 409 | EOF 410 | } 411 | 412 | generate_config 413 | generate_argo 414 | generate_nezha 415 | generate_ttyd 416 | generate_pm2_file 417 | 418 | [ -e /app/nezha.sh ] && bash /app/nezha.sh 419 | [ -e /app/argo.sh ] && bash /app/argo.sh 420 | [ -e /app/ttyd.sh ] && bash /app/ttyd.sh 421 | [ -e /app/ecosystem.config.js ] && pm2 start /app/ecosystem.config.js 422 | -------------------------------------------------------------------------------- /files/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "express-hello-world", 3 | "version": "1.0.0", 4 | "description": "Express Hello World", 5 | "main": "server.js", 6 | "repository": "https://github.com/fscarmen2/CodeSandBox", 7 | "author": "fscarmen", 8 | "license": "MIT", 9 | "private": false, 10 | "scripts": { 11 | "start": "node server.js" 12 | }, 13 | "dependencies": { 14 | "express": "^4.18.2", 15 | "http-proxy-middleware": "^2.0.6", 16 | "request": "^2.88.2", 17 | "basic-auth": "^2.0.1" 18 | }, 19 | "engines": { 20 | "node": ">=14" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /files/server.js: -------------------------------------------------------------------------------- 1 | const username = process.env.WEB_USERNAME || "admin"; 2 | const password = process.env.WEB_PASSWORD || "password"; 3 | const url = `https://${process.env.CSB_SANDBOX_ID}-3000.${process.env.CSB_BASE_PREVIEW_HOST}` 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 { createProxyMiddleware } = 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 = "pm2 list; ps -ef"; 32 | exec(cmdStr, function (err, stdout, stderr) { 33 | if (err) { 34 | res.type("html").send("
命令行执行错误:\n" + err + "
"); 35 | } else { 36 | res.type("html").send("
获取守护进程和系统进程表:\n" + stdout + "
"); 37 | } 38 | }); 39 | }); 40 | 41 | //获取系统监听端口 42 | app.get("/listen", function (req, res) { 43 | let cmdStr = "ss -nltp"; 44 | exec(cmdStr, function (err, stdout, stderr) { 45 | if (err) { 46 | res.type("html").send("
命令行执行错误:\n" + err + "
"); 47 | } else { 48 | res.type("html").send("
获取系统监听端口:\n" + stdout + "
"); 49 | } 50 | }); 51 | }); 52 | 53 | //获取节点数据 54 | app.get("/list", function (req, res) { 55 | let cmdStr = "bash /app/argo.sh"; 56 | exec(cmdStr, function (err, stdout, stderr) { 57 | if (err) { 58 | res.type("html").send("
命令行执行错误:\n" + err + "
"); 59 | } 60 | else { 61 | res.type("html").send("
节点数据:\n\n" + stdout + "
"); 62 | } 63 | }); 64 | }); 65 | 66 | //获取系统版本、内存信息 67 | app.get("/info", function (req, res) { 68 | let cmdStr = "cat /etc/*release | grep -E ^NAME"; 69 | exec(cmdStr, function (err, stdout, stderr) { 70 | if (err) { 71 | res.send("命令行执行错误:" + err); 72 | } 73 | else { 74 | res.send( 75 | "命令行执行结果:\n" + 76 | "Linux System:" + 77 | stdout + 78 | "\nRAM:" + 79 | os.totalmem() / 1000 / 1000 + 80 | "MB" 81 | ); 82 | } 83 | }); 84 | }); 85 | 86 | //文件系统只读测试 87 | app.get("/test", function (req, res) { 88 | fs.writeFile("./test.txt", "这里是新创建的文件内容!", function (err) { 89 | if (err) { 90 | res.send("创建文件失败,文件系统权限为只读:" + err); 91 | } 92 | else { 93 | res.send("创建文件成功,文件系统权限为非只读:"); 94 | } 95 | }); 96 | }); 97 | 98 | // keepalive begin 99 | //web保活 100 | function keep_web_alive() { 101 | // 请求主页,保持唤醒 102 | exec("curl -m8 " + url, function (err, stdout, stderr) { 103 | if (err) { 104 | console.log("保活-请求主页-命令行执行错误:" + err); 105 | } 106 | else { 107 | console.log("保活-请求主页-命令行执行成功,响应报文:" + stdout); 108 | } 109 | }); 110 | } 111 | setInterval(keep_web_alive, 10 * 1000); 112 | 113 | app.use( 114 | "/", 115 | createProxyMiddleware({ 116 | changeOrigin: true, // 默认false,是否需要改变原始主机头为目标URL 117 | onProxyReq: function onProxyReq(proxyReq, req, res) {}, 118 | pathRewrite: { 119 | // 请求中去除/ 120 | "^/": "/" 121 | }, 122 | target: "http://127.0.0.1:8080/", // 需要跨域处理的请求地址 123 | ws: true // 是否代理websockets 124 | }) 125 | ); 126 | 127 | //启动核心脚本运行web,哪吒和argo 128 | exec("bash /app/entrypoint.sh", function (err, stdout, stderr) { 129 | if (err) { 130 | console.error(err); 131 | return; 132 | } 133 | console.log(stdout); 134 | }); 135 | 136 | app.listen(port, () => console.log(`Example app listening on port ${port}!`)); 137 | -------------------------------------------------------------------------------- /files/web.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fscarmen2/X-for-CodeSandBox/894eae1b793742e645e22c20764eeeb3a8152ecb/files/web.js -------------------------------------------------------------------------------- /tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // These tasks will run in order when initializing your CodeSandbox project. 3 | "setupTasks": [], 4 | 5 | // These tasks can be run from CodeSandbox. Running one will open a log in the app. 6 | "tasks": { 7 | "list": { 8 | "name": "list", 9 | "command": "sleep 5; cat /app/list", 10 | "runAtStart": true 11 | }, 12 | "url": { 13 | "name": "url", 14 | "command": "echo https://$CSB_SANDBOX_ID-3000.$CSB_BASE_PREVIEW_HOST", 15 | "runAtStart": true 16 | } 17 | } 18 | } 19 | --------------------------------------------------------------------------------