Compare commits

...

33 Commits

Author SHA1 Message Date
mercury 7bcd8de007 vless: reset stats user 2025-01-29 11:04:06 +04:00
mercury 34eb950852 ip-cidr route 2025-01-24 22:09:05 +04:00
mercury 46021855a5 improve wg client menu 2025-01-23 00:55:44 +04:00
mercury 29c18ceb9d update readme 2025-01-20 01:04:24 +04:00
mercury 49d0827b9e update version 2025-01-18 23:39:39 +04:00
mercury 07e04c384a Merge branch 'dev' of github.com:mercurykd/vpnbot into dev 2025-01-18 23:33:29 +04:00
mercury 579457b4f4 show xray stats 2025-01-18 23:33:00 +04:00
mercury 3dac9416ca fix download mihomo template 2025-01-18 23:32:31 +04:00
mercury 5b4d3b5627 reality degenerate pattern improve 2025-01-18 23:31:58 +04:00
mercury 658e125cd8 show group id 2025-01-18 23:31:01 +04:00
Konstantin 1840555573 Merge pull request #33 from legiz-ru/dev
update singbox 1.10.7 windows x64
2025-01-18 18:23:20 +04:00
legiz-ru ecdc028226 update singbox 1.10.7 windows x64 2025-01-18 16:57:39 +03:00
mercury d432bf82f2 force inclusion of xray statistics 2025-01-16 01:04:33 +04:00
mercury 211e2c079d collect xray metrics 2025-01-13 15:32:54 +04:00
Konstantin 1696c4da7b Merge pull request #32 from legiz-ru/dev
v2ray(xray) client templates update
2025-01-12 02:23:56 +04:00
legiz-ru b8d5700eba v2ray(xray) client update
return warp+block domain routes
replace rule for directing
2025-01-12 01:17:23 +03:00
mercury 7e20c14299 update version 2025-01-07 21:02:43 +04:00
mercury b9155cf674 fix show ports on start 2025-01-07 21:00:06 +04:00
mercury 159f775e12 port accounting for shadowsocks 2025-01-07 18:30:57 +04:00
mercury ae672439be return shadowsocks 2025-01-07 18:01:44 +04:00
mercury 6dafba5618 update version 2025-01-04 22:56:21 +04:00
mercury 7daf61a4f5 improve main menu 2025-01-04 21:52:26 +04:00
mercury f9266827c9 ability to install the desired version 2025-01-03 17:09:51 +04:00
mercury 9e22c64771 update readme 2025-01-03 16:22:10 +04:00
mercury a2026a4436 adaptation of the log analyzer 2025-01-03 13:55:49 +04:00
mercury 95c5b5b8fd update version 2024-12-26 18:29:55 +04:00
mercury efbe20485a ability to change subdomain for naiveproxy 2024-12-26 18:28:24 +04:00
mercury 475eea1f47 ability to change subdomain for openconnect 2024-12-26 18:12:42 +04:00
mercury 02d9cdcccc improve update script 2024-12-26 16:59:06 +04:00
mercury d633799f11 update version 2024-12-26 16:26:34 +04:00
Konstantin ead66c3951 Merge pull request #29 from legiz-ru/dev
sb1.10+tun-inbound + sb-win64-1.10.5
2024-12-26 09:46:35 +04:00
legiz-ru bd7742d8b2 update tun inbound (changes in sb 1.10+)
change inet4_address to address

