Compare commits

...

31 Commits

Author SHA1 Message Date
mercury 321b853d42 amnezia reduce button 2026-03-27 01:49:10 +04:00
mercury 8effb72cdc update version 2026-03-10 10:05:12 +04:00
mercury bec8f5488e reset amnezia keys fix 2026-03-08 01:23:12 +04:00
mercury f97b0f9228 amneziawg2.0 2026-03-08 01:12:09 +04:00
mercury 8e8babe1a6 update version 2025-12-16 00:58:02 +04:00
mercury 238c380f23 fix clash template rules behavior 2025-12-16 00:55:44 +04:00
mercury abc2e7c587 setting up dnstt display in menu 2025-12-16 00:38:34 +04:00
mercury 3f99d9fbf0 hide dnstt 2025-12-15 17:06:19 +04:00
mercury 3f1e80c641 update version 2025-12-15 16:48:24 +04:00
mercury 5afe6a4777 lightweight warp image 2025-12-15 00:44:54 +04:00
mercury c2cf0bff98 delete bot command 2025-12-15 00:34:41 +04:00
mercury 60241aaffb new mtproto image 2025-12-15 00:18:08 +04:00
mercury 96ff868b10 improve dnstt menu 2025-12-14 22:49:28 +04:00
mercury f58c29a66b fix reality start 2025-12-14 22:48:58 +04:00
mercury ca922f4612 change address for wg on start 2025-12-14 22:04:22 +04:00
mercury 5a5b1b62b1 domain for shortlink amnezia 2025-12-14 21:55:30 +04:00
mercury 0ef34f818d changing dependencies when starting containers 2025-12-11 00:44:32 +04:00
mercury d1960d6acb change of strategy for server xray domain resolution 2025-12-10 01:34:44 +04:00
mercury 95cba4c8d1 improved issuance of routing rules vless: ip or domains 2025-12-10 01:33:21 +04:00
mercury 18e2dd53ff changing dependencies when starting containers 2025-12-10 00:40:45 +04:00
mercury 3e5b131c16 delete hysteria upstream 2025-12-10 00:40:15 +04:00
mercury e07d1505e4 attempt to save page when changing domain list 2025-12-10 00:01:02 +04:00
mercury c140f292e8 fix port for first amnezia container 2025-12-09 21:57:10 +04:00
mercury 7cc100ace5 dnstt menu improve 2025-12-09 21:31:12 +04:00
mercury 4938ada85d Merge branch 'xhttp' into dev 2025-12-04 02:24:43 +04:00
mercury c5b9886470 hysteria: logging, correct port 2025-12-04 02:23:00 +04:00
mercury 61d8b899e7 improved docker-compose.override.yml rewrite algorithm 2025-12-04 01:08:14 +04:00
mercury 7d81eeeddd improved process logging 2025-12-03 01:25:53 +04:00
mercury 3bdebd95ab backup dnstt keys 2025-12-03 00:16:19 +04:00
mercury eb4641a58d ability to disable naive and openconnect subdomains 2025-12-03 00:10:47 +04:00
mercury 61900daafd custom hysteria port 2025-12-03 00:08:49 +04:00
14 changed files with 559 additions and 321 deletions
+347 -152
View File
@@ -179,6 +179,9 @@ class Bot
case preg_match('~^/setHwidDevices(?: (\w+))?$~', $this->input['callback'], $m):
$this->setHwidDevices($m[1] ?? null);
break;
case preg_match('~^/changePort(?: (\w+))?$~', $this->input['callback'], $m):
$this->changePort($m[1] ?? null);
break;
case preg_match('~^/hwidUser (\d+)(?:_(\d+))?$~', $this->input['callback'], $m):
$this->hwidUser($m[1], $m[2] ?? 0);
break;
@@ -317,8 +320,11 @@ class Bot
case preg_match('~^/logs$~', $this->input['callback'], $m):
$this->logs();
break;
case preg_match('~^/dnstt$~', $this->input['callback'], $m):
$this->dnstt();
case preg_match('~^/dnstt$~', $this->input['callback'] ?: $this->input['message'], $m):
$this->dnstt(!empty($this->input['callback']));
break;
case preg_match('~^/showdnstt$~', $this->input['callback'], $m):
$this->showdnstt();
break;
case preg_match('~^/dnsttDownload$~', $this->input['callback'], $m):
$this->dnsttDownload();
@@ -455,9 +461,6 @@ class Bot
case preg_match('~^/enterPage$~', $this->input['callback'], $m):
$this->enterPage();
break;
case preg_match('~^/geodb$~', $this->input['callback'], $m):
$this->geodb();
break;
case preg_match('~^/adguardreset$~', $this->input['callback'], $m):
$this->adguardreset();
break;
@@ -515,6 +518,12 @@ class Bot
case preg_match('~^/switchAmnezia (-?\d+)$~', $this->input['callback'], $m):
$this->switchAmnezia($m[1]);
break;
case preg_match('~^/resetAmnezia (-?\d+)$~', $this->input['callback'], $m):
$this->resetAmnezia($m[1]);
break;
case preg_match('~^/reduceAmnezia (-?\d+)$~', $this->input['callback'], $m):
$this->reduceAmnezia($m[1]);
break;
case preg_match('~^/switchExchange (\d+)$~', $this->input['callback'], $m):
$this->switchExchange($m[1]);
break;
@@ -558,8 +567,8 @@ class Bot
case preg_match('~^/addNipdomain$~', $this->input['callback'], $m):
$this->addNipdomain();
break;
case preg_match('~^/(?P<action>change|delete)(?P<typelist>\w+) (?P<arg>\d+)$~', $this->input['callback'], $m):
$this->listPacChange($m['typelist'], $m['action'], $m['arg']);
case preg_match('~^/(?P<action>change|delete)(?P<typelist>\w+) (?P<arg>\d+)(?: (?P<page>\d+))?$~', $this->input['callback'], $m):
$this->listPacChange($m['typelist'], $m['action'], $m['arg'], $m['page'] ?: 0);
break;
case preg_match('~^/paczapret$~', $this->input['callback'], $m):
$this->pacZapret();
@@ -725,11 +734,11 @@ class Bot
public function restartTG()
{
$secret = file_get_contents('/config/mtprotosecret');
$fakedomain = file_get_contents('/config/mtprotodomain') ?: 'vk.com';
$fakedomain = file_get_contents('/config/mtprotodomain') ?: 'yandex.ru';
$this->ssh('pkill mtproto-proxy', 'tg');
if (preg_match('~^\w{32}$~', $secret)) {
$p = getenv('TGPORT');
$this->ssh("mtproto-proxy --domain $fakedomain -u nobody -H $p --nat-info 10.10.0.8:{$this->ip} -S $secret --aes-pwd /proxy-secret /proxy-multi.conf -M 1 >/dev/null 2>&1 &", 'tg');
$this->ssh("mtproto-proxy --domain $fakedomain -u nobody -H $p --nat-info 10.10.0.8:{$this->ip} -S $secret --aes-pwd /proxy-secret /proxy-multi.conf -M 1", 'tg', false, '/logs/mtproto');
}
}
@@ -817,15 +826,15 @@ class Bot
{
$s = file_get_contents('/config/mtprotosecret');
$p = getenv('TGPORT');
$d = trim(file_get_contents('/config/mtprotodomain') ?: 'vk.com');
$d = trim(file_get_contents('/config/mtprotodomain') ?: 'yandex.ru');
$d = exec("echo $d | tr -d '\\n' | xxd -ps -c 200");
$ip = $this->getPacConf()['domain'] ?: $this->ip;
$ip = $this->getDomain();
return "https://t.me/proxy?server=$ip&port=$p&secret=ee$s$d";
}
public function mtproto()
{
$d = file_get_contents('/config/mtprotodomain') ?: 'vk.com';
$d = file_get_contents('/config/mtprotodomain') ?: 'yandex.ru';
$st = $this->ssh('pgrep mtproto-proxy', 'tg') ? 'on' : 'off';
$text[] = "Menu -> MTProto\n";
$text[] = "status: $st\n";
@@ -1147,7 +1156,7 @@ class Bot
file_put_contents('/config/ocserv.conf', $conf);
$this->ssh('pkill ocserv', 'oc');
$pac = $this->getPacConf();
if (!empty($pac['ocserv'])) {
if (!empty($pac['ocserv']) && !empty($this->getHashSubdomain('oc'))) {
$this->ssh('ocserv -c /etc/ocserv/ocserv.conf', 'oc');
}
}
@@ -1159,7 +1168,7 @@ class Bot
$c = file_get_contents('/config/Caddyfile');
$t = preg_replace('~^(\t+)?basic_auth[^\n]+~sm', '$1basic_auth ' . ($pac['naive']['user'] ?? '_') . ' ' . ($pac['naive']['pass'] ?? '__'), $c);
file_put_contents('/config/Caddyfile', $t);
if (!empty($pac['naive']['pass'])) {
if (!empty($pac['naive']['pass']) && !empty($this->getHashSubdomain('np'))) {
$this->ssh('caddy run -c /config/Caddyfile', 'np', false);
}
}
@@ -1172,7 +1181,7 @@ class Bot
$c['auth']['password'] = $pac['hysteria_pass'];
yaml_emit_file('/config/hysteria.yaml', $c);
if (!empty($pac['hysteria_pass'])) {
$this->ssh('hysteria server -c /config/hysteria.yaml', 'hy', false);
$this->ssh('hysteria server -c /config/hysteria.yaml', 'hy', false, '/logs/hysteria');
}
}
@@ -1187,7 +1196,7 @@ class Bot
public function chOcSubdomain($domain)
{
$pac = $this->getPacConf();
if (empty($domain)) {
if ($domain == -1) {
unset($pac["oc_domain"]);
} else {
$pac["oc_domain"] = $domain;
@@ -1201,7 +1210,7 @@ class Bot
public function chNpSubdomain($domain)
{
$pac = $this->getPacConf();
if (!empty($data)) {
if ($domain == -1) {
unset($pac['np_domain']);
} else {
$pac['np_domain'] = $domain;
@@ -1233,7 +1242,11 @@ class Bot
public function chhypass($pass)
{
$pac = $this->getPacConf();
if (!empty($pass)) {
$pac['hysteria_pass'] = $pass;
} else {
unset($pac['hysteria_pass']);
}
$this->setPacConf($pac);
$this->restartHysteria();
$this->menu('hy');
@@ -1831,6 +1844,10 @@ class Bot
'private' => file_get_contents('/certs/cert_private'),
'public' => file_get_contents('/certs/cert_public'),
] : false,
'dnstt' => file_exists('/config/dnstt/server.key') ? [
'private' => file_get_contents('/config/dnstt/server.key'),
'public' => file_get_contents('/config/dnstt/server.pub'),
] : false,
'mtproto' => file_get_contents('/config/mtprotosecret'),
'mtprotodomain' => file_get_contents('/config/mtprotodomain'),
'xray' => $this->getXray(),
@@ -1982,7 +1999,13 @@ class Bot
if (!empty($json['pac']['domain'])) {
$this->setUpstreamDomainOcserv($json['pac']['domain']);
$this->setUpstreamDomainNaive($json['pac']['domain']);
$this->setUpstreamDomainHysteria($json['pac']['domain']);
}
// dnstt
if (!empty($json['dnstt'])) {
$out[] = 'update dnstt certificates';
$this->update($this->input['chat'], $this->input['message_id'], implode("\n", $out));
file_put_contents('/config/dnstt/server.key', $json['dnstt']['private']);
file_put_contents('/config/dnstt/server.pub', $json['dnstt']['public']);
}
// nginx
$out[] = 'reset nginx';
@@ -2053,63 +2076,79 @@ class Bot
$this->restartWG($this->createConfig($server));
}
public function switchAmnezia($page = 0)
public function resetAmnezia($page = 0) {
$this->switchAmnezia($page, 1);
}
public function reduceAmnezia($page = 0) {
$this->switchAmnezia($page, false, 1);
}
public function switchAmnezia($page = 0, $reset = false, $reduce = false)
{
$c = $this->getPacConf();
switch (true) {
case !empty($reset):
$amnezia = 1;
unset($c[$this->getInstanceWG(1) . 'amnezia_keys']);
unset($c[$this->getInstanceWG(1) . 'presharedkey']);
break;
case !empty($reduce):
$amnezia = 1;
unset($c[$this->getInstanceWG(1) . 'amnezia_keys']['S3']);
unset($c[$this->getInstanceWG(1) . 'amnezia_keys']['S4']);
unset($c[$this->getInstanceWG(1) . 'amnezia_keys']['I1']);
break;
default:
$amnezia = $c[$this->getInstanceWG(1) . 'amnezia'] = $c[$this->getInstanceWG(1) . 'amnezia'] ? 0 : 1;
break;
}
$this->setPacConf($c);
$pk = $this->presharedKey();
$ak = $this->amneziaKeys();
$clients = $this->readClients();
foreach ($clients as $k => $v) {
if (!empty($amnezia)) {
$clients[$k]['peers'][0]['PresharedKey'] = $pk;
$clients[$k]['interface']['Jc'] = $ak['Jc'];
$clients[$k]['interface']['Jmin'] = $ak['Jmin'];
$clients[$k]['interface']['Jmax'] = $ak['Jmax'];
$clients[$k]['interface']['S1'] = $ak['S1'];
$clients[$k]['interface']['S2'] = $ak['S2'];
$clients[$k]['interface']['H1'] = $ak['H1'];
$clients[$k]['interface']['H2'] = $ak['H2'];
$clients[$k]['interface']['H3'] = $ak['H3'];
$clients[$k]['interface']['H4'] = $ak['H4'];
} else {
unset($clients[$k]['peers'][0]['PresharedKey']);
unset($clients[$k]['interface']['Jc']);
unset($clients[$k]['interface']['Jmin']);
unset($clients[$k]['interface']['Jmax']);
unset($clients[$k]['interface']['S1']);
unset($clients[$k]['interface']['S2']);
unset($clients[$k]['interface']['S3']);
unset($clients[$k]['interface']['S4']);
unset($clients[$k]['interface']['H1']);
unset($clients[$k]['interface']['H2']);
unset($clients[$k]['interface']['H3']);
unset($clients[$k]['interface']['H4']);
unset($clients[$k]['interface']['I1']);
if (!empty($amnezia)) {
$clients[$k]['peers'][0]['PresharedKey'] = $pk;
foreach ($ak as $j => $i) {
$clients[$k]['interface'][$j] = $i;
}
}
}
$this->saveClients($clients);
$wg = $this->readConfig();
if (!empty($amnezia)) {
$wg['interface']['Jc'] = $ak['Jc'];
$wg['interface']['Jmin'] = $ak['Jmin'];
$wg['interface']['Jmax'] = $ak['Jmax'];
$wg['interface']['S1'] = $ak['S1'];
$wg['interface']['S2'] = $ak['S2'];
$wg['interface']['H1'] = $ak['H1'];
$wg['interface']['H2'] = $ak['H2'];
$wg['interface']['H3'] = $ak['H3'];
$wg['interface']['H4'] = $ak['H4'];
} else {
unset($wg['interface']['Jc']);
unset($wg['interface']['Jmin']);
unset($wg['interface']['Jmax']);
unset($wg['interface']['S1']);
unset($wg['interface']['S2']);
unset($wg['interface']['S3']);
unset($wg['interface']['S4']);
unset($wg['interface']['H1']);
unset($wg['interface']['H2']);
unset($wg['interface']['H3']);
unset($wg['interface']['H4']);
unset($wg['interface']['I1']);
if (!empty($amnezia)) {
foreach ($ak as $j => $i) {
$wg['interface'][$j] = $i;
}
}
foreach ($wg['peers'] as $k => $v) {
@@ -2119,7 +2158,7 @@ class Bot
unset($wg['peers'][$k]['PresharedKey']);
}
}
$this->restartWG($this->createConfig($wg), 1);
$this->restartWG($this->createConfig($wg), !$reset && !$reduce);
$this->menu('wg', $page);
}
@@ -2400,8 +2439,7 @@ class Bot
$adguardClient = $conf['adguardkey'] ? "-d {$conf['adguardkey']}.{$conf['domain']}" : '';
$oc = $this->getHashSubdomain('oc');
$np = $this->getHashSubdomain('np');
$hy = $this->getHashSubdomain('hy');
exec("certbot certonly --force-renew --preferred-chain 'ISRG Root X1' -n --agree-tos --email mail@{$conf['domain']} -d {$conf['domain']} -d $oc.{$conf['domain']} -d $np.{$conf['domain']} -d $hy.{$conf['domain']} $adguardClient --webroot -w /certs/ --logs-dir /logs --max-log-backups 0 2>&1", $out, $code);
exec("certbot certonly --force-renew --preferred-chain 'ISRG Root X1' -n --agree-tos --email mail@{$conf['domain']} -d {$conf['domain']}" . ($oc ? " -d $oc.{$conf['domain']}" : '') . ($np ? " -d $np.{$conf['domain']}" : '') . " $adguardClient --webroot -w /certs/ --logs-dir /logs --max-log-backups 0 2>&1", $out, $code);
if ($code > 0) {
$this->send($this->input['chat'], "ERROR\n" . implode("\n", $out));
break;
@@ -2635,6 +2673,21 @@ class Bot
];
}
public function changePort($container)
{
$r = $this->send(
$this->input['chat'],
"@{$this->input['username']} number port",
$this->input['message_id'],
reply: 'number port',
);
$_SESSION['reply'][$r['result']['message_id']] = [
'start_message' => $this->input['message_id'],
'callback' => 'setPort',
'args' => [$container],
];
}
public function addLinkDomain()
{
$r = $this->send(
@@ -2945,42 +2998,42 @@ DNS-over-HTTPS with IP:
$page = (int) floor(array_search($v, array_keys($conf[$type])) / $this->limit);
}
$page = $page ?: -2;
$this->backXtlsList($type);
$this->backXtlsList($type, $page);
}
public function backXtlsList($type)
public function backXtlsList($type, $page = 0)
{
switch ($type) {
case 'includelist':
$this->pacUpdate($_SESSION['proxylistentry']);
if (!empty($_SESSION['proxylistentry'])) {
$this->xtlsproxy();
$this->xtlsproxy($page);
}
break;
case 'blocklist':
$this->xrayUpdateRules();
$this->xtlsblock();
$this->xtlsblock($page);
break;
case 'warplist':
$this->xrayUpdateRules();
$this->xtlswarp();
$this->xtlswarp($page);
break;
case 'processlist':
$this->xtlsprocess();
$this->xtlsprocess($page);
break;
case 'packagelist':
$this->xtlsapp();
$this->xtlsapp($page);
break;
case 'subnetlist':
$this->xtlssubnet();
$this->xtlssubnet($page);
break;
case 'rulessetlist':
$this->xtlsrulesset();
$this->xtlsrulesset($page);
break;
case 'white':
case 'deny':
$this->syncDeny();
$this->denyList(0, $type == 'white' ? 1 : 0);
$this->denyList($page, $type == 'white' ? 1 : 0);
break;
}
}
@@ -3325,12 +3378,6 @@ DNS-over-HTTPS with IP:
$am = $c[$this->getInstanceWG(1) . 'amnezia'];
$end = $c[$this->getInstanceWG(1) . 'endpoint'];
$data = [
[
[
'text' => $this->i18n($am ? 'on' : 'off') . " amnezia",
'callback_data' => "/switchAmnezia $page",
],
],
[
[
'text' => $this->i18n(!$bt ? 'on' : 'off') . " {$this->i18n('torrent')} ",
@@ -3368,6 +3415,24 @@ DNS-over-HTTPS with IP:
],
],
];
if (!empty($am)) {
array_unshift($data, [
[
'text' => "reset obf-keys",
'callback_data' => "/resetAmnezia $page",
],
[
'text' => "reduce to 1",
'callback_data' => "/reduceAmnezia $page",
],
]);
}
array_unshift($data, [
[
'text' => $this->i18n($am ? 'on' : 'off') . " amnezia",
'callback_data' => "/switchAmnezia $page",
],
]);
if ($clients) {
$data = array_merge($data, $clients);
}
@@ -3775,45 +3840,54 @@ DNS-over-HTTPS with IP:
public function getAmneziaShortLink($client)
{
$dns = explode(',', $client['interface']['DNS']);
$c = json_encode([
$domain = $this->getDomain();
$pac = $this->getPacConf();
$dnsRaw = $client['interface']['DNS'] ?: $pac[$this->getInstanceWG(1) . 'dns'] ?: $this->dns;
$dns = array_map('trim', explode(',', $dnsRaw));
$wgPort = (int) getenv($this->getInstanceWG() == 'wg1' ? 'WG1PORT' : 'WGPORT');
$amneziaKeys = $this->amneziaKeys();
$protoVer = array_key_exists('I1', $amneziaKeys) ? "2" : "1";
$containerName = $protoVer === "2" ? "amnezia-awg2" : "amnezia-awg";
$c = [
"containers" => [
[
"awg" => [
"isThirdPartyConfig" => True,
"last_config" => json_encode([
"H1" => "{$client['interface']['H1']}",
"H2" => "{$client['interface']['H2']}",
"H3" => "{$client['interface']['H3']}",
"H4" => "{$client['interface']['H4']}",
"Jc" => "{$client['interface']['Jc']}",
"Jmax" => "{$client['interface']['Jmax']}",
"Jmin" => "{$client['interface']['Jmin']}",
"S1" => "{$client['interface']['S1']}",
"S2" => "{$client['interface']['S2']}",
"client_ip" => explode('/', $client['interface']['Address'])[0],
"isThirdPartyConfig" => true,
"last_config" => json_encode(array_merge(array_map('strval', $amneziaKeys), [
"protocol_version" => $protoVer,
"client_ip" => $client['interface']['Address'],
"client_priv_key" => $client['interface']['PrivateKey'],
"client_pub_key" => "0",
"config" => $this->createConfig($client),
"hostName" => $this->ip,
"port" => (int) getenv('WG1PORT'),
"hostName" => $domain,
"port" => $wgPort,
"psk_key" => $client['peers'][0]['PresharedKey'],
"server_pub_key" => $client['peers'][0]['PublicKey']
]),
"port" => (int) getenv('WG1PORT'),
"transport_proto" => "udp"
"server_pub_key" => $client['peers'][0]['PublicKey'],
"allowed_ips" => array_map('trim', explode(',', $client['peers'][0]['AllowedIPs'])),
"persistent_keep_alive" => "25"
])),
"port" => $wgPort,
"transport_proto" => "udp",
"protocol_version" => $protoVer
],
"container" => "amnezia-awg"
"container" => $containerName
]
],
"defaultContainer" => "amnezia-awg",
"defaultContainer" => $containerName,
"description" => $client['interface']['## name'],
"dns1" => $dns[0],
"dns2" => $dns[1] ?: '',
"hostName" => $this->ip
]);
exec("echo '$c' | python amnezia.py", $o);
return $o[0];
"dns1" => $dns[0] ?? '',
"dns2" => $dns[1] ?? '',
"hostName" => $domain,
"isThirdPartyConfig" => true
];
$json = json_encode($c);
$proc = proc_open('python amnezia.py', [0 => ['pipe', 'r'], 1 => ['pipe', 'w']], $pipes);
fwrite($pipes[0], $json);
fclose($pipes[0]);
$result = trim(stream_get_contents($pipes[1]));
fclose($pipes[1]);
proc_close($proc);
return $result;
}
public function getClient($client, $page)
@@ -3821,7 +3895,7 @@ DNS-over-HTTPS with IP:
$clients = $this->readClients();
if ($clients) {
$name = $this->getName($clients[$client]['interface']);
$conf = $this->createConfig($clients[$client]);
$conf = htmlspecialchars($this->createConfig($clients[$client]));
if ($this->getWGType() == 'awg') {
$sl = $this->getAmneziaShortLink($clients[$client]);
}
@@ -4398,11 +4472,11 @@ DNS-over-HTTPS with IP:
$data[] = [
[
'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) . " $page",
],
[
'text' => 'delete',
'callback_data' => "/delete$type " . ($i + $page * $this->limit),
'callback_data' => "/delete$type " . ($i + $page * $this->limit) . " $page",
],
];
$i++;
@@ -4448,7 +4522,7 @@ DNS-over-HTTPS with IP:
return [$data, $text];
}
public function listPacChange($type, $action, $key)
public function listPacChange($type, $action, $key, $page = 0)
{
$conf = $this->getPacConf();
$i = 0;
@@ -4467,7 +4541,7 @@ DNS-over-HTTPS with IP:
$i++;
}
$this->setPacConf($conf);
$this->backXtlsList($type);
$this->backXtlsList($type, $page);
}
public function pacZapret()
@@ -4659,7 +4733,7 @@ DNS-over-HTTPS with IP:
if (!file_exists('/config/dnstt/server.key')) {
$this->ssh("dnstt-server -gen-key -privkey-file /dnstt/server.key -pubkey-file /dnstt/server.pub", 'dnstt');
}
$this->ssh("dnstt-server -udp :53 -privkey-file /dnstt/server.key {$c['dnsttDomain']} 127.0.0.1:22", 'dnstt' , false);
$this->ssh("dnstt-server -udp :53 -privkey-file /dnstt/server.key {$c['dnsttDomain']} 127.0.0.1:22", 'dnstt' , false, '/logs/dnstt');
}
}
@@ -4668,25 +4742,43 @@ DNS-over-HTTPS with IP:
$this->sendFile($this->input['from'], curl_file_create('/config/dnstt/server.pub'));
}
public function dnstt()
public function showdnstt()
{
$c = $this->getPacConf();
$c['showdnstt'] = empty($c['showdnstt']);
$this->setPacConf($c);
$this->dnstt(1);
}
public function dnstt($update = false)
{
$c = $this->getPacConf();
$pubkey = file_get_contents('/config/dnstt/server.pub');
$text[] = "dnstt";
$data[] = [
[
'text' => $this->i18n('show in menu ') . $this->i18n($c['showdnstt'] ? 'on' : 'off'),
'callback_data' => "/showdnstt",
],
];
if (!empty($c['dnsttDomain']) && !empty($c['dnsttPassword'])) {
$text[] = "<pre>set the NS record for {$c['dnsttDomain']}: tns.{$c['domain']}\nset A record for tns.{$c['domain']}: {$this->ip}</pre>";
$text[] = "domain: <code>{$c['dnsttDomain']}</code>";
$text[] = "ssh: <code>vpnbot:{$c['dnsttPassword']}</code>";
$text[] = "pubkey: <code>$pubkey</code>";
$text[] = "account: <code>vpnbot:{$c['dnsttPassword']}</code>";
$text[] = "server name: <code>{$c['dnsttDomain']}</code>";
$text[] = "public key: <code>$pubkey</code>";
$data[] = [
[
'text' => $this->i18n('download pubkey'),
'callback_data' => "/dnsttDownload",
],
];
} else {
$text[] = "set subdomain and password";
}
$data[] = [
[
'text' => $this->i18n('set domain'),
'text' => $this->i18n('set subdomain'),
'callback_data' => "/dnsttDomain",
],
];
@@ -4702,12 +4794,21 @@ DNS-over-HTTPS with IP:
'callback_data' => "/menu",
],
];
if ($update) {
$this->update(
$this->input['chat'],
$this->input['message_id'],
implode("\n", $text),
$data ?: false,
);
} else {
$this->send(
$this->input['chat'],
implode("\n", $text),
$this->input['message_id'],
$data ?: false,
);
}
}
public function menu($type = false, $arg = false, $return = false)
@@ -4735,7 +4836,6 @@ DNS-over-HTTPS with IP:
$main[] = '';
$oc = $this->getHashSubdomain('oc');
$np = $this->getHashSubdomain('np');
$hy = $this->getHashSubdomain('hy');
if (!empty($conf['domain'])) {
$ssl_expiry = $this->expireCert();
$certs = $this->domainsCert() ?: [];
@@ -4743,9 +4843,12 @@ DNS-over-HTTPS with IP:
$main[] = "<blockquote>";
$main[] = "Domains:";
$main[] = $conf['domain'] . (in_array($conf['domain'], $certs) ? ' (ssl: ' . date('Y-m-d H:i:s', $ssl_expiry) . ')' : '');
if (!empty($np)) {
$main[] = 'naive ' . "$np.{$conf['domain']}" . (in_array("$np.{$conf['domain']}", $certs) ? ' (ssl: ' . date('Y-m-d H:i:s', $ssl_expiry) . ')' : '');
}
if (!empty($oc)) {
$main[] = 'openconnect ' . "$oc.{$conf['domain']}" . (in_array("$oc.{$conf['domain']}", $certs) ? ' (ssl: ' . date('Y-m-d H:i:s', $ssl_expiry) . ')' : '');
$main[] = 'hysteria ' . "$hy.{$conf['domain']}" . (in_array("$hy.{$conf['domain']}", $certs) ? ' (ssl: ' . date('Y-m-d H:i:s', $ssl_expiry) . ')' : '');
}
if (!empty($conf['adguardkey'])) {
$main[] = "{$conf['adguardkey']}.{$conf['domain']}" . (in_array("{$conf['adguardkey']}.{$conf['domain']}", $certs) ? ' (ssl: ' . date('Y-m-d H:i:s', $ssl_expiry) . ')' : '') . ' adguard DOT';;
}
@@ -4754,6 +4857,10 @@ DNS-over-HTTPS with IP:
$main[] = $this->i18n('domain explain');
}
}
$ports = yaml_parse_file('/docker/compose')['services'];
$hy_port = explode(':', $c['hy']['ports'][0])[0];
$main[] = '';
$main[] = '<code>';
@@ -4777,7 +4884,7 @@ DNS-over-HTTPS with IP:
$this->i18n('on') . ' 443',
$this->i18n('on') . ' 443',
$this->i18n('on') . ' 443',
$this->i18n('on') . ' 443',
$this->i18n($hy_port ? 'on' : 'off') . ($hy_port ? " $hy_port" : 'port unavailable'),
$this->i18n($c['tg'] ? 'on' : 'off') . ' ' . getenv('TGPORT'),
$this->i18n($c['ad'] ? 'on' : 'off') . ' 853',
$this->i18n($c['ss'] ? 'on' : 'off') . ' ' . getenv('SSPORT'),
@@ -4804,7 +4911,8 @@ DNS-over-HTTPS with IP:
$menu = [
'main' => [
'text' => implode("\n", $main ?: []),
'data' => [
'data' => array_merge(
[
[
[
'text' => $this->i18n($this->getPacConf()['amnezia'] ? 'amnezia' : 'wg_title'),
@@ -4855,16 +4963,22 @@ DNS-over-HTTPS with IP:
'callback_data' => "/pacMenu 0",
],
],
],
[array_merge(
[
[
'text' => $this->i18n('Hysteria'),
'callback_data' => "/menu hy",
],
],
$conf['showdnstt'] ? [
[
'text' => $this->i18n('DNSTT'),
'callback_data' => "/dnstt",
],
],
] : [],
)],
[
[
[
'text' => $this->i18n('config'),
@@ -4884,11 +4998,12 @@ DNS-over-HTTPS with IP:
],
],
],
)
],
'wg' => $type == 'wg' ? $this->statusWg($arg) : false,
'client' => $type == 'client' ? $this->getClient(...explode('_', $arg)) : false,
'addpeer' => $type == 'addpeer' ? $this->addWg(...explode('_', $arg)) : false,
'pac' => $type == 'pac' ? $this->pacMenu($arg) : false,
'pac' => $type == 'pac' ? $this->pacMenu((int) $arg) : false,
'adguard' => $type == 'adguard' ? $this->adguardMenu() : false,
'config' => $type == 'config' ? $this->configMenu() : false,
'ss' => $type == 'ss' ? $this->menuSS() : false,
@@ -5953,10 +6068,12 @@ DNS-over-HTTPS with IP:
public function hysteriaMenu()
{
$pac = $this->getPacConf();
$f = '/docker/compose';
$c = yaml_parse_file($f)['services'];
$port = explode(':', $c['hy']['ports'][0])[0];
$domain = $this->getDomain();
$text[] = "Menu -> Hysteria";
$hy = $this->getHashSubdomain('hy');
$text[] = "server: <code>$hy.$domain</code>";
$text[] = "server: " . ($port? "<code>$domain:$port</code>" : 'port unavailable');
$text[] = "passwd: <code>{$pac['hysteria_pass']}</code>";
$data[] = [
[
@@ -7908,17 +8025,11 @@ DNS-over-HTTPS with IP:
case 'package':
echo yaml_emit(['payload' => array_map(fn($e) => "PROCESS-NAME,$e", $v['list'])]);
break;
case 'pac':
echo yaml_emit(['payload' => array_map(fn($e) => "+.$e", $v['list'])]);
break;
case 'subnet':
echo yaml_emit(['payload' => array_map(fn($e) => $e, $v['list'])]);
break;
default:
echo yaml_emit(['payload' => array_map(function($e) {
if (preg_match('~^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(/\d{1,2})?$~', $e)) {
return "IP-CIDR,$e";
if (preg_match('~^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(/\d{1,2})?$~', $e, $m)) {
return "IP-CIDR,$e" . (empty($m[1]) ? '/32' : '');
} else {
return "DOMAIN-SUFFIX,$e";
}
@@ -8019,10 +8130,10 @@ DNS-over-HTTPS with IP:
foreach ($rules as $k => $v) {
if (array_key_exists('domain_suffix', $v)) {
foreach ($v['domain_suffix'] as $j) {
if (!preg_match('~^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(/\d{1,2})?$~', $j)) {
if (!preg_match('~^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(/\d{1,2})?$~', $j, $m)) {
$domains[] = $j;
} else {
$ips[] = $j;
$ips[] = $j . (empty($m[1]) ? '/32' : '');
}
}
unset($rules[$k]['domain_suffix']);
@@ -8104,7 +8215,7 @@ DNS-over-HTTPS with IP:
{
$sub = $this->getHashSubdomain('oc');
$nginx = file_get_contents('/config/upstream.conf');
$t = preg_replace('~#ocserv.+#ocserv~s', $domain ? "#ocserv\n$sub.$domain ocserv;\n#ocserv" : "#ocserv\n#$sub.\$domain ocserv;\n#ocserv", $nginx);
$t = preg_replace('~#ocserv.+#ocserv~s', $domain ? "#ocserv\n" . ($sub ? '' : '#' ) . "$sub.$domain ocserv;\n#ocserv" : "#ocserv\n#$sub.\$domain ocserv;\n#ocserv", $nginx);
file_put_contents('/config/upstream.conf', $t);
$this->ssh("nginx -s reload 2>&1", 'up');
}
@@ -8113,16 +8224,7 @@ DNS-over-HTTPS with IP:
{
$sub = $this->getHashSubdomain('np');
$nginx = file_get_contents('/config/upstream.conf');
$t = preg_replace('~#naive.+#naive~s', $domain ? "#naive\n$sub.$domain naive;\n#naive" : "#naive\n#$sub.\$domain naive;\n#naive", $nginx);
file_put_contents('/config/upstream.conf', $t);
$this->ssh("nginx -s reload 2>&1", 'up');
}
public function setUpstreamDomainHysteria($domain)
{
$sub = $this->getHashSubdomain('hy');
$nginx = file_get_contents('/config/upstream.conf');
$t = preg_replace('~#hysteria.+#hysteria~s', $domain ? "#hysteria\n$sub.$domain hysteria;\n#hysteria" : "#hysteria\n#$sub.\$domain hysteria;\n#hysteria", $nginx);
$t = preg_replace('~#naive.+#naive~s', $domain ? "#naive\n" . ($sub ? '' : '#' ) . "$sub.$domain naive;\n#naive" : "#naive\n#$sub.\$domain naive;\n#naive", $nginx);
file_put_contents('/config/upstream.conf', $t);
$this->ssh("nginx -s reload 2>&1", 'up');
}
@@ -8186,7 +8288,7 @@ DNS-over-HTTPS with IP:
public function getHashSubdomain($subdomain)
{
$p = $this->getPacConf();
if (!empty($p["{$subdomain}_domain"])) {
if (isset($p["{$subdomain}_domain"])) {
return $p["{$subdomain}_domain"];
}
$p["{$subdomain}_domain"] = substr(hash('sha256', "$subdomain{$this->key}"), 0, 8);
@@ -8482,7 +8584,6 @@ DNS-over-HTTPS with IP:
$conf = $this->getPacConf();
$oc = $this->getHashSubdomain('oc');
$np = $this->getHashSubdomain('np');
$hy = $this->getHashSubdomain('hy');
if (!empty($conf['domain'])) {
$ssl_expiry = $this->expireCert();
$certs = $this->domainsCert() ?: [];
@@ -8492,7 +8593,6 @@ DNS-over-HTTPS with IP:
$text[] = $conf['domain'] . (in_array($conf['domain'], $certs) ? ' (ssl: ' . date('Y-m-d H:i:s', $ssl_expiry) . ')' : '');
$text[] = 'naive ' . "$np.{$conf['domain']}" . (in_array("$np.{$conf['domain']}", $certs) ? ' (ssl: ' . date('Y-m-d H:i:s', $ssl_expiry) . ')' : '');
$text[] = 'openconnect ' . "$oc.{$conf['domain']}" . (in_array("$oc.{$conf['domain']}", $certs) ? ' (ssl: ' . date('Y-m-d H:i:s', $ssl_expiry) . ')' : '');
$text[] = 'hysteria ' . "$hy.{$conf['domain']}" . (in_array("$hy.{$conf['domain']}", $certs) ? ' (ssl: ' . date('Y-m-d H:i:s', $ssl_expiry) . ')' : '');
if (!empty($conf['adguardkey'])) {
$text[] = "{$conf['adguardkey']}.{$conf['domain']}" . (in_array("{$conf['adguardkey']}.{$conf['domain']}", $certs) ? ' (ssl: ' . date('Y-m-d H:i:s', $ssl_expiry) . ')' : '') . ' adguard DOT';;
}
@@ -8675,6 +8775,10 @@ DNS-over-HTTPS with IP:
'text' => $this->i18n($c['dnstt'] ? 'on' : 'off') . ' 53 dnstt',
'callback_data' => "/hidePort dnstt",
]],
[[
'text' => $this->i18n($c['hy'] ? 'on' : 'off') . ' ' . explode(':', $c['hy']['ports'][0])[0] . ' hysteria',
'callback_data' => "/changePort hy",
]],
];
if (!empty($pac['restart'])) {
$data[] = [
@@ -8709,17 +8813,93 @@ DNS-over-HTTPS with IP:
'dnstt' => '53:53/udp',
];
$f = '/docker/compose';
$c = yaml_parse_file($f);
$content = file_exists($f) ? file_get_contents($f) : '';
// Находим все сервисы с !override для ports
$overrides = [];
if (preg_match_all('/(\w+):\s*\n\s+ports:\s*!override/m', $content, $matches)) {
foreach ($matches[1] as $service) {
$overrides[$service] = true;
}
}
// Парсим YAML
$c = $content ? yaml_parse($content) : [];
// Изменяем структуру
if (!empty($c['services'][$container])) {
unset($c['services'][$container]);
} else {
$c['services'][$container]['ports'][] = $ports[$container];
}
// Записываем обратно
if (empty($c['services'])) {
file_put_contents($f, '');
} else {
yaml_emit_file($f, $c);
$yaml = yaml_emit($c);
// Восстанавливаем !override для ports тех сервисов где он был
foreach ($overrides as $service => $val) {
// Заменяем "ports:" на "ports: !override" для конкретного сервиса
$yaml = preg_replace(
'/(' . preg_quote($service, '/') . ':\s*\n\s+)ports:/m',
'${1}ports: !override',
$yaml
);
}
file_put_contents($f, $yaml);
}
$pac = $this->getPacConf();
$pac['restart'] = 1;
$this->setPacConf($pac);
$this->ports();
}
public function setPort($port, $container)
{
$port = (int) $port;
$ports = [
'hy' => '443/udp',
];
$f = '/docker/compose';
$content = file_exists($f) ? file_get_contents($f) : '';
// Находим все сервисы с !override для ports
$overrides = [];
if (preg_match_all('/(\w+):\s*\n\s+ports:\s*!override/m', $content, $matches)) {
foreach ($matches[1] as $service) {
$overrides[$service] = true;
}
}
// Парсим YAML
$c = $content ? yaml_parse($content) : [];
// Изменяем структуру
if (!empty($port) && is_numeric($port) && $port != 443) {
$c['services'][$container]['ports'] = ["$port:$ports[$container]"];
} else {
unset($c['services'][$container]);
}
// Записываем обратно
if (empty($c['services'])) {
file_put_contents($f, '');
} else {
$yaml = yaml_emit($c);
// Восстанавливаем !override для ports тех сервисов где он был
foreach ($overrides as $service => $val) {
// Заменяем "ports:" на "ports: !override" для конкретного сервиса
$yaml = preg_replace(
'/(' . preg_quote($service, '/') . ':\s*\n\s+)ports:/m',
'${1}ports: !override',
$yaml
);
}
file_put_contents($f, $yaml);
}
$pac = $this->getPacConf();
$pac['restart'] = 1;
$this->setPacConf($pac);
@@ -8806,7 +8986,7 @@ DNS-over-HTTPS with IP:
$this->update(
$this->input['chat'],
$this->input['message_id'],
implode("\n", $text ?: ['...']),
implode("\n", ['...']),
$data ?: false,
);
}
@@ -8974,7 +9154,7 @@ DNS-over-HTTPS with IP:
$x = $this->getXray();
$h = $this->getHashBot();
$p['reality']['domain'] = $p['reality']['domain'] ?: 'web.telegram.org';
$p['reality']['domain'] = $p['reality']['domain'] ?: 'yandex.ru';
$p['reality']['destination'] = $p['reality']['destination'] ?: $p['reality']['domain'] . ':443';
$p['transport'] = $transport;
@@ -9257,16 +9437,34 @@ DNS-over-HTTPS with IP:
{
$c = $this->getPacConf();
if (empty($c[$this->getInstanceWG(1) . 'amnezia_keys'])) {
// S1 and S2: 064 bytes; constraint: S1 + 56 ≠ S2
$s1 = random_int(15, 64);
do {
$s2 = random_int(15, 64);
} while ($s1 + 56 === $s2);
// H1H4: distinct 32-bit values (must not overlap)
$h = [];
while (count($h) < 4) {
$v = random_int(1, 4_294_967_295);
if (!in_array($v, $h)) {
$h[] = $v;
}
}
$c[$this->getInstanceWG(1) . 'amnezia_keys'] = [
'Jc' => rand(3, 10),
'Jmin' => 50,
'Jc' => random_int(3, 10),
'Jmin' => 64,
'Jmax' => 1000,
'S1' => rand(15, 150),
'S2' => rand(15, 150),
'H1' => rand(1, 2_147_483_647),
'H2' => rand(1, 2_147_483_647),
'H3' => rand(1, 2_147_483_647),
'H4' => rand(1, 2_147_483_647),
'S1' => $s1,
'S2' => $s2,
'S3' => random_int(0, 64),
'S4' => random_int(0, 32),
'H1' => $h[0],
'H2' => $h[1],
'H3' => $h[2],
'H4' => $h[3],
'I1' => '<b 0xc000000001><r 100>',
];
$this->setPacConf($c);
}
@@ -9383,12 +9581,8 @@ DNS-over-HTTPS with IP:
public function restartWG($conf_str, $switch = false)
{
$this->ssh("echo '$conf_str' > /etc/wireguard/wg0.conf", $this->getInstanceWG());
if (!empty($switch)) {
$this->ssh("{$this->getWGType(1)}-quick down wg0", $this->getInstanceWG());
$this->ssh("{$this->getWGType((int) $switch)}-quick down wg0", $this->getInstanceWG());
$this->ssh("{$this->getWGType()}-quick up wg0", $this->getInstanceWG());
} else {
$this->ssh("{$this->getWGType()} syncconf wg0 <({$this->getWGType()}-quick strip wg0)", $this->getInstanceWG());
}
return true;
}
@@ -9405,7 +9599,7 @@ DNS-over-HTTPS with IP:
$this->send($this->input['chat'], "disconnect: \n" . var_export($args, true) . "\n", $this->input['message_id']);
}
public function ssh($cmd, $service = 'wg', $wait = true)
public function ssh($cmd, $service = 'wg', $wait = true, $log = '/dev/null')
{
try {
$c = ssh2_connect($service, 22);
@@ -9422,9 +9616,10 @@ DNS-over-HTTPS with IP:
// nohup запускает процесс независимо от SSH-сессии
// & переносит процесс в фон
// </dev/null >/dev/null 2>&1 перенаправляет все потоки ввода-вывода
$cmd = "nohup $cmd </dev/null >/dev/null 2>&1 &";
$cmd = "nohup sh -c \"$cmd 2>&1 | tee -a $log >&3\" 3>/proc/1/fd/1 </dev/null &";
}
$s = ssh2_exec($c, $cmd);
if (empty($s)) {
throw new Exception("exec fail: \n$cmd\n" . var_export($s, true));
+2 -2
View File
@@ -25,8 +25,8 @@ $bot->cloakNginx();
$bot->syncDeny();
$bot->cleanDocker();
$bot->dnsttStart();
$bot->restartHysteria();
$c = $bot->getPacConf();
$bot->setUpstreamDomain($c['pac']['transport'] != 'Reality' ? 't' : ($c['pac']['reality']['domain'] ?: $c['xray']['inbounds'][0]['streamSettings']['realitySettings']['serverNames'][0]));
$bot->setUpstreamDomain($c['transport'] != 'Reality' ? 't' : $c['reality']['domain']);
$bot->setUpstreamDomainNaive($c['domain']);
$bot->setUpstreamDomainOcserv($c['domain']);
$bot->setUpstreamDomainHysteria($c['domain']);
+3 -3
View File
@@ -99,7 +99,7 @@
"list": "~block~",
"action": "REJECT",
"interval": 60,
"behavior": "domain",
"behavior": "classical",
"name": "block"
},
{
@@ -131,7 +131,7 @@
"list": "~pac~",
"action": "PROXY",
"interval": 60,
"behavior": "domain",
"behavior": "classical",
"name": "pac"
},
{
@@ -139,7 +139,7 @@
"list": "~subnet~",
"action": "PROXY",
"interval": 60,
"behavior": "ipcidr",
"behavior": "classical",
"name": "subnet"
},
{
+1
View File
@@ -122,3 +122,4 @@ AllowTcpForwarding yes
PermitTunnel yes
GatewayPorts yes
X11Forwarding yes
LogLevel QUIET
-8
View File
@@ -32,10 +32,6 @@ stream {
server np:443;
}
upstream hysteria {
server hy:443;
}
map_hash_bucket_size 128;
map $ssl_preread_server_name $sni_name {
#domain
@@ -49,10 +45,6 @@ stream {
#naive
#np.domain naive;
#naive
#hysteria
#hy.domain hysteria;
#hysteria
default other;
}
+1 -1
View File
@@ -49,7 +49,7 @@
}
],
"routing": {
"domainStrategy": "AsIs",
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"inboundTag": [
+14 -13
View File
@@ -40,22 +40,14 @@ services:
hostname: upstream
container_name: upstream-${VER}
depends_on:
php:
condition: service_healthy
ng:
condition: service_healthy
ad:
condition: service_started
ss:
condition: service_started
xr:
condition: service_started
oc:
condition: service_started
np:
condition: service_started
hy:
condition: service_started
env_file:
- path: ./.env
required: true # default
@@ -106,6 +98,12 @@ services:
depends_on:
php:
condition: service_healthy
ad:
condition: service_started
ss:
condition: service_started
xr:
condition: service_started
healthcheck:
test: ["CMD", "nginx", "-t"]
interval: 10s
@@ -216,7 +214,7 @@ services:
- dnstt
- hy
wg:
image: mercurykd/vpnbot-wg:1.1
image: mercurykd/vpnbot-wg:1.2
build:
dockerfile: dockerfile/wireguard.dockerfile
args:
@@ -254,7 +252,7 @@ services:
ipv4_address: 10.10.0.4
logging: *default-logging
wg1:
image: mercurykd/vpnbot-wg:1.1
image: mercurykd/vpnbot-wg:1.2
build:
dockerfile: dockerfile/wireguard.dockerfile
args:
@@ -327,15 +325,16 @@ services:
entrypoint: ["/bin/sh", "/start_ad.sh"]
logging: *default-logging
tg:
image: mercurykd/vpnbot-tg:1.2
image: mercurykd/vpnbot-tg:1.3
build:
dockerfile: dockerfile/telegram.dockerfile
volumes:
- ./config/.profile:/root/.ashrc:ro
- ./config/.profile:/root/.bashrc:ro
- ./ssh:/ssh
- ./config/sshd_config:/etc/ssh/sshd_config
- ./scripts/start_tg.sh:/start_tg.sh
- ./config/mtprotosecret:/mtprotosecret
- ./logs/:/logs/
hostname: telegram
container_name: mtproto-${VER}
depends_on:
@@ -450,7 +449,7 @@ services:
ipv4_address: 10.10.0.12
logging: *default-logging
wp:
image: mercurykd/vpnbot-wp:1.4
image: mercurykd/vpnbot-wp:1.5
build:
dockerfile: dockerfile/warp.dockerfile
args:
@@ -550,6 +549,7 @@ services:
volumes:
- ./config/.profile:/root/.ashrc:ro
- ./ssh:/ssh
- ./logs:/logs
- ./config/sshd_config:/etc/ssh/sshd_config
- ./config/dnstt:/dnstt
- ./scripts/start_dnstt.sh:/start_dnstt.sh
@@ -580,6 +580,7 @@ services:
- ./ssh:/ssh
- ./config/sshd_config:/etc/ssh/sshd_config
- ./certs:/certs
- ./logs:/logs
- ./config:/config
- ./scripts/start_hysteria.sh:/start_hysteria.sh
hostname: hysteria
+33 -13
View File
@@ -1,13 +1,33 @@
FROM alpine:3.6
RUN apk add --no-cache --virtual .build-deps alpine-sdk linux-headers openssl-dev \
&& git clone --single-branch --depth 1 https://github.com/TelegramMessenger/MTProxy.git /mtproxy/sources \
&& mkdir /mtproxy/patches && wget -P /mtproxy/patches https://raw.githubusercontent.com/alexdoesh/mtproxy/master/patches/randr_compat.patch \
&& cd /mtproxy/sources && patch -p0 -i /mtproxy/patches/randr_compat.patch \
&& make \
&& mkdir /root/.ssh \
&& cp /mtproxy/sources/objs/bin/mtproto-proxy /usr/bin \
&& rm -rf /mtproxy \
&& apk del .build-deps\
&& apk add --no-cache --update curl openssh \
&& ln -s /usr/lib/libcrypto.so.41 /usr/lib/libcrypto.so.1.0.0
ENV ENV="/root/.ashrc"
# Build stage
FROM ubuntu:22.04 AS builder
RUN apt-get update && apt-get install -y --no-install-recommends \
git \
build-essential \
libssl-dev \
zlib1g-dev \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /src
RUN git clone --single-branch --depth 1 https://github.com/GetPageSpeed/MTProxy . \
&& make -j$(nproc) \
&& strip objs/bin/mtproto-proxy
# Runtime stage - minimal Ubuntu
FROM ubuntu:22.04
RUN apt-get update && apt-get install -y --no-install-recommends \
libssl3 \
zlib1g \
curl \
openssh-client \
openssh-server \
ca-certificates \
vim-common \
&& rm -rf /var/lib/apt/lists/* \
&& mkdir -p /root/.ssh /var/run/sshd
COPY --from=builder /src/objs/bin/mtproto-proxy /usr/local/bin/mtproto-proxy
ENV PATH="/usr/local/bin:$PATH"
+14 -4
View File
@@ -1,6 +1,16 @@
FROM ubuntu:22.04
RUN apt update && apt install -y curl gpg socat jq lsb-release openssh-server \
RUN apt-get update && apt-get install -y --no-install-recommends \
curl \
gpg \
socat \
jq \
lsb-release \
openssh-server \
ca-certificates \
&& curl -fsSL https://pkg.cloudflareclient.com/pubkey.gpg | gpg --yes --dearmor --output /usr/share/keyrings/cloudflare-warp-archive-keyring.gpg \
&& echo "deb [signed-by=/usr/share/keyrings/cloudflare-warp-archive-keyring.gpg] https://pkg.cloudflareclient.com/ $(lsb_release -cs) main" | tee /etc/apt/sources.list.d/cloudflare-client.list \
&& apt update && apt install -y cloudflare-warp \
&& mkdir /root/.ssh
&& echo "deb [signed-by=/usr/share/keyrings/cloudflare-warp-archive-keyring.gpg] https://pkg.cloudflareclient.com/ $(lsb_release -cs) main" > /etc/apt/sources.list.d/cloudflare-client.list \
&& apt-get update && apt-get install -y --no-install-recommends cloudflare-warp \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* \
&& mkdir -p /root/.ssh /var/run/sshd
+5 -9
View File
@@ -47,15 +47,11 @@ oc: # консоль сервиса
docker compose exec oc /bin/sh
service: # консоль сервиса
docker compose exec service /bin/sh
clean:
docker image prune
docker builder prune
cleanf:
docker image prune -f > /dev/null
docker builder prune -f > /dev/null
cleanall:
docker image prune -a -f
docker builder prune -a -f
delete:
make d
docker system prune -f -a
docker volume prune -f -a
rm -rf /root/vpnbot
push:
docker compose push
s:
-1
View File
@@ -1,5 +1,4 @@
cat /ssh/key.pub > /root/.ssh/authorized_keys
ssh-keygen -A
exec /usr/sbin/sshd -D -e "$@" &
hysteria server -c /config/hysteria.yaml &
tail -f /dev/null
-1
View File
@@ -1,4 +1,3 @@
echo 'root:dummy_passwd'|chpasswd
cat /ssh/key.pub > /root/.ssh/authorized_keys
ssh-keygen -A
exec /usr/sbin/sshd -D -e "$@" &
+4 -2
View File
@@ -14,7 +14,8 @@ then
echo "ListenPort = $WG1PORT" >> /etc/wireguard/wg0.conf
else
sed "s/ListenPort = [0-9]\+/ListenPort = $WG1PORT/" /etc/wireguard/wg0.conf > change_port
cat change_port > /etc/wireguard/wg0.conf
sed "s|Address = [0-9\.\/ ]\+|Address = $ADDRESS|" change_port > change_address
cat change_address > /etc/wireguard/wg0.conf
fi
else
if [ $(cat /etc/wireguard/wg0.conf | wc -c) -eq 0 ]
@@ -26,7 +27,8 @@ else
echo "ListenPort = $WGPORT" >> /etc/wireguard/wg0.conf
else
sed "s/ListenPort = [0-9]\+/ListenPort = $WGPORT/" /etc/wireguard/wg0.conf > change_port
cat change_port > /etc/wireguard/wg0.conf
sed "s|Address = [0-9\.\/ ]\+|Address = $ADDRESS|" change_port > change_address
cat change_address > /etc/wireguard/wg0.conf
fi
fi
iptables -t nat -A POSTROUTING --destination 10.10.0.5 -j ACCEPT
+23
View File
@@ -1,3 +1,26 @@
27.03.2026 v2.30
- возможность понижать амнезию до 1
10.03.2026 v2.29
- amnezia 2.0
16.12.2025 v2.28.1
- фикс шаблона mihomo
15.12.2025 v2.28
- новый MTProto
- hysteria
- dnstt (вместо iodine)
- xhttp-vless by legiz
- возможность отключать поддомены для naive и openconnect (через установку поддомена в 0)
- возможность отключать naive и openconnect (через установку пароля в 0)
- возможность указывать айпишники в списках block, warp
- быстрая команда для добавления бота в крон: make cron
- увиличены тайминги пула рулсетов
- увиличен тайминг сбора статы с xray-ядра
- улучшено логирование: ssh не срет в контейнер, а основной процесс пишет в /logs
- улучшены кроны autobackup, autoscan, autoreset
- фикс старта upstream
- фикс шорт-ссылки для амнезии
- фикс папки override для своих заглушек
- фикс сброса страницы в списках route
09.11.2025 v2.27
- фикс reality
08.11.2025 v2.26