Compare commits

...

23 Commits

Author SHA1 Message Date
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
13 changed files with 282 additions and 141 deletions
+192 -88
View File
@@ -179,6 +179,9 @@ class Bot
case preg_match('~^/setHwidDevices(?: (\w+))?$~', $this->input['callback'], $m): case preg_match('~^/setHwidDevices(?: (\w+))?$~', $this->input['callback'], $m):
$this->setHwidDevices($m[1] ?? null); $this->setHwidDevices($m[1] ?? null);
break; 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): case preg_match('~^/hwidUser (\d+)(?:_(\d+))?$~', $this->input['callback'], $m):
$this->hwidUser($m[1], $m[2] ?? 0); $this->hwidUser($m[1], $m[2] ?? 0);
break; break;
@@ -558,8 +561,8 @@ class Bot
case preg_match('~^/addNipdomain$~', $this->input['callback'], $m): case preg_match('~^/addNipdomain$~', $this->input['callback'], $m):
$this->addNipdomain(); $this->addNipdomain();
break; break;
case preg_match('~^/(?P<action>change|delete)(?P<typelist>\w+) (?P<arg>\d+)$~', $this->input['callback'], $m): 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']); $this->listPacChange($m['typelist'], $m['action'], $m['arg'], $m['page'] ?: 0);
break; break;
case preg_match('~^/paczapret$~', $this->input['callback'], $m): case preg_match('~^/paczapret$~', $this->input['callback'], $m):
$this->pacZapret(); $this->pacZapret();
@@ -725,11 +728,11 @@ class Bot
public function restartTG() public function restartTG()
{ {
$secret = file_get_contents('/config/mtprotosecret'); $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'); $this->ssh('pkill mtproto-proxy', 'tg');
if (preg_match('~^\w{32}$~', $secret)) { if (preg_match('~^\w{32}$~', $secret)) {
$p = getenv('TGPORT'); $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 +820,15 @@ class Bot
{ {
$s = file_get_contents('/config/mtprotosecret'); $s = file_get_contents('/config/mtprotosecret');
$p = getenv('TGPORT'); $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"); $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"; return "https://t.me/proxy?server=$ip&port=$p&secret=ee$s$d";
} }
public function mtproto() 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'; $st = $this->ssh('pgrep mtproto-proxy', 'tg') ? 'on' : 'off';
$text[] = "Menu -> MTProto\n"; $text[] = "Menu -> MTProto\n";
$text[] = "status: $st\n"; $text[] = "status: $st\n";
@@ -1147,7 +1150,7 @@ class Bot
file_put_contents('/config/ocserv.conf', $conf); file_put_contents('/config/ocserv.conf', $conf);
$this->ssh('pkill ocserv', 'oc'); $this->ssh('pkill ocserv', 'oc');
$pac = $this->getPacConf(); $pac = $this->getPacConf();
if (!empty($pac['ocserv'])) { if (!empty($pac['ocserv']) && !empty($this->getHashSubdomain('oc'))) {
$this->ssh('ocserv -c /etc/ocserv/ocserv.conf', 'oc'); $this->ssh('ocserv -c /etc/ocserv/ocserv.conf', 'oc');
} }
} }
@@ -1159,7 +1162,7 @@ class Bot
$c = file_get_contents('/config/Caddyfile'); $c = file_get_contents('/config/Caddyfile');
$t = preg_replace('~^(\t+)?basic_auth[^\n]+~sm', '$1basic_auth ' . ($pac['naive']['user'] ?? '_') . ' ' . ($pac['naive']['pass'] ?? '__'), $c); $t = preg_replace('~^(\t+)?basic_auth[^\n]+~sm', '$1basic_auth ' . ($pac['naive']['user'] ?? '_') . ' ' . ($pac['naive']['pass'] ?? '__'), $c);
file_put_contents('/config/Caddyfile', $t); 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); $this->ssh('caddy run -c /config/Caddyfile', 'np', false);
} }
} }
@@ -1172,7 +1175,7 @@ class Bot
$c['auth']['password'] = $pac['hysteria_pass']; $c['auth']['password'] = $pac['hysteria_pass'];
yaml_emit_file('/config/hysteria.yaml', $c); yaml_emit_file('/config/hysteria.yaml', $c);
if (!empty($pac['hysteria_pass'])) { 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 +1190,7 @@ class Bot
public function chOcSubdomain($domain) public function chOcSubdomain($domain)
{ {
$pac = $this->getPacConf(); $pac = $this->getPacConf();
if (empty($domain)) { if ($domain == -1) {
unset($pac["oc_domain"]); unset($pac["oc_domain"]);
} else { } else {
$pac["oc_domain"] = $domain; $pac["oc_domain"] = $domain;
@@ -1201,7 +1204,7 @@ class Bot
public function chNpSubdomain($domain) public function chNpSubdomain($domain)
{ {
$pac = $this->getPacConf(); $pac = $this->getPacConf();
if (!empty($data)) { if ($domain == -1) {
unset($pac['np_domain']); unset($pac['np_domain']);
} else { } else {
$pac['np_domain'] = $domain; $pac['np_domain'] = $domain;
@@ -1831,6 +1834,10 @@ class Bot
'private' => file_get_contents('/certs/cert_private'), 'private' => file_get_contents('/certs/cert_private'),
'public' => file_get_contents('/certs/cert_public'), 'public' => file_get_contents('/certs/cert_public'),
] : false, ] : 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'), 'mtproto' => file_get_contents('/config/mtprotosecret'),
'mtprotodomain' => file_get_contents('/config/mtprotodomain'), 'mtprotodomain' => file_get_contents('/config/mtprotodomain'),
'xray' => $this->getXray(), 'xray' => $this->getXray(),
@@ -1982,7 +1989,13 @@ class Bot
if (!empty($json['pac']['domain'])) { if (!empty($json['pac']['domain'])) {
$this->setUpstreamDomainOcserv($json['pac']['domain']); $this->setUpstreamDomainOcserv($json['pac']['domain']);
$this->setUpstreamDomainNaive($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 // nginx
$out[] = 'reset nginx'; $out[] = 'reset nginx';
@@ -2400,8 +2413,7 @@ class Bot
$adguardClient = $conf['adguardkey'] ? "-d {$conf['adguardkey']}.{$conf['domain']}" : ''; $adguardClient = $conf['adguardkey'] ? "-d {$conf['adguardkey']}.{$conf['domain']}" : '';
$oc = $this->getHashSubdomain('oc'); $oc = $this->getHashSubdomain('oc');
$np = $this->getHashSubdomain('np'); $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']}" . ($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);
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);
if ($code > 0) { if ($code > 0) {
$this->send($this->input['chat'], "ERROR\n" . implode("\n", $out)); $this->send($this->input['chat'], "ERROR\n" . implode("\n", $out));
break; break;
@@ -2635,6 +2647,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() public function addLinkDomain()
{ {
$r = $this->send( $r = $this->send(
@@ -2945,42 +2972,42 @@ DNS-over-HTTPS with IP:
$page = (int) floor(array_search($v, array_keys($conf[$type])) / $this->limit); $page = (int) floor(array_search($v, array_keys($conf[$type])) / $this->limit);
} }
$page = $page ?: -2; $page = $page ?: -2;
$this->backXtlsList($type); $this->backXtlsList($type, $page);
} }
public function backXtlsList($type) public function backXtlsList($type, $page = 0)
{ {
switch ($type) { switch ($type) {
case 'includelist': case 'includelist':
$this->pacUpdate($_SESSION['proxylistentry']); $this->pacUpdate($_SESSION['proxylistentry']);
if (!empty($_SESSION['proxylistentry'])) { if (!empty($_SESSION['proxylistentry'])) {
$this->xtlsproxy(); $this->xtlsproxy($page);
} }
break; break;
case 'blocklist': case 'blocklist':
$this->xrayUpdateRules(); $this->xrayUpdateRules();
$this->xtlsblock(); $this->xtlsblock($page);
break; break;
case 'warplist': case 'warplist':
$this->xrayUpdateRules(); $this->xrayUpdateRules();
$this->xtlswarp(); $this->xtlswarp($page);
break; break;
case 'processlist': case 'processlist':
$this->xtlsprocess(); $this->xtlsprocess($page);
break; break;
case 'packagelist': case 'packagelist':
$this->xtlsapp(); $this->xtlsapp($page);
break; break;
case 'subnetlist': case 'subnetlist':
$this->xtlssubnet(); $this->xtlssubnet($page);
break; break;
case 'rulessetlist': case 'rulessetlist':
$this->xtlsrulesset(); $this->xtlsrulesset($page);
break; break;
case 'white': case 'white':
case 'deny': case 'deny':
$this->syncDeny(); $this->syncDeny();
$this->denyList(0, $type == 'white' ? 1 : 0); $this->denyList($page, $type == 'white' ? 1 : 0);
break; break;
} }
} }
@@ -3775,6 +3802,7 @@ DNS-over-HTTPS with IP:
public function getAmneziaShortLink($client) public function getAmneziaShortLink($client)
{ {
$domain = $this->getDomain();
$dns = explode(',', $client['interface']['DNS']); $dns = explode(',', $client['interface']['DNS']);
$c = json_encode([ $c = json_encode([
"containers" => [ "containers" => [
@@ -3795,8 +3823,8 @@ DNS-over-HTTPS with IP:
"client_priv_key" => $client['interface']['PrivateKey'], "client_priv_key" => $client['interface']['PrivateKey'],
"client_pub_key" => "0", "client_pub_key" => "0",
"config" => $this->createConfig($client), "config" => $this->createConfig($client),
"hostName" => $this->ip, "hostName" => $domain,
"port" => (int) getenv('WG1PORT'), "port" => (int) getenv($this->getInstanceWG() == 'wg1' ? 'WG1PORT' : 'WGPORT'),
"psk_key" => $client['peers'][0]['PresharedKey'], "psk_key" => $client['peers'][0]['PresharedKey'],
"server_pub_key" => $client['peers'][0]['PublicKey'] "server_pub_key" => $client['peers'][0]['PublicKey']
]), ]),
@@ -3810,7 +3838,7 @@ DNS-over-HTTPS with IP:
"description" => $client['interface']['## name'], "description" => $client['interface']['## name'],
"dns1" => $dns[0], "dns1" => $dns[0],
"dns2" => $dns[1] ?: '', "dns2" => $dns[1] ?: '',
"hostName" => $this->ip "hostName" => $domain
]); ]);
exec("echo '$c' | python amnezia.py", $o); exec("echo '$c' | python amnezia.py", $o);
return $o[0]; return $o[0];
@@ -4398,11 +4426,11 @@ DNS-over-HTTPS with IP:
$data[] = [ $data[] = [
[ [
'text' => $this->i18n($v ? 'on' : 'off') . ' ' . ($basename ? basename($k) . ' ' : '') . (in_array($type, ['rulessetlist', 'packagelist', 'processlist', 'subnetlist']) ? $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) . " $page",
], ],
[ [
'text' => 'delete', 'text' => 'delete',
'callback_data' => "/delete$type " . ($i + $page * $this->limit), 'callback_data' => "/delete$type " . ($i + $page * $this->limit) . " $page",
], ],
]; ];
$i++; $i++;
@@ -4448,7 +4476,7 @@ DNS-over-HTTPS with IP:
return [$data, $text]; return [$data, $text];
} }
public function listPacChange($type, $action, $key) public function listPacChange($type, $action, $key, $page = 0)
{ {
$conf = $this->getPacConf(); $conf = $this->getPacConf();
$i = 0; $i = 0;
@@ -4467,7 +4495,7 @@ DNS-over-HTTPS with IP:
$i++; $i++;
} }
$this->setPacConf($conf); $this->setPacConf($conf);
$this->backXtlsList($type); $this->backXtlsList($type, $page);
} }
public function pacZapret() public function pacZapret()
@@ -4659,7 +4687,7 @@ DNS-over-HTTPS with IP:
if (!file_exists('/config/dnstt/server.key')) { 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 -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');
} }
} }
@@ -4673,20 +4701,24 @@ DNS-over-HTTPS with IP:
$c = $this->getPacConf(); $c = $this->getPacConf();
$pubkey = file_get_contents('/config/dnstt/server.pub'); $pubkey = file_get_contents('/config/dnstt/server.pub');
$text[] = "dnstt"; $text[] = "dnstt";
$text[] = "<pre>set the NS record for {$c['dnsttDomain']}: tns.{$c['domain']}\nset A record for tns.{$c['domain']}: {$this->ip}</pre>"; if (!empty($c['dnsttDomain']) && !empty($c['dnsttPassword'])) {
$text[] = "domain: <code>{$c['dnsttDomain']}</code>"; $text[] = "<pre>set the NS record for {$c['dnsttDomain']}: tns.{$c['domain']}\nset A record for tns.{$c['domain']}: {$this->ip}</pre>";
$text[] = "ssh: <code>vpnbot:{$c['dnsttPassword']}</code>"; $text[] = "account: <code>vpnbot:{$c['dnsttPassword']}</code>";
$text[] = "pubkey: <code>$pubkey</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[] = [ $data[] = [
[ [
'text' => $this->i18n('download pubkey'), 'text' => $this->i18n('set subdomain'),
'callback_data' => "/dnsttDownload",
],
];
$data[] = [
[
'text' => $this->i18n('set domain'),
'callback_data' => "/dnsttDomain", 'callback_data' => "/dnsttDomain",
], ],
]; ];
@@ -4735,7 +4767,6 @@ DNS-over-HTTPS with IP:
$main[] = ''; $main[] = '';
$oc = $this->getHashSubdomain('oc'); $oc = $this->getHashSubdomain('oc');
$np = $this->getHashSubdomain('np'); $np = $this->getHashSubdomain('np');
$hy = $this->getHashSubdomain('hy');
if (!empty($conf['domain'])) { if (!empty($conf['domain'])) {
$ssl_expiry = $this->expireCert(); $ssl_expiry = $this->expireCert();
$certs = $this->domainsCert() ?: []; $certs = $this->domainsCert() ?: [];
@@ -4743,9 +4774,12 @@ DNS-over-HTTPS with IP:
$main[] = "<blockquote>"; $main[] = "<blockquote>";
$main[] = "Domains:"; $main[] = "Domains:";
$main[] = $conf['domain'] . (in_array($conf['domain'], $certs) ? ' (ssl: ' . date('Y-m-d H:i:s', $ssl_expiry) . ')' : ''); $main[] = $conf['domain'] . (in_array($conf['domain'], $certs) ? ' (ssl: ' . date('Y-m-d H:i:s', $ssl_expiry) . ')' : '');
$main[] = 'naive ' . "$np.{$conf['domain']}" . (in_array("$np.{$conf['domain']}", $certs) ? ' (ssl: ' . date('Y-m-d H:i:s', $ssl_expiry) . ')' : ''); if (!empty($np)) {
$main[] = 'openconnect ' . "$oc.{$conf['domain']}" . (in_array("$oc.{$conf['domain']}", $certs) ? ' (ssl: ' . date('Y-m-d H:i:s', $ssl_expiry) . ')' : ''); $main[] = 'naive ' . "$np.{$conf['domain']}" . (in_array("$np.{$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($oc)) {
$main[] = 'openconnect ' . "$oc.{$conf['domain']}" . (in_array("$oc.{$conf['domain']}", $certs) ? ' (ssl: ' . date('Y-m-d H:i:s', $ssl_expiry) . ')' : '');
}
if (!empty($conf['adguardkey'])) { 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';; $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,7 +4788,11 @@ DNS-over-HTTPS with IP:
$main[] = $this->i18n('domain explain'); $main[] = $this->i18n('domain explain');
} }
} }
$main[] = '';
$ports = yaml_parse_file('/docker/compose')['services'];
$hy_port = explode(':', $c['hy']['ports'][0])[0];
$main[] = '';
$main[] = '<code>'; $main[] = '<code>';
$main[] = $this->alignColumns([ $main[] = $this->alignColumns([
@@ -4777,7 +4815,7 @@ DNS-over-HTTPS with IP:
$this->i18n('on') . ' 443', $this->i18n('on') . ' 443',
$this->i18n('on') . ' 443', $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['tg'] ? 'on' : 'off') . ' ' . getenv('TGPORT'),
$this->i18n($c['ad'] ? 'on' : 'off') . ' 853', $this->i18n($c['ad'] ? 'on' : 'off') . ' 853',
$this->i18n($c['ss'] ? 'on' : 'off') . ' ' . getenv('SSPORT'), $this->i18n($c['ss'] ? 'on' : 'off') . ' ' . getenv('SSPORT'),
@@ -4888,7 +4926,7 @@ DNS-over-HTTPS with IP:
'wg' => $type == 'wg' ? $this->statusWg($arg) : false, 'wg' => $type == 'wg' ? $this->statusWg($arg) : false,
'client' => $type == 'client' ? $this->getClient(...explode('_', $arg)) : false, 'client' => $type == 'client' ? $this->getClient(...explode('_', $arg)) : false,
'addpeer' => $type == 'addpeer' ? $this->addWg(...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, 'adguard' => $type == 'adguard' ? $this->adguardMenu() : false,
'config' => $type == 'config' ? $this->configMenu() : false, 'config' => $type == 'config' ? $this->configMenu() : false,
'ss' => $type == 'ss' ? $this->menuSS() : false, 'ss' => $type == 'ss' ? $this->menuSS() : false,
@@ -5953,10 +5991,12 @@ DNS-over-HTTPS with IP:
public function hysteriaMenu() public function hysteriaMenu()
{ {
$pac = $this->getPacConf(); $pac = $this->getPacConf();
$f = '/docker/compose';
$c = yaml_parse_file($f)['services'];
$port = explode(':', $c['hy']['ports'][0])[0];
$domain = $this->getDomain(); $domain = $this->getDomain();
$text[] = "Menu -> Hysteria"; $text[] = "Menu -> Hysteria";
$hy = $this->getHashSubdomain('hy'); $text[] = "server: " . ($port? "<code>$domain:$port</code>" : 'port unavailable');
$text[] = "server: <code>$hy.$domain</code>";
$text[] = "passwd: <code>{$pac['hysteria_pass']}</code>"; $text[] = "passwd: <code>{$pac['hysteria_pass']}</code>";
$data[] = [ $data[] = [
[ [
@@ -7908,17 +7948,11 @@ DNS-over-HTTPS with IP:
case 'package': case 'package':
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'])]);
break; 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: default:
echo yaml_emit(['payload' => array_map(function($e) { 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)) { if (preg_match('~^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(/\d{1,2})?$~', $e, $m)) {
return "IP-CIDR,$e"; return "IP-CIDR,$e" . (empty($m[1]) ? '/32' : '');
} else { } else {
return "DOMAIN-SUFFIX,$e"; return "DOMAIN-SUFFIX,$e";
} }
@@ -8019,10 +8053,10 @@ DNS-over-HTTPS with IP:
foreach ($rules as $k => $v) { foreach ($rules as $k => $v) {
if (array_key_exists('domain_suffix', $v)) { if (array_key_exists('domain_suffix', $v)) {
foreach ($v['domain_suffix'] as $j) { 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; $domains[] = $j;
} else { } else {
$ips[] = $j; $ips[] = $j . (empty($m[1]) ? '/32' : '');
} }
} }
unset($rules[$k]['domain_suffix']); unset($rules[$k]['domain_suffix']);
@@ -8104,7 +8138,7 @@ DNS-over-HTTPS with IP:
{ {
$sub = $this->getHashSubdomain('oc'); $sub = $this->getHashSubdomain('oc');
$nginx = file_get_contents('/config/upstream.conf'); $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); file_put_contents('/config/upstream.conf', $t);
$this->ssh("nginx -s reload 2>&1", 'up'); $this->ssh("nginx -s reload 2>&1", 'up');
} }
@@ -8113,16 +8147,7 @@ DNS-over-HTTPS with IP:
{ {
$sub = $this->getHashSubdomain('np'); $sub = $this->getHashSubdomain('np');
$nginx = file_get_contents('/config/upstream.conf'); $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); $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');
}
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);
file_put_contents('/config/upstream.conf', $t); file_put_contents('/config/upstream.conf', $t);
$this->ssh("nginx -s reload 2>&1", 'up'); $this->ssh("nginx -s reload 2>&1", 'up');
} }
@@ -8186,7 +8211,7 @@ DNS-over-HTTPS with IP:
public function getHashSubdomain($subdomain) public function getHashSubdomain($subdomain)
{ {
$p = $this->getPacConf(); $p = $this->getPacConf();
if (!empty($p["{$subdomain}_domain"])) { if (isset($p["{$subdomain}_domain"])) {
return $p["{$subdomain}_domain"]; return $p["{$subdomain}_domain"];
} }
$p["{$subdomain}_domain"] = substr(hash('sha256', "$subdomain{$this->key}"), 0, 8); $p["{$subdomain}_domain"] = substr(hash('sha256', "$subdomain{$this->key}"), 0, 8);
@@ -8482,7 +8507,6 @@ DNS-over-HTTPS with IP:
$conf = $this->getPacConf(); $conf = $this->getPacConf();
$oc = $this->getHashSubdomain('oc'); $oc = $this->getHashSubdomain('oc');
$np = $this->getHashSubdomain('np'); $np = $this->getHashSubdomain('np');
$hy = $this->getHashSubdomain('hy');
if (!empty($conf['domain'])) { if (!empty($conf['domain'])) {
$ssl_expiry = $this->expireCert(); $ssl_expiry = $this->expireCert();
$certs = $this->domainsCert() ?: []; $certs = $this->domainsCert() ?: [];
@@ -8492,7 +8516,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[] = $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[] = '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[] = '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'])) { 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';; $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 +8698,10 @@ DNS-over-HTTPS with IP:
'text' => $this->i18n($c['dnstt'] ? 'on' : 'off') . ' 53 dnstt', 'text' => $this->i18n($c['dnstt'] ? 'on' : 'off') . ' 53 dnstt',
'callback_data' => "/hidePort 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'])) { if (!empty($pac['restart'])) {
$data[] = [ $data[] = [
@@ -8701,25 +8728,101 @@ DNS-over-HTTPS with IP:
public function hidePort($container) public function hidePort($container)
{ {
$ports = [ $ports = [
'wg' => getenv('WGPORT') . ':' . getenv('WGPORT') . '/udp', 'wg' => getenv('WGPORT') . ':' . getenv('WGPORT') . '/udp',
'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', 'ss' => '8388:8388',
'dnstt' => '53:53/udp', 'dnstt' => '53:53/udp',
]; ];
$f = '/docker/compose'; $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])) { if (!empty($c['services'][$container])) {
unset($c['services'][$container]); unset($c['services'][$container]);
} else { } else {
$c['services'][$container]['ports'][] = $ports[$container]; $c['services'][$container]['ports'][] = $ports[$container];
} }
// Записываем обратно
if (empty($c['services'])) { if (empty($c['services'])) {
file_put_contents($f, ''); file_put_contents($f, '');
} else { } 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 = $this->getPacConf();
$pac['restart'] = 1; $pac['restart'] = 1;
$this->setPacConf($pac); $this->setPacConf($pac);
@@ -8974,7 +9077,7 @@ DNS-over-HTTPS with IP:
$x = $this->getXray(); $x = $this->getXray();
$h = $this->getHashBot(); $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['reality']['destination'] = $p['reality']['destination'] ?: $p['reality']['domain'] . ':443';
$p['transport'] = $transport; $p['transport'] = $transport;
@@ -9405,7 +9508,7 @@ DNS-over-HTTPS with IP:
$this->send($this->input['chat'], "disconnect: \n" . var_export($args, true) . "\n", $this->input['message_id']); $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 { try {
$c = ssh2_connect($service, 22); $c = ssh2_connect($service, 22);
@@ -9422,9 +9525,10 @@ DNS-over-HTTPS with IP:
// nohup запускает процесс независимо от SSH-сессии // nohup запускает процесс независимо от SSH-сессии
// & переносит процесс в фон // & переносит процесс в фон
// </dev/null >/dev/null 2>&1 перенаправляет все потоки ввода-вывода // </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); $s = ssh2_exec($c, $cmd);
if (empty($s)) { if (empty($s)) {
throw new Exception("exec fail: \n$cmd\n" . var_export($s, true)); 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->syncDeny();
$bot->cleanDocker(); $bot->cleanDocker();
$bot->dnsttStart(); $bot->dnsttStart();
$bot->restartHysteria();
$c = $bot->getPacConf(); $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->setUpstreamDomainNaive($c['domain']);
$bot->setUpstreamDomainOcserv($c['domain']); $bot->setUpstreamDomainOcserv($c['domain']);
$bot->setUpstreamDomainHysteria($c['domain']);
+2 -1
View File
@@ -121,4 +121,5 @@ PasswordAuthentication yes
AllowTcpForwarding yes AllowTcpForwarding yes
PermitTunnel yes PermitTunnel yes
GatewayPorts yes GatewayPorts yes
X11Forwarding yes X11Forwarding yes
LogLevel QUIET
-8
View File
@@ -32,10 +32,6 @@ stream {
server np:443; server np:443;
} }
upstream hysteria {
server hy:443;
}
map_hash_bucket_size 128; map_hash_bucket_size 128;
map $ssl_preread_server_name $sni_name { map $ssl_preread_server_name $sni_name {
#domain #domain
@@ -49,10 +45,6 @@ stream {
#naive #naive
#np.domain naive; #np.domain naive;
#naive #naive
#hysteria
#hy.domain hysteria;
#hysteria
default other; default other;
} }
+1 -1
View File
@@ -49,7 +49,7 @@
} }
], ],
"routing": { "routing": {
"domainStrategy": "AsIs", "domainStrategy": "IPIfNonMatch",
"rules": [ "rules": [
{ {
"inboundTag": [ "inboundTag": [
+12 -11
View File
@@ -40,22 +40,14 @@ services:
hostname: upstream hostname: upstream
container_name: upstream-${VER} container_name: upstream-${VER}
depends_on: depends_on:
php:
condition: service_healthy
ng: ng:
condition: service_healthy condition: service_healthy
ad:
condition: service_started
ss:
condition: service_started
xr: xr:
condition: service_started condition: service_started
oc: oc:
condition: service_started condition: service_started
np: np:
condition: service_started condition: service_started
hy:
condition: service_started
env_file: env_file:
- path: ./.env - path: ./.env
required: true # default required: true # default
@@ -106,6 +98,12 @@ services:
depends_on: depends_on:
php: php:
condition: service_healthy condition: service_healthy
ad:
condition: service_started
ss:
condition: service_started
xr:
condition: service_started
healthcheck: healthcheck:
test: ["CMD", "nginx", "-t"] test: ["CMD", "nginx", "-t"]
interval: 10s interval: 10s
@@ -327,15 +325,16 @@ services:
entrypoint: ["/bin/sh", "/start_ad.sh"] entrypoint: ["/bin/sh", "/start_ad.sh"]
logging: *default-logging logging: *default-logging
tg: tg:
image: mercurykd/vpnbot-tg:1.2 image: mercurykd/vpnbot-tg:1.3
build: build:
dockerfile: dockerfile/telegram.dockerfile dockerfile: dockerfile/telegram.dockerfile
volumes: volumes:
- ./config/.profile:/root/.ashrc:ro - ./config/.profile:/root/.bashrc:ro
- ./ssh:/ssh - ./ssh:/ssh
- ./config/sshd_config:/etc/ssh/sshd_config - ./config/sshd_config:/etc/ssh/sshd_config
- ./scripts/start_tg.sh:/start_tg.sh - ./scripts/start_tg.sh:/start_tg.sh
- ./config/mtprotosecret:/mtprotosecret - ./config/mtprotosecret:/mtprotosecret
- ./logs/:/logs/
hostname: telegram hostname: telegram
container_name: mtproto-${VER} container_name: mtproto-${VER}
depends_on: depends_on:
@@ -450,7 +449,7 @@ services:
ipv4_address: 10.10.0.12 ipv4_address: 10.10.0.12
logging: *default-logging logging: *default-logging
wp: wp:
image: mercurykd/vpnbot-wp:1.4 image: mercurykd/vpnbot-wp:1.5
build: build:
dockerfile: dockerfile/warp.dockerfile dockerfile: dockerfile/warp.dockerfile
args: args:
@@ -550,6 +549,7 @@ services:
volumes: volumes:
- ./config/.profile:/root/.ashrc:ro - ./config/.profile:/root/.ashrc:ro
- ./ssh:/ssh - ./ssh:/ssh
- ./logs:/logs
- ./config/sshd_config:/etc/ssh/sshd_config - ./config/sshd_config:/etc/ssh/sshd_config
- ./config/dnstt:/dnstt - ./config/dnstt:/dnstt
- ./scripts/start_dnstt.sh:/start_dnstt.sh - ./scripts/start_dnstt.sh:/start_dnstt.sh
@@ -580,6 +580,7 @@ services:
- ./ssh:/ssh - ./ssh:/ssh
- ./config/sshd_config:/etc/ssh/sshd_config - ./config/sshd_config:/etc/ssh/sshd_config
- ./certs:/certs - ./certs:/certs
- ./logs:/logs
- ./config:/config - ./config:/config
- ./scripts/start_hysteria.sh:/start_hysteria.sh - ./scripts/start_hysteria.sh:/start_hysteria.sh
hostname: hysteria hostname: hysteria
+33 -13
View File
@@ -1,13 +1,33 @@
FROM alpine:3.6 # Build stage
RUN apk add --no-cache --virtual .build-deps alpine-sdk linux-headers openssl-dev \ FROM ubuntu:22.04 AS builder
&& 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 \ RUN apt-get update && apt-get install -y --no-install-recommends \
&& cd /mtproxy/sources && patch -p0 -i /mtproxy/patches/randr_compat.patch \ git \
&& make \ build-essential \
&& mkdir /root/.ssh \ libssl-dev \
&& cp /mtproxy/sources/objs/bin/mtproto-proxy /usr/bin \ zlib1g-dev \
&& rm -rf /mtproxy \ ca-certificates \
&& apk del .build-deps\ && rm -rf /var/lib/apt/lists/*
&& apk add --no-cache --update curl openssh \
&& ln -s /usr/lib/libcrypto.so.41 /usr/lib/libcrypto.so.1.0.0 WORKDIR /src
ENV ENV="/root/.ashrc" 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 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 \ && 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 \ && 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 update && apt install -y cloudflare-warp \ && apt-get update && apt-get install -y --no-install-recommends cloudflare-warp \
&& mkdir /root/.ssh && 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 docker compose exec oc /bin/sh
service: # консоль сервиса service: # консоль сервиса
docker compose exec service /bin/sh docker compose exec service /bin/sh
clean: delete:
docker image prune make d
docker builder prune docker system prune -f -a
cleanf: docker volume prune -f -a
docker image prune -f > /dev/null rm -rf /root/vpnbot
docker builder prune -f > /dev/null
cleanall:
docker image prune -a -f
docker builder prune -a -f
push: push:
docker compose push docker compose push
s: s:
-1
View File
@@ -1,5 +1,4 @@
cat /ssh/key.pub > /root/.ssh/authorized_keys cat /ssh/key.pub > /root/.ssh/authorized_keys
ssh-keygen -A ssh-keygen -A
exec /usr/sbin/sshd -D -e "$@" & exec /usr/sbin/sshd -D -e "$@" &
hysteria server -c /config/hysteria.yaml &
tail -f /dev/null tail -f /dev/null
-1
View File
@@ -1,4 +1,3 @@
echo 'root:dummy_passwd'|chpasswd
cat /ssh/key.pub > /root/.ssh/authorized_keys cat /ssh/key.pub > /root/.ssh/authorized_keys
ssh-keygen -A ssh-keygen -A
exec /usr/sbin/sshd -D -e "$@" & exec /usr/sbin/sshd -D -e "$@" &
+4 -2
View File
@@ -14,7 +14,8 @@ then
echo "ListenPort = $WG1PORT" >> /etc/wireguard/wg0.conf echo "ListenPort = $WG1PORT" >> /etc/wireguard/wg0.conf
else else
sed "s/ListenPort = [0-9]\+/ListenPort = $WG1PORT/" /etc/wireguard/wg0.conf > change_port 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 fi
else else
if [ $(cat /etc/wireguard/wg0.conf | wc -c) -eq 0 ] if [ $(cat /etc/wireguard/wg0.conf | wc -c) -eq 0 ]
@@ -26,7 +27,8 @@ else
echo "ListenPort = $WGPORT" >> /etc/wireguard/wg0.conf echo "ListenPort = $WGPORT" >> /etc/wireguard/wg0.conf
else else
sed "s/ListenPort = [0-9]\+/ListenPort = $WGPORT/" /etc/wireguard/wg0.conf > change_port 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
fi fi
iptables -t nat -A POSTROUTING --destination 10.10.0.5 -j ACCEPT iptables -t nat -A POSTROUTING --destination 10.10.0.5 -j ACCEPT
+17
View File
@@ -1,3 +1,20 @@
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 09.11.2025 v2.27
- фикс reality - фикс reality
08.11.2025 v2.26 08.11.2025 v2.26