https://sing-box.sagernet.org/migration/#tun-address-fields-are-merged
2024-12-24 16:32:07 +03:00
legiz-ru ac593629a8 update singbox 1.10.5 windows x64 2024-12-24 16:24:58 +03:00
15 changed files with 687 additions and 243 deletions
+348 -67
View File
@@ -37,20 +37,9 @@ class Bot
'xray', 'xray',
]; ];
$this->reg = '~' . implode('|', [ $this->reg = '~' . implode('|', [
'GET /ws HTTP',
'GET /adguard/(?:.+)? HTTP',
'GET /webapp(?:.+)? HTTP',
'GET /pac(?:.+)? HTTP',
'GET \.well-known(?:.+)? HTTP',
'GET /v2ray(?:.+)? HTTP',
'GET /dns-query(?:.+)? HTTP',
'GET / HTTP', 'GET / HTTP',
'GET /tlgrm(?:.+)? HTTP',
'GET /jsoneditor.min.css HTTP',
'GET /jsoneditor.min.js HTTP',
'GET /jquery-3.7.1.min.js HTTP',
'GET /img/jsoneditor-icons.svg HTTP',
'GET /favicon.ico HTTP', 'GET /favicon.ico HTTP',
preg_quote($this->getHashBot())
]) . '~'; ]) . '~';
} }
@@ -249,6 +238,7 @@ class Bot
break; break;
case preg_match('~^/id$~', $this->input['message'], $m): case preg_match('~^/id$~', $this->input['message'], $m):
$this->send($this->input['chat'], $this->input['from'], $this->input['message_id']); $this->send($this->input['chat'], $this->input['from'], $this->input['message_id']);
$this->send($this->input['chat'], $this->input['chat'], $this->input['message_id']);
break; break;
case preg_match('~^/adguardChBr$~', $this->input['callback'], $m): case preg_match('~^/adguardChBr$~', $this->input['callback'], $m):
$this->adguardChBr(); $this->adguardChBr();
@@ -307,7 +297,7 @@ class Bot
case preg_match('~^/delLog (?P<arg>\d+(?:_(?:-)?\d+)?)$~', $this->input['callback'], $m): case preg_match('~^/delLog (?P<arg>\d+(?:_(?:-)?\d+)?)$~', $this->input['callback'], $m):
$this->delLog(...explode('_', $m['arg'])); $this->delLog(...explode('_', $m['arg']));
break; break;
case preg_match('~^/debug$~', $this->input['callback'], $m): case preg_match('~^/debug$~', $this->input['message'], $m):
$this->debug(); $this->debug();
break; break;
case preg_match('~^/backup$~', $this->input['callback'], $m): case preg_match('~^/backup$~', $this->input['callback'], $m):
@@ -358,12 +348,18 @@ class Bot
case preg_match('~^/changeCamouflage$~', $this->input['callback'], $m): case preg_match('~^/changeCamouflage$~', $this->input['callback'], $m):
$this->changeCamouflage(); $this->changeCamouflage();
break; break;
case preg_match('~^/changeOcDomain$~', $this->input['callback'], $m):
$this->changeOcDomain();
break;
case preg_match('~^/changeOcPass$~', $this->input['callback'], $m): case preg_match('~^/changeOcPass$~', $this->input['callback'], $m):
$this->changeOcPass(); $this->changeOcPass();
break; break;
case preg_match('~^/changeNaiveUser$~', $this->input['callback'], $m): case preg_match('~^/changeNaiveUser$~', $this->input['callback'], $m):
$this->changeNaiveUser(); $this->changeNaiveUser();
break; break;
case preg_match('~^/changeNaiveSubdomain$~', $this->input['callback'], $m):
$this->changeNaiveSubdomain();
break;
case preg_match('~^/changeNaivePass$~', $this->input['callback'], $m): case preg_match('~^/changeNaivePass$~', $this->input['callback'], $m):
$this->changeNaivePass(); $this->changeNaivePass();
break; break;
@@ -382,6 +378,9 @@ class Bot
case preg_match('~^/renameXrUser (\d+)$~', $this->input['callback'], $m): case preg_match('~^/renameXrUser (\d+)$~', $this->input['callback'], $m):
$this->renameXrUser($m[1]); $this->renameXrUser($m[1]);
break; break;
case preg_match('~^/resetXrUser (\d+)$~', $this->input['callback'], $m):
$this->resetXrUser($m[1]);
break;
case preg_match('~^/v2ray$~', $this->input['callback'], $m): case preg_match('~^/v2ray$~', $this->input['callback'], $m):
$this->v2ray(); $this->v2ray();
break; break;
@@ -545,6 +544,9 @@ class Bot
case preg_match('~^/xtlsprocess(?: (\d+))?$~', $this->input['callback'], $m): case preg_match('~^/xtlsprocess(?: (\d+))?$~', $this->input['callback'], $m):
$this->xtlsprocess($m[1] ?: 0); $this->xtlsprocess($m[1] ?: 0);
break; break;
case preg_match('~^/xtlssubnet(?: (\d+))?$~', $this->input['callback'], $m):
$this->xtlssubnet($m[1] ?: 0);
break;
case preg_match('~^/xtlsrulesset(?: (\d+))?$~', $this->input['callback'], $m): case preg_match('~^/xtlsrulesset(?: (\d+))?$~', $this->input['callback'], $m):
$this->xtlsrulesset($m[1] ?: 0); $this->xtlsrulesset($m[1] ?: 0);
break; break;
@@ -672,13 +674,73 @@ class Bot
} }
} }
public function restartXray($c) public function restartXray($c, $norestart = false)
{ {
$c['inbounds'][0]['settings']['clients'] = array_values($c['inbounds'][0]['settings']['clients']); $c['inbounds'][0]['settings']['clients'] = array_values($c['inbounds'][0]['settings']['clients']);
$c['log']['access'] = '/logs/xray'; $c['log']['access'] = '/logs/xray';
$this->ssh('pkill xray', 'xr'); foreach ($c['inbounds'] as $v) {
file_put_contents('/config/xray.json', json_encode($c, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)); if ($v['tag'] == 'api') {
$this->ssh('xray run -config /xray.json > /dev/null 2>&1 &', 'xr'); $inbound = true;
break;
}
}
if (empty($inbound)) {
$c['inbounds'][] = [
"listen" => "127.0.0.1",
"port" => 8080,
"protocol" => "dokodemo-door",
"settings" => [
"address" => "127.0.0.1"
],
"tag" => "api"
];
}
foreach ($c['routing']['rules'] as $v) {
if ($v['outboundTag'] == 'api') {
$rule = true;
break;
}
}
if (empty($rule)) {
$c['routing']['rules'][] = [
"inboundTag" => ["api"],
"outboundTag" => "api",
"type" => "field"
];
}
$c['stats'] = new stdClass();
$c['api'] = [
'services' => ['StatsService'],
'tag' => 'api'
];
$l = new stdClass();
$l->{'0'} = [
"statsUserUplink" => true,
"statsUserDownlink" => true
];
$c['policy']['levels'] = $l;
$c['policy']['system'] = [
"statsInboundUplink" => true,
"statsInboundDownlink" => true,
"statsOutboundUplink" => true,
"statsOutboundDownlink" => true
];
if (empty($norestart)) {
$c = $this->collectSession($c);
file_put_contents('/config/xray.json', json_encode($c, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
$this->ssh('pkill xray', 'xr');
$this->ssh('xray run -config /xray.json > /dev/null 2>&1 &', 'xr');
} else {
file_put_contents('/config/xray.json', json_encode($c, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
}
}
public function collectSession($c) {
foreach ($c['inbounds'][0]['settings']['clients'] as $k => $v) {
$c['inbounds'][0]['settings']['clients'][$k]['global']['download'] += $v['session']['download'];
$c['inbounds'][0]['settings']['clients'][$k]['global']['upload'] += $v['session']['upload'];
}
return $c;
} }
public function linkMtproto() public function linkMtproto()
@@ -816,7 +878,7 @@ class Bot
$this->input['chat'], $this->input['chat'],
"@{$this->input['username']} enter camouflage key", "@{$this->input['username']} enter camouflage key",
$this->input['message_id'], $this->input['message_id'],
reply: 'enter password', reply: 'enter camouflage key',
); );
$_SESSION['reply'][$r['result']['message_id']] = [ $_SESSION['reply'][$r['result']['message_id']] = [
'start_message' => $this->input['message_id'], 'start_message' => $this->input['message_id'],
@@ -826,6 +888,22 @@ class Bot
]; ];
} }
public function changeOcDomain()
{
$r = $this->send(
$this->input['chat'],
"@{$this->input['username']} enter subdomain",
$this->input['message_id'],
reply: 'enter subdomain',
);
$_SESSION['reply'][$r['result']['message_id']] = [
'start_message' => $this->input['message_id'],
'start_callback' => $this->input['callback_id'],
'callback' => 'chOcSubdomain',
'args' => [],
];
}
public function changeOcDns() public function changeOcDns()
{ {
$r = $this->send( $r = $this->send(
@@ -864,7 +942,7 @@ class Bot
$this->input['chat'], $this->input['chat'],
"@{$this->input['username']} enter login", "@{$this->input['username']} enter login",
$this->input['message_id'], $this->input['message_id'],
reply: 'enter password', reply: 'enter login',
); );
$_SESSION['reply'][$r['result']['message_id']] = [ $_SESSION['reply'][$r['result']['message_id']] = [
'start_message' => $this->input['message_id'], 'start_message' => $this->input['message_id'],
@@ -874,6 +952,22 @@ class Bot
]; ];
} }
public function changeNaiveSubdomain()
{
$r = $this->send(
$this->input['chat'],
"@{$this->input['username']} enter subdomain",
$this->input['message_id'],
reply: 'enter subdomain',
);
$_SESSION['reply'][$r['result']['message_id']] = [
'start_message' => $this->input['message_id'],
'start_callback' => $this->input['callback_id'],
'callback' => 'chNpSubdomain',
'args' => [],
];
}
public function changeNaivePass() public function changeNaivePass()
{ {
$r = $this->send( $r = $this->send(
@@ -987,6 +1081,34 @@ class Bot
$this->menu('oc'); $this->menu('oc');
} }
public function chOcSubdomain($domain)
{
$pac = $this->getPacConf();
if (empty($domain)) {
unset($pac["oc_domain"]);
} else {
$pac["oc_domain"] = $domain;
}
$this->setPacConf($pac);
$this->chocdomain($pac['domain']);
$this->setUpstreamDomainOcserv($pac['domain']);
$this->menu('oc');
}
public function chNpSubdomain($domain)
{
$pac = $this->getPacConf();
if (!empty($data)) {
unset($pac['np_domain']);
} else {
$pac['np_domain'] = $domain;
}
$this->setPacConf($pac);
$this->restartNaive();
$this->setUpstreamDomainNaive($pac['domain']);
$this->menu('naive');
}
public function chnplogin($user) public function chnplogin($user)
{ {
$pac = $this->getPacConf(); $pac = $this->getPacConf();
@@ -1196,10 +1318,30 @@ class Bot
$this->checkBackup($period); $this->checkBackup($period);
$this->checkCert(); $this->checkCert();
$this->autoAnalyzeLogs(); $this->autoAnalyzeLogs();
$this->xrayStatsUser();
sleep($period); sleep($period);
} }
} }
public function xrayStatsUser()
{
try {
$x = $this->getXray();
if (!empty($users = $x['inbounds'][0]['settings']['clients'])) {
foreach ($users as $k => $v) {
$d = json_decode($this->ssh('xray api stats --server=127.0.0.1:8080 -name "user>>>' . $v['email'] . '>>>traffic>>>downlink" 2>&1', 'xr'), true)['stat']['value'] ?: 0;
$u = json_decode($this->ssh('xray api stats --server=127.0.0.1:8080 -name "user>>>' . $v['email'] . '>>>traffic>>>uplink" 2>&1', 'xr'), true)['stat']['value'] ?: 0;
$x['inbounds'][0]['settings']['clients'][$k]['session'] = [
'download' => $d,
'upload' => $u,
];
}
$this->restartXray($x, norestart: 1);
}
} catch (\Throwable $th) {
}
}
public function autoAnalyzeLogs() public function autoAnalyzeLogs()
{ {
try { try {
@@ -1476,6 +1618,8 @@ class Bot
'xray' => $this->getXray(), 'xray' => $this->getXray(),
'oc' => file_get_contents('/config/ocserv.conf'), 'oc' => file_get_contents('/config/ocserv.conf'),
'ocu' => file_get_contents('/config/ocserv.passwd'), 'ocu' => file_get_contents('/config/ocserv.passwd'),
'ss' => $this->getSSConfig(),
'sl' => $this->getSSLocalConfig(),
]; ];
return json_encode($conf, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); return json_encode($conf, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
@@ -1557,6 +1701,22 @@ class Bot
yaml_emit_file($this->adguard, $json['ad']); yaml_emit_file($this->adguard, $json['ad']);
$this->startAd(); $this->startAd();
} }
// ss
if (!empty($json['ss'])) {
$out[] = 'update shadowsocks server';
$this->update($this->input['chat'], $this->input['message_id'], implode("\n", $out));
$this->ssh('pkill ssserver', 'ss');
file_put_contents('/config/ssserver.json', json_encode($json['ss'], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
$this->ssh('ssserver -v -d -c /config.json', 'ss');
}
// sl
if (!empty($json['sl'])) {
$out[] = 'update shadowsocks proxy';
$this->update($this->input['chat'], $this->input['message_id'], implode("\n", $out));
$this->ssh('pkill sslocal', 'proxy');
file_put_contents('/config/sslocal.json', json_encode($json['sl'], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
$this->ssh('sslocal -v -d -c /config.json', 'proxy');
}
// mtproto // mtproto
if (!empty($json['mtproto'])) { if (!empty($json['mtproto'])) {
$out[] = 'update mtproto'; $out[] = 'update mtproto';
@@ -2539,15 +2699,15 @@ DNS-over-HTTPS with IP:
$this->xtlswarp(); $this->xtlswarp();
break; break;
case 'processlist': case 'processlist':
$this->xrayUpdateRules();
$this->xtlsprocess(); $this->xtlsprocess();
break; break;
case 'packagelist': case 'packagelist':
$this->xrayUpdateRules();
$this->xtlsapp(); $this->xtlsapp();
break; break;
case 'subnetlist':
$this->xtlssubnet();
break;
case 'rulessetlist': case 'rulessetlist':
$this->xrayUpdateRules();
$this->xtlsrulesset(); $this->xtlsrulesset();
break; break;
case 'white': case 'white':
@@ -3362,8 +3522,6 @@ DNS-over-HTTPS with IP:
'text' => $this->i18n('delete'), 'text' => $this->i18n('delete'),
'callback_data' => "/delete {$client}_$page", 'callback_data' => "/delete {$client}_$page",
], ],
],
[
[ [
'text' => $this->i18n('back'), 'text' => $this->i18n('back'),
'callback_data' => "/menu wg $page", 'callback_data' => "/menu wg $page",
@@ -3597,6 +3755,12 @@ DNS-over-HTTPS with IP:
case 'packagelist': case 'packagelist':
$dir = 'PACKAGE'; $dir = 'PACKAGE';
break; break;
case 'processlist':
$dir = 'PROCESS';
break;
case 'subnetlist':
$dir = 'SUBNET';
break;
case 'rulessetlist': case 'rulessetlist':
$dir = 'rulesset'; $dir = 'rulesset';
break; break;
@@ -3643,6 +3807,22 @@ DNS-over-HTTPS with IP:
], ],
]; ];
break; break;
case 'processlist':
$data[] = [
[
'text' => $this->i18n('back'),
'callback_data' => "/xtlsprocess",
],
];
break;
case 'subnetlist':
$data[] = [
[
'text' => $this->i18n('back'),
'callback_data' => "/xtlssubnet",
],
];
break;
case 'rulessetlist': case 'rulessetlist':
$data[] = [ $data[] = [
[ [
@@ -3790,7 +3970,25 @@ DNS-over-HTTPS with IP:
$text[] = "Menu -> " . $this->i18n('xray') . ' -> ' . $this->i18n('routes') . ' -> process list'; $text[] = "Menu -> " . $this->i18n('xray') . ' -> ' . $this->i18n('routes') . ' -> process list';
[$data] = $this->listPac('processlist', $page, 'xtlsprocess'); [$data] = $this->listPac('processlist', $page, 'xtlsprocess');
$p = $this->getPacConf(); $data[] = [
[
'text' => $this->i18n('back'),
'callback_data' => "/routes",
],
];
$this->update(
$this->input['chat'],
$this->input['message_id'],
implode("\n", $text ?: ['...']),
$data ?: false,
);
}
public function xtlssubnet($page = 0)
{
$text[] = "Menu -> " . $this->i18n('xray') . ' -> ' . $this->i18n('routes') . ' -> subnet';
[$data] = $this->listPac('subnetlist', $page, 'xtlssubnet');
$data[] = [ $data[] = [
[ [
'text' => $this->i18n('back'), 'text' => $this->i18n('back'),
@@ -3846,7 +4044,7 @@ DNS-over-HTTPS with IP:
} }
$data[] = [ $data[] = [
[ [
'text' => $this->i18n($v ? 'on' : 'off') . ' ' . ($basename ? basename($k) . ' ' : '') . (in_array($type, ['rulessetlist', 'packagelist', 'processlist']) ? $k : idn_to_utf8($k)), 'text' => $this->i18n($v ? 'on' : 'off') . ' ' . ($basename ? basename($k) . ' ' : '') . (in_array($type, ['rulessetlist', 'packagelist', 'processlist', 'subnetlist']) ? $k : idn_to_utf8($k)),
'callback_data' => "/change$type " . ($i + $page * $this->limit), 'callback_data' => "/change$type " . ($i + $page * $this->limit),
], ],
[ [
@@ -3940,14 +4138,12 @@ DNS-over-HTTPS with IP:
public function menuSS() public function menuSS()
{ {
$conf = $this->getPacConf(); $hash = $this->getHashBot();
$ip = $this->ip;
$domain = $this->getDomain(); $domain = $this->getDomain();
$scheme = empty($ssl = $this->nginxGetTypeCert()) ? 'http' : 'https';
$ss = $this->getSSConfig(); $ss = $this->getSSConfig();
$v2ray = !empty($ss['plugin']) ? 'ON' : 'OFF'; $v2ray = !empty($ss['plugin']) ? 'ON' : 'OFF';
$port = !empty($ss['plugin']) ? (!empty($ssl) ? 443 : 80) : getenv('SSPORT'); $port = !empty($ss['plugin']) ? 443 : getenv('SSPORT');
$options = !empty($ssl) && !empty($ss['plugin']) ? "tls;fast-open;path=/v2ray;host=$domain" : "path=/v2ray;host=$domain"; $options = !empty($ss['plugin']) ? "tls;fast-open;path=/v2ray$hash;host=$domain" : "path=/v2ray$hash;host=$domain";
$text = "Menu -> ShadowSocks"; $text = "Menu -> ShadowSocks";
$data[] = [ $data[] = [
@@ -3956,7 +4152,7 @@ DNS-over-HTTPS with IP:
'callback_data' => "/sspswd", 'callback_data' => "/sspswd",
], ],
]; ];
$ss_link = preg_replace('~==~', '', 'ss://' . base64_encode("{$ss['method']}:{$ss['password']}")) . "@$domain:$port" . (!empty($ss['plugin']) ? '?plugin=' . urlencode("v2ray-plugin;path=/v2ray;host=$domain" . (!empty($ssl) ? ';tls' : '')) : ''); $ss_link = preg_replace('~==~', '', 'ss://' . base64_encode("{$ss['method']}:{$ss['password']}")) . "@$domain:$port" . (!empty($ss['plugin']) ? '?plugin=' . urlencode("v2ray-plugin;path=/v2ray$hash;host=$domain;tls") : '');
$text .= "\n\n<code>$ss_link</code>\n"; $text .= "\n\n<code>$ss_link</code>\n";
$text .= "\n\npassword: <span class='tg-spoiler'>{$ss['password']}</span>"; $text .= "\n\npassword: <span class='tg-spoiler'>{$ss['password']}</span>";
$text .= "\n\nserver: <code>$domain:$port</code>"; $text .= "\n\nserver: <code>$domain:$port</code>";
@@ -4024,16 +4220,17 @@ DNS-over-HTTPS with IP:
$c = yaml_parse_file($f)['services']; $c = yaml_parse_file($f)['services'];
$main[] = 'v' . getenv('VER') . " $branch" . ($update ? ' (have updates)' : ''); $main[] = 'v' . getenv('VER') . " $branch" . ($update ? ' (have updates)' : '');
$main[] = ''; $main[] = '';
$main[] = $this->i18n($c['wg'] ? 'on' : 'off') . ' ' . getenv('WGPORT') . ' Wireguard';
$main[] = $this->i18n($c['wg1'] ? 'on' : 'off') . ' ' . getenv('WG1PORT') . ' Wireguard 1';
$main[] = $this->i18n($c['tg'] ? 'on' : 'off') . ' ' . getenv('TGPORT') . ' MTProto';
$main[] = $this->i18n($c['ad'] ? 'on' : 'off') . ' 853 AdguardHome DoT';
$main[] = '';
$main[] = $cron; $main[] = $cron;
$main[] = $this->i18n($backup ? 'on' : 'off') . ' autobackup' . ($backup ? " $backup" : ''); $main[] = $this->i18n($backup ? 'on' : 'off') . ' autobackup' . ($backup ? " $backup" : '');
$main[] = $this->i18n($conf['autoupdate'] ? 'on' : 'off') . ' autoupdate'; $main[] = $this->i18n($conf['autoupdate'] ? 'on' : 'off') . ' autoupdate';
$main[] = $this->i18n($conf['autoscan'] ? 'on' : 'off') . ' autoscan'; $main[] = $this->i18n($conf['autoscan'] ? 'on' : 'off') . ' autoscan';
$main[] = $this->i18n($conf['autodeny'] ? 'on' : 'off') . ' autoblock' . ($conf['deny'] ? ': ' . count($conf['deny']) : ''); $main[] = $this->i18n($conf['autodeny'] ? 'on' : 'off') . ' autoblock' . ($conf['deny'] ? ': ' . count($conf['deny']) : '');
$main[] = '';
$main[] = $this->i18n($c['wg'] ? 'on' : 'off') . ' ' . getenv('WGPORT') . ' Wireguard';
$main[] = $this->i18n($c['wg1'] ? 'on' : 'off') . ' ' . getenv('WG1PORT') . ' Wireguard 1';
$main[] = $this->i18n($c['tg'] ? 'on' : 'off') . ' ' . getenv('TGPORT') . ' MTProto';
$main[] = $this->i18n($c['ad'] ? 'on' : 'off') . ' 853 AdguardHome DoT';
$main[] = $this->i18n($c['ss'] ? 'on' : 'off') . ' 8388 Shadowsocks';
if (!empty($conf['domain'])) { if (!empty($conf['domain'])) {
$main[] = ''; $main[] = '';
$oc = $this->getHashSubdomain('oc'); $oc = $this->getHashSubdomain('oc');
@@ -4047,12 +4244,6 @@ DNS-over-HTTPS with IP:
'main' => [ 'main' => [
'text' => implode("\n", $main ?: []), 'text' => implode("\n", $main ?: []),
'data' => [ 'data' => [
[
[
'text' => $this->i18n('config'),
'callback_data' => "/menu config",
],
],
[ [
[ [
'text' => $this->i18n($this->getPacConf()['amnezia'] ? 'amnezia' : 'wg_title'), 'text' => $this->i18n($this->getPacConf()['amnezia'] ? 'amnezia' : 'wg_title'),
@@ -4094,15 +4285,25 @@ DNS-over-HTTPS with IP:
], ],
], ],
[ [
[
'text' => $this->i18n('sh_title'),
'callback_data' => "/menu ss",
],
[ [
'text' => $this->i18n('pac'), 'text' => $this->i18n('pac'),
'callback_data' => "/pacMenu 0", 'callback_data' => "/pacMenu 0",
], ],
], ],
[
[
'text' => $this->i18n('config'),
'callback_data' => "/menu config",
],
],
[ [
[ [
'text' => $this->i18n('chat'), 'text' => $this->i18n('chat'),
'url' => "https://t.me/+Wfxg6-nrokBlMmYy", 'url' => base64_decode('aHR0cHM6Ly90Lm1lLytXZnhnNi1ucm9rQmxNbVl5'),
], ],
[ [
'text' => $this->i18n('donate'), 'text' => $this->i18n('donate'),
@@ -4350,7 +4551,6 @@ DNS-over-HTTPS with IP:
} }
$t = [ $t = [
$this->suspicious('~\d+\.\d+\.\d+\.\d+.+200\s\d+\s0$~', '/logs/upstream_access', $xr, 'possibly a Reality Degenerate'),
$this->suspicious($this->reg, '/logs/nginx_default_access', $xr, 'possibly a scanner', true), $this->suspicious($this->reg, '/logs/nginx_default_access', $xr, 'possibly a scanner', true),
$this->suspicious($this->reg, '/logs/nginx_domain_access', $xr, 'possibly a scanner', true), $this->suspicious($this->reg, '/logs/nginx_domain_access', $xr, 'possibly a scanner', true),
]; ];
@@ -4362,6 +4562,15 @@ DNS-over-HTTPS with IP:
} }
} }
$r = $this->suspicious('~\d+\.\d+\.\d+\.\d+.+200\s\d+\s0$~', '/logs/upstream_access', $xr, 'possibly a Reality Degenerate');
if (!empty($r)) {
foreach ($r as $k => $v) {
if (count($v) > 30) {
$ip[$k] = $v;
}
}
}
if (!empty($return)) { if (!empty($return)) {
return $ip; return $ip;
} }
@@ -4823,6 +5032,12 @@ DNS-over-HTTPS with IP:
$text[] = "Menu -> NaiveProxy"; $text[] = "Menu -> NaiveProxy";
$np = $this->getHashSubdomain('np'); $np = $this->getHashSubdomain('np');
$text[] = "<code>https://{$pac['naive']['user']}:{$pac['naive']['pass']}@$np.$domain</code>"; $text[] = "<code>https://{$pac['naive']['user']}:{$pac['naive']['pass']}@$np.$domain</code>";
$data[] = [
[
'text' => $this->i18n('change subdomain'),
'callback_data' => "/changeNaiveSubdomain",
],
];
$data[] = [ $data[] = [
[ [
'text' => $this->i18n('change login'), 'text' => $this->i18n('change login'),
@@ -4926,6 +5141,12 @@ DNS-over-HTTPS with IP:
$text[] = "<code>https://$oc.$domain/?$cs</code>"; $text[] = "<code>https://$oc.$domain/?$cs</code>";
} }
$text[] = "password: <span class='tg-spoiler'>$pass</span>"; $text[] = "password: <span class='tg-spoiler'>$pass</span>";
$data[] = [
[
'text' => $this->i18n('change subdomain'),
'callback_data' => "/changeOcDomain",
],
];
$data[] = [ $data[] = [
[ [
'text' => $this->i18n('change secret'), 'text' => $this->i18n('change secret'),
@@ -5049,15 +5270,15 @@ DNS-over-HTTPS with IP:
public function setTimerXr($time, $i) public function setTimerXr($time, $i)
{ {
$time = strtotime($time);
if ($time === false) {
$this->send($this->input['chat'], 'wrong format');
return;
}
$c = $this->getXray(); $c = $this->getXray();
if (empty($time)) { if (empty($time)) {
unset($c['inbounds'][0]['settings']['clients'][$i]['time']); unset($c['inbounds'][0]['settings']['clients'][$i]['time']);
} else { } else {
$time = strtotime($time);
if ($time === false) {
$this->send($this->input['chat'], 'wrong format');
return;
}
if (!empty($c['inbounds'][0]['settings']['clients'][$i]['off'])) { if (!empty($c['inbounds'][0]['settings']['clients'][$i]['off'])) {
$this->switchXr($i, 1); $this->switchXr($i, 1);
$c = $this->getXray(); $c = $this->getXray();
@@ -5094,6 +5315,17 @@ DNS-over-HTTPS with IP:
$this->userXr($i); $this->userXr($i);
} }
public function resetXrUser($i)
{
$c = $this->getXray();
$c['inbounds'][0]['settings']['clients'][$i]['global'] = [
'download' => 0,
'upload' => 0,
];
$this->restartXray($c);
$this->userXr($i);
}
public function listXr($i) public function listXr($i)
{ {
$c = $this->getPacConf(); $c = $this->getPacConf();
@@ -5226,14 +5458,7 @@ DNS-over-HTTPS with IP:
public function downloadOrigin($type) public function downloadOrigin($type)
{ {
switch ($type) { $f = new \CURLFile("/config/$type.json", 'application/json', 'origin.json');
case 'sing':
$f = new \CURLFile('/config/sing.json', 'application/json', 'origin.json');
break;
case 'v2ray':
$f = new \CURLFile('/config/v2ray.json', 'application/json', 'origin.json');
break;
}
$this->sendFile($this->input['chat'], $f); $this->sendFile($this->input['chat'], $f);
} }
@@ -5368,6 +5593,25 @@ DNS-over-HTTPS with IP:
$this->xray(); $this->xray();
} }
public function getBytes($bytes)
{
$t = [
'B',
'KB',
'MB',
'GB',
'TB',
];
foreach ($t as $k => $v) {
if ($k == 0) {
continue;
}
if ($bytes / (1024 ** $k) < 1) {
return round($bytes / (1024 ** ($k - 1)), 2) . " {$t[$k - 1]}";
}
}
}
public function xray($page = 0) public function xray($page = 0)
{ {
if (!$this->ssh('pgrep xray', 'xr')) { if (!$this->ssh('pgrep xray', 'xr')) {
@@ -5450,10 +5694,12 @@ DNS-over-HTTPS with IP:
$page = $page == -2 ? $all - 1 : $page; $page = $page == -2 ? $all - 1 : $page;
$clients = $page != -1 ? array_slice($clients, $page * $this->limit, $this->limit, true) : $clients; $clients = $page != -1 ? array_slice($clients, $page * $this->limit, $this->limit, true) : $clients;
foreach ($clients as $k => $v) { foreach ($clients as $k => $v) {
$time = $v['time'] ? $this->getTime($v['time']) : ''; $download = $this->getBytes($v['global']['download'] + $v['session']['download']);
$data[] = [ $upload = $this->getBytes($v['global']['upload'] + $v['session']['upload']);
$time = $v['time'] ? $this->getTime($v['time']) : '';
$data[] = [
[ [
'text' => "{$v['email']}" . ($time ? ": $time" : ''), 'text' => "{$v['email']}" . ($time ? ": $time" : '') . " (↓$download$upload)",
'callback_data' => "/userXr $k", 'callback_data' => "/userXr $k",
], ],
]; ];
@@ -5503,9 +5749,6 @@ DNS-over-HTTPS with IP:
{ {
$text[] = "Menu -> " . $this->i18n('xray') . ' -> routes'; $text[] = "Menu -> " . $this->i18n('xray') . ' -> routes';
$p = $this->getPacConf();
$outbound = $p['outbound'] ?: 'proxy';
$data = [ $data = [
[[ [[
'text' => $this->i18n('block'), 'text' => $this->i18n('block'),
@@ -5519,6 +5762,10 @@ DNS-over-HTTPS with IP:
'text' => 'domains', 'text' => 'domains',
'callback_data' => "/xtlsproxy", 'callback_data' => "/xtlsproxy",
]], ]],
[[
'text' => "subnet",
'callback_data' => "/xtlssubnet",
]],
[[ [[
'text' => 'process', 'text' => 'process',
'callback_data' => "/xtlsprocess", 'callback_data' => "/xtlsprocess",
@@ -5797,6 +6044,14 @@ DNS-over-HTTPS with IP:
'callback_data' => "/qrXray {$i}_2", 'callback_data' => "/qrXray {$i}_2",
], ],
]; ];
$download = $this->getBytes($c['global']['download'] + $c['session']['download']);
$upload = $this->getBytes($c['global']['upload'] + $c['session']['upload']);
$data[] = [
[
'text' => $this->i18n('reset stats') . ": ↓$download$upload",
'callback_data' => "/resetXrUser $i",
],
];
$data[] = [ $data[] = [
[ [
'text' => $this->i18n('rename'), 'text' => $this->i18n('rename'),
@@ -6037,6 +6292,7 @@ DNS-over-HTTPS with IP:
'"~warp~"' => json_encode(array_keys(array_filter($pac['warplist'] ?: []))), '"~warp~"' => json_encode(array_keys(array_filter($pac['warplist'] ?: []))),
'"~process~"' => json_encode(array_keys(array_filter($pac['processlist'] ?: []))), '"~process~"' => json_encode(array_keys(array_filter($pac['processlist'] ?: []))),
'"~package~"' => json_encode(array_keys(array_filter($pac['packagelist'] ?: []))), '"~package~"' => json_encode(array_keys(array_filter($pac['packagelist'] ?: []))),
'"~subnet~"' => json_encode(array_keys(array_filter($pac['subnetlist'] ?: []))),
'~dns~' => "https://$domain/dns-query$hash/$uid", '~dns~' => "https://$domain/dns-query$hash/$uid",
'~uid~' => $uid, '~uid~' => $uid,
'~domain~' => $domain, '~domain~' => $domain,
@@ -6146,6 +6402,9 @@ DNS-over-HTTPS with IP:
case 'domain': case 'domain':
echo yaml_emit(['payload' => array_map(fn($e) => "+.$e", $v['list'])]); echo yaml_emit(['payload' => array_map(fn($e) => "+.$e", $v['list'])]);
break; break;
case 'ipcidr':
echo yaml_emit(['payload' => array_map(fn($e) => $e, $v['list'])]);
break;
default: default:
echo yaml_emit(['payload' => array_map(fn($e) => "PROCESS-NAME,$e", $v['list'])]); echo yaml_emit(['payload' => array_map(fn($e) => "PROCESS-NAME,$e", $v['list'])]);
@@ -6373,7 +6632,7 @@ DNS-over-HTTPS with IP:
location location
CONF; CONF;
$template = preg_replace('~(location /adguard.+?})\s*location~s', $r, $template); $template = preg_replace('~(location /adguard.+?})\s*location~s', $r, $template);
$template = preg_replace('~(/webapp|/pac|/adguard|/ws|location /dns-query)~', '${1}' . $h, $template); $template = preg_replace('~(/webapp|/pac|/adguard|/ws|/v2ray|location /dns-query)~', '${1}' . $h, $template);
file_put_contents('/config/nginx.conf', $template); file_put_contents('/config/nginx.conf', $template);
$x = $this->getXray(); $x = $this->getXray();
if (!empty($x['inbounds'][0]['streamSettings']['wsSettings']['path'])) { if (!empty($x['inbounds'][0]['streamSettings']['wsSettings']['path'])) {
@@ -6386,7 +6645,7 @@ DNS-over-HTTPS with IP:
public function getHashSubdomain($subdomain) public function getHashSubdomain($subdomain)
{ {
return substr(hash('sha256', "$subdomain{$this->key}"), 0, 8); return $this->getPacConf()["{$subdomain}_domain"] ?: substr(hash('sha256', "$subdomain{$this->key}"), 0, 8);
} }
public function addWg($page) public function addWg($page)
@@ -6741,6 +7000,8 @@ DNS-over-HTTPS with IP:
'text' => $this->i18n('Ports'), 'text' => $this->i18n('Ports'),
'callback_data' => "/ports", 'callback_data' => "/ports",
], ],
];
$data[] = [
[ [
'text' => $this->i18n('IP ban & Logs'), 'text' => $this->i18n('IP ban & Logs'),
'callback_data' => "/ipMenu", 'callback_data' => "/ipMenu",
@@ -6831,6 +7092,7 @@ DNS-over-HTTPS with IP:
$text[] = 'Settings -> Ports'; $text[] = 'Settings -> Ports';
$f = '/docker/compose'; $f = '/docker/compose';
$c = yaml_parse_file($f)['services']; $c = yaml_parse_file($f)['services'];
$pac = $this->getPacConf();
$data = [ $data = [
[[ [[
'text' => $this->i18n($c['wg'] ? 'on' : 'off') . ' ' . getenv('WGPORT') . ' Wireguard', 'text' => $this->i18n($c['wg'] ? 'on' : 'off') . ' ' . getenv('WGPORT') . ' Wireguard',
@@ -6848,7 +7110,19 @@ DNS-over-HTTPS with IP:
'text' => $this->i18n($c['ad'] ? 'on' : 'off') . ' 853 AdguardHome DoT', 'text' => $this->i18n($c['ad'] ? 'on' : 'off') . ' 853 AdguardHome DoT',
'callback_data' => "/hidePort ad", 'callback_data' => "/hidePort ad",
]], ]],
[[
'text' => $this->i18n($c['ss'] ? 'on' : 'off') . ' 8388 Shadowsocks',
'callback_data' => "/hidePort ss",
]],
]; ];
if (!empty($pac['restart'])) {
$data[] = [
[
'text' => $this->i18n('restart'),
'callback_data' => "/restart",
],
];
}
$data[] = [ $data[] = [
[ [
'text' => $this->i18n('back'), 'text' => $this->i18n('back'),
@@ -6870,6 +7144,7 @@ DNS-over-HTTPS with IP:
'wg1' => getenv('WG1PORT') . ':' . getenv('WG1PORT') . '/udp', 'wg1' => getenv('WG1PORT') . ':' . getenv('WG1PORT') . '/udp',
'tg' => getenv('TGPORT') . ':' . getenv('TGPORT'), 'tg' => getenv('TGPORT') . ':' . getenv('TGPORT'),
'ad' => '853:853', 'ad' => '853:853',
'ss' => '8388:8388',
]; ];
$f = '/docker/compose'; $f = '/docker/compose';
$c = yaml_parse_file($f); $c = yaml_parse_file($f);
@@ -6883,7 +7158,10 @@ DNS-over-HTTPS with IP:
} else { } else {
yaml_emit_file($f, $c); yaml_emit_file($f, $c);
} }
$this->restart(); $pac = $this->getPacConf();
$pac['restart'] = 1;
$this->setPacConf($pac);
$this->ports();
} }
public function branches() public function branches()
@@ -7020,6 +7298,9 @@ DNS-over-HTTPS with IP:
} }
file_put_contents('/update/message', ''); file_put_contents('/update/message', '');
file_put_contents('/update/reload_message', ''); file_put_contents('/update/reload_message', '');
$pac = $this->getPacConf();
unset($pac['restart']);
$this->setPacConf($pac);
} }
public function backup() public function backup()
+1 -1
View File
@@ -30,7 +30,7 @@ $i = [
'ru' => 'PAC', 'ru' => 'PAC',
], ],
'chat' => [ 'chat' => [
'en' => 'discussion group', 'en' => 'chat',
'ru' => 'чат поддержки', 'ru' => 'чат поддержки',
], ],
'back' => [ 'back' => [
+1
View File
@@ -13,6 +13,7 @@ if ($c['debug']) {
$bot = new Bot($c['key'], $i); $bot = new Bot($c['key'], $i);
$bot->selfUpdate(); $bot->selfUpdate();
$bot->ssPswdCheck();
$bot->restartTG(); $bot->restartTG();
if (!empty($bot->selfupdate)) { if (!empty($bot->selfupdate)) {
$bot->offWarp(); $bot->offWarp();
+8
View File
@@ -133,6 +133,14 @@
"behavior": "domain", "behavior": "domain",
"name": "pac" "name": "pac"
}, },
{
"type": "RULE-SET",
"list": "~subnet~",
"action": "PROXY",
"interval": 30,
"behavior": "ipcidr",
"name": "subnet"
},
{ {
"type": "MATCH", "type": "MATCH",
"action": "DIRECT" "action": "DIRECT"
+24
View File
@@ -97,6 +97,18 @@ http {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_read_timeout 5d; proxy_read_timeout 5d;
} }
location /v2ray {
access_log /logs/nginx_v2ray_access;
proxy_redirect off;
proxy_buffering off;
proxy_http_version 1.1;
proxy_pass http://ss:8388/;
proxy_set_header Host $http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
location /dns-query { location /dns-query {
access_log /logs/nginx_doh_access; access_log /logs/nginx_doh_access;
proxy_http_version 1.1; proxy_http_version 1.1;
@@ -162,6 +174,17 @@ http {
# proxy_pass http://php; # proxy_pass http://php;
# } # }
# location /v2ray {
# access_log /logs/nginx_v2ray_access;
# proxy_redirect off;
# proxy_buffering off;
# proxy_http_version 1.1;
# proxy_pass http://ss:8388/;
# proxy_set_header Host $http_host;
# proxy_set_header Upgrade $http_upgrade;
# proxy_set_header Connection "upgrade";
# }
# location /ws { # location /ws {
# proxy_pass http://xr:443; # proxy_pass http://xr:443;
# proxy_redirect off; # proxy_redirect off;
@@ -173,6 +196,7 @@ http {
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# proxy_read_timeout 5d; # proxy_read_timeout 5d;
# } # }
# location /dns-query { # location /dns-query {
# access_log /logs/nginx_doh_access; # access_log /logs/nginx_doh_access;
# proxy_http_version 1.1; # proxy_http_version 1.1;
+24
View File
@@ -97,6 +97,18 @@ http {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_read_timeout 5d; proxy_read_timeout 5d;
} }
location /v2ray {
access_log /logs/nginx_v2ray_access;
proxy_redirect off;
proxy_buffering off;
proxy_http_version 1.1;
proxy_pass http://ss:8388/;
proxy_set_header Host $http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
location /dns-query { location /dns-query {
access_log /logs/nginx_doh_access; access_log /logs/nginx_doh_access;
proxy_http_version 1.1; proxy_http_version 1.1;
@@ -162,6 +174,17 @@ http {
# proxy_pass http://php; # proxy_pass http://php;
# } # }
# location /v2ray {
# access_log /logs/nginx_v2ray_access;
# proxy_redirect off;
# proxy_buffering off;
# proxy_http_version 1.1;
# proxy_pass http://ss:8388/;
# proxy_set_header Host $http_host;
# proxy_set_header Upgrade $http_upgrade;
# proxy_set_header Connection "upgrade";
# }
# location /ws { # location /ws {
# proxy_pass http://xr:443; # proxy_pass http://xr:443;
# proxy_redirect off; # proxy_redirect off;
@@ -173,6 +196,7 @@ http {
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# proxy_read_timeout 5d; # proxy_read_timeout 5d;
# } # }
# location /dns-query { # location /dns-query {
# access_log /logs/nginx_doh_access; # access_log /logs/nginx_doh_access;
# proxy_http_version 1.1; # proxy_http_version 1.1;
+17 -2
View File
@@ -9,7 +9,7 @@
"tag": "tun-in", "tag": "tun-in",
"domain_strategy": "prefer_ipv4", "domain_strategy": "prefer_ipv4",
"interface_name": "sing-tun", "interface_name": "sing-tun",
"inet4_address": "172.19.0.1\/30", "address": ["172.19.0.1\/30"],
"mtu": 1400, "mtu": 1400,
"gso": true, "gso": true,
"auto_route": true, "auto_route": true,
@@ -129,6 +129,21 @@
], ],
"outbound": "~outbound~" "outbound": "~outbound~"
}, },
{
"addruleset": true,
"createruleset": [
{
"name": "subnet",
"interval": "30s",
"rules": [
{
"ip_cidr": "~subnet~"
}
]
}
],
"outbound": "~outbound~"
},
{ {
"addruleset": true, "addruleset": true,
"createruleset": [ "createruleset": [
@@ -192,4 +207,4 @@
], ],
"final": "direct" "final": "direct"
} }
} }
+111 -81
View File
@@ -4,92 +4,122 @@
"error": "", "error": "",
"loglevel": "warning" "loglevel": "warning"
}, },
"inbounds": [{ "inbounds": [
"tag": "socks", {
"port": 10808, "tag": "socks",
"listen": "127.0.0.1", "port": 10808,
"protocol": "socks", "listen": "127.0.0.1",
"sniffing": { "protocol": "socks",
"enabled": true, "sniffing": {
"destOverride": ["http", "tls"], "enabled": true,
"routeOnly": false "destOverride": [
}, "http",
"settings": { "tls"
"auth": "noauth", ],
"udp": true, "routeOnly": false
"allowTransparent": false },
} "settings": {
}, { "auth": "noauth",
"tag": "http", "udp": true,
"port": 10809, "allowTransparent": false
"listen": "127.0.0.1",
"protocol": "http",
"sniffing": {
"enabled": true,
"destOverride": ["http", "tls"],
"routeOnly": false
},
"settings": {
"auth": "noauth",
"udp": true,
"allowTransparent": false
}
}],
"outbounds": [{
"tag": "~outbound~",
"protocol": "vless",
"settings": {
"vnext": [{
"address": "~domain~",
"port": 443,
"users": [{
"id": "~uid~",
"alterId": 0,
"email": "t@t.tt",
"security": "auto",
"encryption": "none",
"flow": "xtls-rprx-vision"
}]
}]
},
"streamSettings": {
"network": "tcp",
"security": "reality",
"realitySettings": {
"serverName": "~server_name~",
"fingerprint": "chrome",
"show": false,
"publicKey": "~public_key~",
"shortId": "~short_id~",
"spiderX": ""
} }
}, },
"mux": { {
"enabled": false, "tag": "http",
"concurrency": -1 "port": 10809,
} "listen": "127.0.0.1",
}, { "protocol": "http",
"tag": "direct", "sniffing": {
"protocol": "freedom" "enabled": true,
}, { "destOverride": [
"tag": "block", "http",
"protocol": "blackhole", "tls"
"settings": { ],
"response": { "routeOnly": false
"type": "http" },
"settings": {
"auth": "noauth",
"udp": true,
"allowTransparent": false
} }
} }
}], ],
"outbounds": [
{
"tag": "direct",
"protocol": "freedom"
},
{
"tag": "~outbound~",
"protocol": "vless",
"settings": {
"vnext": [
{
"address": "~domain~",
"port": 443,
"users": [
{
"id": "~uid~",
"alterId": 0,
"email": "t@t.tt",
"security": "auto",
"encryption": "none",
"flow": "xtls-rprx-vision"
}
]
}
]
},
"streamSettings": {
"network": "tcp",
"security": "reality",
"realitySettings": {
"serverName": "~server_name~",
"fingerprint": "chrome",
"show": false,
"publicKey": "~public_key~",
"shortId": "~short_id~",
"spiderX": ""
}
},
"mux": {
"enabled": false,
"concurrency": -1
}
},
{
"tag": "block",
"protocol": "blackhole",
"settings": {
"response": {
"type": "http"
}
}
}
],
"routing": { "routing": {
"domainStrategy": "AsIs", "domainStrategy": "AsIs",
"rules": [{ "rules": [
"type": "field", {
"outboundTag": "~outbound~", "type": "field",
"domain": "~pac~" "outboundTag": "block",
}, { "domain": "~block~"
"type": "field", },
"port": "0-65535", {
"outboundTag": "direct" "type": "field",
}] "outboundTag": "~outbound~",
"domain": "~pac~"
},
{
"type": "field",
"outboundTag": "~outbound~",
"ip": "~subnet~"
},
{
"type": "field",
"outboundTag": "~outbound~",
"domain": "~warp~"
}
]
} }
} }
+39 -1
View File
@@ -22,6 +22,15 @@
} }
}, },
"tag": "vless_tls" "tag": "vless_tls"
},
{
"listen": "127.0.0.1",
"port": 8080,
"protocol": "dokodemo-door",
"settings": {
"address": "127.0.0.1"
},
"tag": "api"
} }
], ],
"log": { "log": {
@@ -40,6 +49,35 @@
], ],
"routing": { "routing": {
"domainStrategy": "AsIs", "domainStrategy": "AsIs",
"rules": [] "rules": [
{
"inboundTag": [
"api"
],
"outboundTag": "api",
"type": "field"
}
]
},
"stats": {},
"api": {
"services": [
"StatsService"
],
"tag": "api"
},
"policy": {
"levels": {
"0": {
"statsUserUplink": true,
"statsUserDownlink": true
}
},
"system": {
"statsInboundUplink": true,
"statsInboundDownlink": true,
"statsOutboundUplink": true,
"statsOutboundDownlink": true
}
} }
} }
+63
View File
@@ -44,6 +44,8 @@ services:
condition: service_healthy condition: service_healthy
ad: ad:
condition: service_started condition: service_started
ss:
condition: service_started
env_file: env_file:
- path: ./.env - path: ./.env
required: true # default required: true # default
@@ -162,6 +164,7 @@ services:
- ./update:/update - ./update:/update
- ./.git:/.git - ./.git:/.git
- ./scripts/start_service.sh:/start_service.sh - ./scripts/start_service.sh:/start_service.sh
- ./docker-compose.override.yml:/docker/compose
- /var/run/docker.sock:/var/run/docker.sock:ro - /var/run/docker.sock:/var/run/docker.sock:ro
environment: environment:
IP: ${IP} IP: ${IP}
@@ -192,6 +195,8 @@ services:
- xr - xr
- oc - oc
- np - np
- proxy
- ss
wg: wg:
image: mercurykd/vpnbot-wg:1.1 image: mercurykd/vpnbot-wg:1.1
build: build:
@@ -460,3 +465,61 @@ services:
default: default:
ipv4_address: 10.10.0.13 ipv4_address: 10.10.0.13
logging: *default-logging logging: *default-logging
proxy:
image: mercurykd/vpnbot-ss:1.2
build:
dockerfile: dockerfile/shadowsocks.dockerfile
args:
image: ${IMAGE}
volumes:
- ./config/.profile:/root/.ashrc:ro
- ./config/sslocal.json:/config.json
- ./ssh:/ssh
- ./config/sshd_config:/etc/ssh/sshd_config
- ./scripts/start_proxy.sh:/start_proxy.sh
hostname: proxy
container_name: proxy-${VER}
depends_on:
php:
condition: service_healthy
networks:
default:
ipv4_address: 10.10.0.3
environment:
TZ: ${TZ}
env_file:
- path: ./.env
required: true # default
- path: ./override.env
required: false
stop_grace_period: 1s
command: ["/bin/sh", "/start_proxy.sh"]
logging: *default-logging
ss:
image: mercurykd/vpnbot-ss:1.2
build:
dockerfile: dockerfile/shadowsocks.dockerfile
args:
image: ${IMAGE}
volumes:
- ./config/.profile:/root/.ashrc:ro
- ./config/ssserver.json:/config.json
- ./ssh:/ssh
- ./config/sshd_config:/etc/ssh/sshd_config
- ./scripts/start_ss.sh:/start_ss.sh
hostname: shadowsocks
container_name: shadowsocks-${VER}
depends_on:
php:
condition: service_healthy
env_file:
- path: ./.env
required: true # default
- path: ./override.env
required: false
stop_grace_period: 1s
command: ["/bin/sh", "/start_ss.sh"]
networks:
default:
ipv4_address: 10.10.0.6
logging: *default-logging
+18 -89
View File
@@ -1,100 +1,29 @@
telegram bot to manage servers (inside the bot) telegram bot to manage servers (inside the bot)
<img src="https://github.com/user-attachments/assets/ec5faa51-987c-461a-a973-d94c7edf7115" width="300"> - VLESS (Reality OR Websocket)
- NaiveProxy
### VLESS (Reality OR Websocket) - OpenConnect
- change secret - Wireguard
- qr/config - Amnezia
- change fake domain - AdguardHome
- multiple users - MTProto
- subscriptions with routing (xray, sing-box, mihomo) - PAC
- routing templates per user - automatic ssl
- routing via rulesets (sing-box, mihomo)
- steal from yourself
- add domains to warp
### Main menu VLESS:
<img src="https://github.com/user-attachments/assets/80d2f671-fade-4819-a96a-efa253741ffd" width="300">
### User menu VLESS:
<img src="https://github.com/user-attachments/assets/5c3c5b5e-1931-4e98-a472-d303bac61a4e" width="300">
### NaiveProxy
- change login
- change password
<img src="https://github.com/mercurykd/vpnbot/assets/30900414/2127a4af-0436-452c-bfe2-c750dd5dbc06" width="300">
### OpenConnect
- change secret
- change password
- change dns
- add user
- add ip subnet
- expose-iroutes (lan between users)
<img src="https://github.com/user-attachments/assets/c3a8a78e-fe99-423c-a626-610b333a2a56" width="300">
### Wireguard / Amnezia
- create
- delete
- rename
- timer
- torrent blocking
- qr/config
- AmneziaVPN vpn:// link
- statistics
<img src="https://github.com/mercurykd/vpnbot/assets/30900414/51a79c93-8083-40ba-a14b-a6ef19f00531" width="300">
<img src="https://github.com/mercurykd/vpnbot/assets/30900414/fd6ffd9f-bd75-479c-8dca-ea6c0b938b6c" width="300">
### Shadowsocks + v2ray
- change password
- on/off v2ray
- qr
- short link
<img src="https://github.com/mercurykd/vpnbot/assets/30900414/fbe39617-63ae-4536-8ab0-e4269ed8784a" width="300">
### AdguardHome
- change password
- change upstream dns
- check dns
- check safesearch
- add custom clientID for DNSoverTLS (DOT)
- fill allowed clients (WG/AWG + OpenConnect + VLESS)
- custom ID for each user VLESS
<img src="https://github.com/user-attachments/assets/1dcdd9f9-f781-4ec2-8e32-01ce6095e0a3" width="300">
### PAC
- the ability to create your own PAC available by url with the ability to substitute the final ip and port
- Shadowsocks Android PAC
- add [antifilter-community](https://community.antifilter.download/) or [ru-bundle](https://github.com/legiz-ru/sb-rule-sets/blob/main/ru-bundle.lst) domain lists
<img src="https://github.com/user-attachments/assets/8d039dbb-6478-43a8-811a-4279e766c884" width="300">
### MTProto
- change secret
- qr/config
<img src="https://github.com/user-attachments/assets/d37b2e1c-f991-4e1c-8060-1b547eea8fe2" width="300">
### Settings
- add/change admin
- change language (en/ru)
- import/export all settings
- domain binding
- obtain ssl for domain
- fake html for domain
- ports block
<img src="https://github.com/user-attachments/assets/82b78014-eaa2-4b4c-bc90-77f58d03d57c" width="300">
--- ---
environment: ubuntu 22.04/24.04, debian 11/12 environment: ubuntu 22.04/24.04, debian 11/12
### Install: ## Install:
```shell ```shell
wget -O- https://raw.githubusercontent.com/mercurykd/vpnbot/master/scripts/init.sh | sh -s YOUR_TELEGRAM_BOT_KEY wget -O- https://raw.githubusercontent.com/mercurykd/vpnbot/master/scripts/init.sh | sh -s YOUR_TELEGRAM_BOT_KEY master
``` ```
#### Restart:
### Install as service (autoload on start):
```shell ```shell
cd /root/vpnbot make r
bash scripts/install_as_service.sh
``` ```
#### autoload:
```shell
crontab -e
```
add `@reboot cd /root/vpnbot && make r` and save
+2
View File
@@ -1,3 +1,4 @@
TAG="${2:-master}"
apt update apt update
apt install -y \ apt install -y \
ca-certificates \ ca-certificates \
@@ -13,6 +14,7 @@ apt install -y \
curl -fsSL https://get.docker.com -o get-docker.sh && sh get-docker.sh curl -fsSL https://get.docker.com -o get-docker.sh && sh get-docker.sh
git clone https://github.com/mercurykd/vpnbot.git git clone https://github.com/mercurykd/vpnbot.git
cd ./vpnbot cd ./vpnbot
git checkout $TAG
echo "<?php echo "<?php
\$c = ['key' => '$1'];" > ./app/config.php \$c = ['key' => '$1'];" > ./app/config.php
Binary file not shown.
+11 -2
View File
@@ -1,5 +1,14 @@
#!/bin/bash #!/bin/bash
pwd=`pwd` pwd=`pwd`
process_name="$pwd/update/update.sh"
current_pid=$$
pids=$(pgrep -f $process_name)
for pid in $pids; do
if [ $pid -ne $current_pid ]; then
kill -9 $pid
fi
done
> $pwd/update/pipe > $pwd/update/pipe
echo "$$" > $pwd/update/update_pid echo "$$" > $pwd/update/update_pid
@@ -27,10 +36,10 @@ do
git pull > ./update/message git pull > ./update/message
fi fi
curl -H "Content-Type: application/json" -X POST https://api.telegram.org/bot$key/editMessageText -d "$(cat $pwd/update/curl | sed 's/"text":"~t~"/"text": "launching the bot"/')" curl -H "Content-Type: application/json" -X POST https://api.telegram.org/bot$key/editMessageText -d "$(cat $pwd/update/curl | sed 's/"text":"~t~"/"text": "launching the bot"/')"
IP=$(curl ipinfo.io/ip) VER=$(git describe --tags) docker compose --env-file ./.env --env-file ./override.env up -d --force-recreate
bash $pwd/update/update.sh &
> $pwd/update/key > $pwd/update/key
> $pwd/update/curl > $pwd/update/curl
IP=$(curl -s -t 1 2ip.io || curl -s -t 1 ipinfo.io/ip || curl -s -t 1 ifconfig.me) VER=$(git describe --tags) docker compose --env-file ./.env --env-file ./override.env up -d --force-recreate
bash $pwd/update/update.sh &
exit 0 exit 0
fi fi
sleep 1 sleep 1
+20
View File
@@ -1,3 +1,23 @@
29.01.2025 v2.7
- vless: сброс статистики юзера
24.01.2025 v2.6
- правки меню
- vless:добавлена возможность маршрутизировать список ip-сетей
18.01.2025 v2.5
- фикс скачивания шаблона михомо
- обновлен singbox.exe
- вывод статистики vless пользователей
- смягчил паттерн поиска reality degenerate в логах
07.01.2025 v2.4
- вернул shadowsocks (спасибо за донат)
04.01.2025
- возможность установить нужную версию с нуля
- корректировка автосканера под новую версию
- улучшение основного меню
26.12.2024 v2.2
- возможность менять поддомен для naive/openconnect
26.12.2024 v2.1
- обновление версии singbox и конфига под него
22.12.2024 v2.0 22.12.2024 v2.0
!!! версия не совместима с предыдущими, возможно прийдется накатывать руками. старые конфиги (кроме вг) не будут работать! перед обновлением: !!! версия не совместима с предыдущими, возможно прийдется накатывать руками. старые конфиги (кроме вг) не будут работать! перед обновлением:
- включить все порты или удалить docker-compose.override.yml - включить все порты или удалить docker-compose.override.yml