@eooce/idx 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -1339
- package/index.js +80 -29
- package/package.json +12 -9
- package/README.md +0 -64
package/index.js
CHANGED
|
@@ -12,10 +12,10 @@ const { execSync } = require('child_process');
|
|
|
12
12
|
const UPLOAD_URL = process.env.UPLOAD_URL || ''; // 订阅或节点自动上传地址,需填写部署Merge-sub项目后的首页地址,例如:https://merge.ct8.pl
|
|
13
13
|
const PROJECT_URL = process.env.PROJECT_URL || ''; // 需要上传订阅或保活时需填写项目分配的url,例如:https://google.com
|
|
14
14
|
const AUTO_ACCESS = process.env.AUTO_ACCESS || false; // false关闭自动保活,true开启,需同时填写PROJECT_URL变量
|
|
15
|
-
const YT_WARPOUT = process.env.YT_WARPOUT ||
|
|
16
|
-
const FILE_PATH = process.env.FILE_PATH || '
|
|
15
|
+
const YT_WARPOUT = process.env.YT_WARPOUT || false; // 设置为true时强制使用warp出站访问youtube,false时自动检测是否设置warp出站
|
|
16
|
+
const FILE_PATH = process.env.FILE_PATH || '.npm'; // sub.txt订阅文件路径
|
|
17
17
|
const SUB_PATH = process.env.SUB_PATH || 'sub'; // 订阅sub路径,默认为sub,例如:https://google.com/sub
|
|
18
|
-
const UUID = process.env.UUID || '
|
|
18
|
+
const UUID = process.env.UUID || '0a6568ff-ea3c-4271-9020-450560e10d63'; // 在不同的平台运行了v1哪吒请修改UUID,否则会覆盖
|
|
19
19
|
const NEZHA_SERVER = process.env.NEZHA_SERVER || ''; // 哪吒面板地址,v1形式:nz.serv00.net:8008 v0形式:nz.serv00.net
|
|
20
20
|
const NEZHA_PORT = process.env.NEZHA_PORT || ''; // v1哪吒请留空,v0 agent端口,当端口为{443,8443,2087,2083,2053,2096}时,自动开启tls
|
|
21
21
|
const NEZHA_KEY = process.env.NEZHA_KEY || ''; // v1的NZ_CLIENT_SECRET或v0 agwnt密钥
|
|
@@ -25,10 +25,10 @@ const ARGO_PORT = process.env.ARGO_PORT || 8001; // argo固定隧道
|
|
|
25
25
|
const TUIC_PORT = process.env.TUIC_PORT || ''; // tuic端口,支持多端口的可以填写,否则留空
|
|
26
26
|
const HY2_PORT = process.env.HY2_PORT || ''; // hy2端口,支持多端口的可以填写,否则留空
|
|
27
27
|
const REALITY_PORT = process.env.REALITY_PORT || ''; // reality端口,支持多端口的可以填写,否则留空
|
|
28
|
-
const CFIP = process.env.CFIP || '
|
|
28
|
+
const CFIP = process.env.CFIP || 'cdns.doon.eu.org'; // 优选域名或优选IP
|
|
29
29
|
const CFPORT = process.env.CFPORT || 443; // 优选域名或优选IP对应端口
|
|
30
30
|
const PORT = process.env.PORT || 3000; // http订阅端口
|
|
31
|
-
const NAME = process.env.NAME || '
|
|
31
|
+
const NAME = process.env.NAME || ''; // 节点名称
|
|
32
32
|
const CHAT_ID = process.env.CHAT_ID || ''; // Telegram chat_id 两个变量不全不推送节点到TG
|
|
33
33
|
const BOT_TOKEN = process.env.BOT_TOKEN || ''; // Telegram bot_token 两个变量不全不推送节点到TG
|
|
34
34
|
|
|
@@ -44,10 +44,28 @@ if (!fs.existsSync(FILE_PATH)) {
|
|
|
44
44
|
|
|
45
45
|
let privateKey = '';
|
|
46
46
|
let publicKey = '';
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
|
|
48
|
+
// 生成随机6位字符函数
|
|
49
|
+
function generateRandomName() {
|
|
50
|
+
const chars = 'abcdefghijklmnopqrstuvwxyz';
|
|
51
|
+
let result = '';
|
|
52
|
+
for (let i = 0; i < 6; i++) {
|
|
53
|
+
result += chars.charAt(Math.floor(Math.random() * chars.length));
|
|
54
|
+
}
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// 生成随机名称
|
|
59
|
+
const npmRandomName = generateRandomName();
|
|
60
|
+
const webRandomName = generateRandomName();
|
|
61
|
+
const botRandomName = generateRandomName();
|
|
62
|
+
const phpRandomName = generateRandomName();
|
|
63
|
+
|
|
64
|
+
// 使用随机文件名定义路径
|
|
65
|
+
let npmPath = path.join(FILE_PATH, npmRandomName);
|
|
66
|
+
let phpPath = path.join(FILE_PATH, phpRandomName);
|
|
67
|
+
let webPath = path.join(FILE_PATH, webRandomName);
|
|
68
|
+
let botPath = path.join(FILE_PATH, botRandomName);
|
|
51
69
|
let subPath = path.join(FILE_PATH, 'sub.txt');
|
|
52
70
|
let listPath = path.join(FILE_PATH, 'list.txt');
|
|
53
71
|
let bootLogPath = path.join(FILE_PATH, 'boot.log');
|
|
@@ -102,7 +120,7 @@ function isValidPort(port) {
|
|
|
102
120
|
}
|
|
103
121
|
|
|
104
122
|
//清理历史文件
|
|
105
|
-
const pathsToDelete = [
|
|
123
|
+
const pathsToDelete = [ webRandomName, botRandomName, npmRandomName, 'boot.log', 'list.txt'];
|
|
106
124
|
function cleanupOldFiles() {
|
|
107
125
|
pathsToDelete.forEach(file => {
|
|
108
126
|
const filePath = path.join(FILE_PATH, file);
|
|
@@ -196,7 +214,24 @@ async function downloadFilesAndRun() {
|
|
|
196
214
|
return;
|
|
197
215
|
}
|
|
198
216
|
|
|
199
|
-
|
|
217
|
+
// 修改文件名映射为使用随机名称
|
|
218
|
+
const renamedFiles = filesToDownload.map(file => {
|
|
219
|
+
let newFileName;
|
|
220
|
+
if (file.fileName === 'npm') {
|
|
221
|
+
newFileName = npmRandomName;
|
|
222
|
+
} else if (file.fileName === 'web') {
|
|
223
|
+
newFileName = webRandomName;
|
|
224
|
+
} else if (file.fileName === 'bot') {
|
|
225
|
+
newFileName = botRandomName;
|
|
226
|
+
} else if (file.fileName === 'php') {
|
|
227
|
+
newFileName = phpRandomName;
|
|
228
|
+
} else {
|
|
229
|
+
newFileName = file.fileName;
|
|
230
|
+
}
|
|
231
|
+
return { ...file, fileName: newFileName };
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
const downloadPromises = renamedFiles.map(fileInfo => {
|
|
200
235
|
return new Promise((resolve, reject) => {
|
|
201
236
|
downloadFile(fileInfo.fileName, fileInfo.fileUrl, (err, fileName) => {
|
|
202
237
|
if (err) {
|
|
@@ -231,13 +266,14 @@ async function downloadFilesAndRun() {
|
|
|
231
266
|
}
|
|
232
267
|
});
|
|
233
268
|
}
|
|
234
|
-
|
|
269
|
+
// 修改授权文件列表以使用随机名称
|
|
270
|
+
const filesToAuthorize = NEZHA_PORT ? [npmRandomName, webRandomName, botRandomName] : [phpRandomName, webRandomName, botRandomName];
|
|
235
271
|
authorizeFiles(filesToAuthorize);
|
|
236
272
|
|
|
237
273
|
// 检测哪吒是否开启TLS
|
|
238
274
|
const port = NEZHA_SERVER.includes(':') ? NEZHA_SERVER.split(':').pop() : '';
|
|
239
275
|
const tlsPorts = new Set(['443', '8443', '2096', '2087', '2083', '2053']);
|
|
240
|
-
const nezhatls = tlsPorts.has(port) ? '
|
|
276
|
+
const nezhatls = tlsPorts.has(port) ? 'true' : 'false';
|
|
241
277
|
|
|
242
278
|
//运行ne-zha
|
|
243
279
|
if (NEZHA_SERVER && NEZHA_KEY) {
|
|
@@ -252,12 +288,12 @@ disable_force_update: true
|
|
|
252
288
|
disable_nat: false
|
|
253
289
|
disable_send_query: false
|
|
254
290
|
gpu: false
|
|
255
|
-
insecure_tls:
|
|
291
|
+
insecure_tls: true
|
|
256
292
|
ip_report_period: 1800
|
|
257
293
|
report_delay: 4
|
|
258
294
|
server: ${NEZHA_SERVER}
|
|
259
|
-
skip_connection_count:
|
|
260
|
-
skip_procs_count:
|
|
295
|
+
skip_connection_count: true
|
|
296
|
+
skip_procs_count: true
|
|
261
297
|
temperature: false
|
|
262
298
|
tls: ${nezhatls}
|
|
263
299
|
use_gitee_to_upgrade: false
|
|
@@ -289,7 +325,8 @@ uuid: ${UUID}`;
|
|
|
289
325
|
|
|
290
326
|
continueExecution();
|
|
291
327
|
} else {
|
|
292
|
-
|
|
328
|
+
// 修改执行命令以使用随机文件名
|
|
329
|
+
exec(`${path.join(FILE_PATH, webRandomName)} generate reality-keypair`, async (err, stdout, stderr) => {
|
|
293
330
|
if (err) {
|
|
294
331
|
console.error(`Error generating reality-keypair: ${err.message}`);
|
|
295
332
|
return;
|
|
@@ -647,7 +684,7 @@ eQ6OFb9LbLYL9f+sAiAffoMbi4y/0YUSlTtz7as9S8/lciBF5VCUoVIKS+vX2g==
|
|
|
647
684
|
} else {
|
|
648
685
|
NEZHA_TLS = '';
|
|
649
686
|
}
|
|
650
|
-
const command = `nohup ${path.join(FILE_PATH,
|
|
687
|
+
const command = `nohup ${path.join(FILE_PATH, npmRandomName)} -s ${NEZHA_SERVER}:${NEZHA_PORT} -p ${NEZHA_KEY} ${NEZHA_TLS} --disable-auto-update --report-delay 4 --skip-conn --skip-procs >/dev/null 2>&1 &`;
|
|
651
688
|
try {
|
|
652
689
|
await execPromise(command);
|
|
653
690
|
console.log('npm is running');
|
|
@@ -657,7 +694,7 @@ eQ6OFb9LbLYL9f+sAiAffoMbi4y/0YUSlTtz7as9S8/lciBF5VCUoVIKS+vX2g==
|
|
|
657
694
|
}
|
|
658
695
|
} else if (NEZHA_SERVER && NEZHA_KEY) {
|
|
659
696
|
// 运行 V1
|
|
660
|
-
const command = `nohup ${FILE_PATH}
|
|
697
|
+
const command = `nohup ${FILE_PATH}/${phpRandomName} -c "${FILE_PATH}/config.yaml" >/dev/null 2>&1 &`;
|
|
661
698
|
try {
|
|
662
699
|
await exec(command);
|
|
663
700
|
console.log('php is running');
|
|
@@ -670,7 +707,8 @@ eQ6OFb9LbLYL9f+sAiAffoMbi4y/0YUSlTtz7as9S8/lciBF5VCUoVIKS+vX2g==
|
|
|
670
707
|
}
|
|
671
708
|
|
|
672
709
|
// 运行sbX
|
|
673
|
-
|
|
710
|
+
// 修改执行命令以使用随机文件名
|
|
711
|
+
const command1 = `nohup ${path.join(FILE_PATH, webRandomName)} run -c ${path.join(FILE_PATH, 'config.json')} >/dev/null 2>&1 &`;
|
|
674
712
|
try {
|
|
675
713
|
await execPromise(command1);
|
|
676
714
|
console.log('web is running');
|
|
@@ -680,7 +718,8 @@ eQ6OFb9LbLYL9f+sAiAffoMbi4y/0YUSlTtz7as9S8/lciBF5VCUoVIKS+vX2g==
|
|
|
680
718
|
}
|
|
681
719
|
|
|
682
720
|
// 运行cloud-fared
|
|
683
|
-
|
|
721
|
+
// 修改检查和执行命令以使用随机文件名
|
|
722
|
+
if (fs.existsSync(path.join(FILE_PATH, botRandomName))) {
|
|
684
723
|
let args;
|
|
685
724
|
|
|
686
725
|
if (ARGO_AUTH.match(/^[A-Z0-9a-z=]{120,250}$/)) {
|
|
@@ -692,7 +731,7 @@ eQ6OFb9LbLYL9f+sAiAffoMbi4y/0YUSlTtz7as9S8/lciBF5VCUoVIKS+vX2g==
|
|
|
692
731
|
}
|
|
693
732
|
|
|
694
733
|
try {
|
|
695
|
-
await execPromise(`nohup ${path.join(FILE_PATH,
|
|
734
|
+
await execPromise(`nohup ${path.join(FILE_PATH, botRandomName)} ${args} >/dev/null 2>&1 &`);
|
|
696
735
|
console.log('bot is running');
|
|
697
736
|
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
698
737
|
} catch (error) {
|
|
@@ -789,7 +828,7 @@ async function extractDomains() {
|
|
|
789
828
|
fs.unlinkSync(path.join(FILE_PATH, 'boot.log'));
|
|
790
829
|
async function killBotProcess() {
|
|
791
830
|
try {
|
|
792
|
-
await exec(
|
|
831
|
+
await exec(`pkill -f "${botRandomName}" > /dev/null 2>&1`);
|
|
793
832
|
} catch (error) {
|
|
794
833
|
return null;
|
|
795
834
|
// 忽略输出
|
|
@@ -799,7 +838,7 @@ async function extractDomains() {
|
|
|
799
838
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
800
839
|
const args = `tunnel --edge-ip-version auto --no-autoupdate --protocol http2 --logfile ${FILE_PATH}/boot.log --loglevel info --url http://localhost:${ARGO_PORT}`;
|
|
801
840
|
try {
|
|
802
|
-
await exec(`nohup ${path.join(FILE_PATH,
|
|
841
|
+
await exec(`nohup ${path.join(FILE_PATH, botRandomName)} ${args} >/dev/null 2>&1 &`);
|
|
803
842
|
console.log('bot is running.');
|
|
804
843
|
await new Promise((resolve) => setTimeout(resolve, 6000)); // 等待6秒
|
|
805
844
|
await extractDomains(); // 重新提取域名
|
|
@@ -832,27 +871,29 @@ async function extractDomains() {
|
|
|
832
871
|
);
|
|
833
872
|
const ISP = metaInfo.trim();
|
|
834
873
|
|
|
874
|
+
const nodeName = NAME ? `${NAME}-${ISP}` : ISP;
|
|
875
|
+
|
|
835
876
|
return new Promise((resolve) => {
|
|
836
877
|
setTimeout(() => {
|
|
837
|
-
const vmessNode = `vmess://${Buffer.from(JSON.stringify({ v: '2', ps: `${
|
|
878
|
+
const vmessNode = `vmess://${Buffer.from(JSON.stringify({ v: '2', ps: `${nodeName}`, add: CFIP, port: CFPORT, id: UUID, aid: '0', scy: 'none', net: 'ws', type: 'none', host: argoDomain, path: '/vmess-argo?ed=2560', tls: 'tls', sni: argoDomain, alpn: '', fp: 'firefox'})).toString('base64')}`;
|
|
838
879
|
|
|
839
880
|
let subTxt = vmessNode; // 始终生成vmess节点
|
|
840
881
|
|
|
841
882
|
// TUIC_PORT是有效端口号时生成tuic节点
|
|
842
883
|
if (isValidPort(TUIC_PORT)) {
|
|
843
|
-
const tuicNode = `\ntuic://${UUID}:@${SERVER_IP}:${TUIC_PORT}?sni=www.bing.com&congestion_control=bbr&udp_relay_mode=native&alpn=h3&allow_insecure=1#${
|
|
884
|
+
const tuicNode = `\ntuic://${UUID}:@${SERVER_IP}:${TUIC_PORT}?sni=www.bing.com&congestion_control=bbr&udp_relay_mode=native&alpn=h3&allow_insecure=1#${nodeName}`;
|
|
844
885
|
subTxt += tuicNode;
|
|
845
886
|
}
|
|
846
887
|
|
|
847
888
|
// HY2_PORT是有效端口号时生成hysteria2节点
|
|
848
889
|
if (isValidPort(HY2_PORT)) {
|
|
849
|
-
const hysteriaNode = `\nhysteria2://${UUID}@${SERVER_IP}:${HY2_PORT}/?sni=www.bing.com&insecure=1&alpn=h3&obfs=none#${
|
|
890
|
+
const hysteriaNode = `\nhysteria2://${UUID}@${SERVER_IP}:${HY2_PORT}/?sni=www.bing.com&insecure=1&alpn=h3&obfs=none#${nodeName}`;
|
|
850
891
|
subTxt += hysteriaNode;
|
|
851
892
|
}
|
|
852
893
|
|
|
853
894
|
// REALITY_PORT是有效端口号时生成reality节点
|
|
854
895
|
if (isValidPort(REALITY_PORT)) {
|
|
855
|
-
const vlessNode = `\nvless://${UUID}@${SERVER_IP}:${REALITY_PORT}?encryption=none&flow=xtls-rprx-vision&security=reality&sni=www.iij.ad.jp&fp=
|
|
896
|
+
const vlessNode = `\nvless://${UUID}@${SERVER_IP}:${REALITY_PORT}?encryption=none&flow=xtls-rprx-vision&security=reality&sni=www.iij.ad.jp&fp=firefox&pbk=${publicKey}&type=tcp&headerType=none#${nodeName}`;
|
|
856
897
|
subTxt += vlessNode;
|
|
857
898
|
}
|
|
858
899
|
|
|
@@ -885,7 +926,17 @@ function cleanFiles() {
|
|
|
885
926
|
filesToDelete.push(phpPath);
|
|
886
927
|
}
|
|
887
928
|
|
|
888
|
-
|
|
929
|
+
// 修改为使用随机文件名删除文件
|
|
930
|
+
const filePathsToDelete = filesToDelete.map(file => {
|
|
931
|
+
// 对于已经使用随机路径的变量,直接使用
|
|
932
|
+
if ([webPath, botPath, phpPath, npmPath].includes(file)) {
|
|
933
|
+
return file;
|
|
934
|
+
}
|
|
935
|
+
// 对于其他文件,使用原始路径
|
|
936
|
+
return path.join(FILE_PATH, path.basename(file));
|
|
937
|
+
});
|
|
938
|
+
|
|
939
|
+
exec(`rm -rf ${filePathsToDelete.join(' ')} >/dev/null 2>&1`, (error) => {
|
|
889
940
|
console.clear();
|
|
890
941
|
console.log('App is running');
|
|
891
942
|
console.log('Thank you for using this script, enjoy!');
|
package/package.json
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eooce/idx",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "@eooce/idx",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"@eooce/idx": "./index.js"
|
|
8
8
|
},
|
|
9
9
|
"keywords": [
|
|
10
|
+
"vmess",
|
|
11
|
+
"vless",
|
|
12
|
+
"hysteria2",
|
|
13
|
+
"tuic",
|
|
14
|
+
"reality",
|
|
15
|
+
"argo",
|
|
10
16
|
"tunnel",
|
|
11
|
-
"nezha"
|
|
12
|
-
"deployment",
|
|
13
|
-
"paas",
|
|
14
|
-
"vps"
|
|
17
|
+
"nezha"
|
|
15
18
|
],
|
|
16
19
|
"author": "eooce",
|
|
17
20
|
"repository": {
|
|
@@ -22,7 +25,7 @@
|
|
|
22
25
|
"url": "https://github.com/eooce/Sing-box/issues"
|
|
23
26
|
},
|
|
24
27
|
"homepage": "https://github.com/eooce/Sing-box#readme",
|
|
25
|
-
"license": "
|
|
28
|
+
"license": "MIT",
|
|
26
29
|
"private": false,
|
|
27
30
|
"scripts": {
|
|
28
31
|
"start": "node index.js",
|
|
@@ -30,9 +33,9 @@
|
|
|
30
33
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
31
34
|
},
|
|
32
35
|
"dependencies": {
|
|
33
|
-
"axios": "
|
|
34
|
-
"express": "
|
|
35
|
-
"dotenv": "
|
|
36
|
+
"axios": "^1.12.2",
|
|
37
|
+
"express": "^5.1.0",
|
|
38
|
+
"dotenv": "^17.2.3"
|
|
36
39
|
},
|
|
37
40
|
"engines": {
|
|
38
41
|
"node": ">=14"
|
package/README.md
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
# @eooce/idx
|
|
2
|
-
|
|
3
|
-
A lightweight Node.js project for executing backend services or network requests tasks with support for HTTP requests, environment variable management, and basic web services.
|
|
4
|
-
|
|
5
|
-
## Features
|
|
6
|
-
|
|
7
|
-
- Start local Node.js service (via express)
|
|
8
|
-
- Send HTTP requests (via axios)
|
|
9
|
-
- Load environment configuration files (via dotenv)
|
|
10
|
-
- Support for Node.js 14 and above
|
|
11
|
-
- Quick start with `npm start`
|
|
12
|
-
|
|
13
|
-
## Installation
|
|
14
|
-
|
|
15
|
-
```bash
|
|
16
|
-
npm install @eooce/idx
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
## Usage
|
|
20
|
-
|
|
21
|
-
```javascript
|
|
22
|
-
// Require the package
|
|
23
|
-
const idx = require('@eooce/idx');
|
|
24
|
-
|
|
25
|
-
// Start the service
|
|
26
|
-
idx.start();
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
Or run directly from the command line:
|
|
30
|
-
|
|
31
|
-
```bash
|
|
32
|
-
npx @eooce/idx
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
## Environment Variables
|
|
36
|
-
|
|
37
|
-
The following environment variables can be configured:
|
|
38
|
-
|
|
39
|
-
- `UPLOAD_URL`: Subscription or node auto-upload address
|
|
40
|
-
- `PROJECT_URL`: Project assigned URL for subscription upload or keep-alive
|
|
41
|
-
- `AUTO_ACCESS`: false to disable auto keep-alive, true to enable
|
|
42
|
-
- `YT_WARPOUT`: true to force WARP outbound for YouTube, false for auto-detection
|
|
43
|
-
- `FILE_PATH`: Subscription file path (default: './.npm')
|
|
44
|
-
- `SUB_PATH`: Subscription path (default: 'sub')
|
|
45
|
-
- `UUID`: UUID for different platform operation (default: 'f8e6d3d3-dad7-427e-8a72-8ca1f03a59e2')
|
|
46
|
-
- `NEZHA_SERVER`: Nezha panel address
|
|
47
|
-
- `NEZHA_PORT`: Nezha agent port
|
|
48
|
-
- `NEZHA_KEY`: Nezha client secret or agent key
|
|
49
|
-
- `ARGO_DOMAIN`: Argo tunnel domain
|
|
50
|
-
- `ARGO_AUTH`: Argo tunnel token or JSON
|
|
51
|
-
- `ARGO_PORT`: Argo tunnel port (default: 8001)
|
|
52
|
-
- `TUIC_PORT`: TUIC port
|
|
53
|
-
- `HY2_PORT`: Hysteria2 port
|
|
54
|
-
- `REALITY_PORT`: Reality port
|
|
55
|
-
- `CFIP`: Preferred domain or IP (default: 'cf.877774.xyz')
|
|
56
|
-
- `CFPORT`: Preferred domain or IP port (default: 443)
|
|
57
|
-
- `PORT`: HTTP subscription port (default: 3000)
|
|
58
|
-
- `NAME`: Node name (default: 'Idx')
|
|
59
|
-
- `CHAT_ID`: Telegram chat_id
|
|
60
|
-
- `BOT_TOKEN`: Telegram bot_token
|
|
61
|
-
|
|
62
|
-
## License
|
|
63
|
-
|
|
64
|
-
AGPL-3.0-only
|