mirror of
https://github.com/anten-ka/gotelegram_pro.git
synced 2026-05-19 17:56:07 +00:00
v2.5.0: add shared 443 and per-user traffic
This commit is contained in:
248
lib/shared443.sh
Normal file
248
lib/shared443.sh
Normal file
@@ -0,0 +1,248 @@
|
||||
#!/bin/bash
|
||||
# goTelegram Pro v2.5.0 — shared TCP/443 dispatcher helpers
|
||||
|
||||
SHARED443_CONFIG="${SHARED443_CONFIG:-/opt/gotelegram/shared-443.json}"
|
||||
SHARED443_STREAM_CONF="${SHARED443_STREAM_CONF:-/etc/nginx/stream-conf.d/gotelegram-shared443.conf}"
|
||||
SHARED443_TELEMT_PORT="${SHARED443_TELEMT_PORT:-7443}"
|
||||
SHARED443_PUBLIC_PORT="${SHARED443_PUBLIC_PORT:-443}"
|
||||
|
||||
SHARED443_LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
type log_error >/dev/null 2>&1 || source "$SHARED443_LIB_DIR/common.sh"
|
||||
type install_nginx >/dev/null 2>&1 || source "$SHARED443_LIB_DIR/website.sh"
|
||||
|
||||
shared443_detect_nginx_stream() {
|
||||
nginx -V 2>&1 | grep -Eq -- '--with-stream|ngx_stream_module|ngx_stream_ssl_preread_module'
|
||||
}
|
||||
|
||||
shared443_install_stream_module() {
|
||||
if shared443_detect_nginx_stream; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
case "$(get_pkg_manager 2>/dev/null || echo unknown)" in
|
||||
apt)
|
||||
apt_update >/dev/null 2>&1 || true
|
||||
apt_install libnginx-mod-stream || return 1
|
||||
;;
|
||||
dnf|yum)
|
||||
install_pkg nginx-mod-stream || true
|
||||
;;
|
||||
esac
|
||||
|
||||
shared443_detect_nginx_stream
|
||||
}
|
||||
|
||||
shared443_ensure_nginx_include() {
|
||||
mkdir -p /etc/nginx/stream-conf.d
|
||||
if nginx -T 2>/dev/null | grep -q '/etc/nginx/stream-conf.d/\*.conf'; then
|
||||
return 0
|
||||
fi
|
||||
if grep -Eq '^[[:space:]]*stream[[:space:]]*\{' /etc/nginx/nginx.conf 2>/dev/null; then
|
||||
log_warning "В nginx уже есть stream-блок, но нет include /etc/nginx/stream-conf.d/*.conf"
|
||||
log_dim "Добавьте include вручную или перенесите $SHARED443_STREAM_CONF в существующий stream-блок."
|
||||
return 1
|
||||
fi
|
||||
|
||||
cp /etc/nginx/nginx.conf "/etc/nginx/nginx.conf.gotelegram.$(date +%Y%m%d_%H%M%S).bak" 2>/dev/null || true
|
||||
cat >> /etc/nginx/nginx.conf <<'EOF'
|
||||
|
||||
# goTelegram Pro shared TCP/443 routes
|
||||
stream {
|
||||
include /etc/nginx/stream-conf.d/*.conf;
|
||||
}
|
||||
EOF
|
||||
}
|
||||
|
||||
shared443_rewrite_telemt_bind() {
|
||||
local listen_port="${1:-$SHARED443_TELEMT_PORT}"
|
||||
local public_port="${2:-$SHARED443_PUBLIC_PORT}"
|
||||
local listen_addr="${3:-127.0.0.1}"
|
||||
|
||||
command -v python3 >/dev/null 2>&1 || {
|
||||
log_error "python3 нужен для безопасного изменения $TELEMT_CONFIG"
|
||||
return 1
|
||||
}
|
||||
|
||||
python3 - "$TELEMT_CONFIG" "$listen_port" "$public_port" "$listen_addr" <<'PY'
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
path = Path(sys.argv[1])
|
||||
listen_port = sys.argv[2]
|
||||
public_port = sys.argv[3]
|
||||
listen_addr = sys.argv[4]
|
||||
lines = path.read_text(encoding="utf-8", errors="ignore").splitlines() if path.exists() else []
|
||||
out = []
|
||||
section = ""
|
||||
server_seen = False
|
||||
server_port_seen = False
|
||||
server_addr_seen = False
|
||||
links_seen = False
|
||||
public_seen = False
|
||||
|
||||
def flush_section(next_line=None):
|
||||
global section, server_port_seen, server_addr_seen, public_seen
|
||||
if section == "server":
|
||||
if not server_port_seen:
|
||||
out.append(f"port = {listen_port}")
|
||||
if not server_addr_seen:
|
||||
out.append(f'listen_addr_ipv4 = "{listen_addr}"')
|
||||
if section == "general.links" and not public_seen:
|
||||
out.append(f"public_port = {public_port}")
|
||||
if next_line is not None:
|
||||
out.append(next_line)
|
||||
|
||||
for raw in lines:
|
||||
stripped = raw.strip()
|
||||
if stripped.startswith("[") and stripped.endswith("]"):
|
||||
flush_section(raw)
|
||||
section = stripped.strip("[]")
|
||||
if section == "server":
|
||||
server_seen = True
|
||||
server_port_seen = False
|
||||
server_addr_seen = False
|
||||
elif section == "general.links":
|
||||
links_seen = True
|
||||
public_seen = False
|
||||
continue
|
||||
|
||||
if section == "server" and stripped.startswith("port") and "=" in stripped:
|
||||
out.append(f"port = {listen_port}")
|
||||
server_port_seen = True
|
||||
continue
|
||||
if section == "server" and stripped.startswith("listen_addr_ipv4") and "=" in stripped:
|
||||
out.append(f'listen_addr_ipv4 = "{listen_addr}"')
|
||||
server_addr_seen = True
|
||||
continue
|
||||
if section == "general.links" and stripped.startswith("public_port") and "=" in stripped:
|
||||
out.append(f"public_port = {public_port}")
|
||||
public_seen = True
|
||||
continue
|
||||
out.append(raw)
|
||||
|
||||
flush_section()
|
||||
if not links_seen:
|
||||
if out and out[-1].strip():
|
||||
out.append("")
|
||||
out.extend(["[general.links]", f"public_port = {public_port}"])
|
||||
if not server_seen:
|
||||
if out and out[-1].strip():
|
||||
out.append("")
|
||||
out.extend(["[server]", f"port = {listen_port}", f'listen_addr_ipv4 = "{listen_addr}"'])
|
||||
|
||||
tmp = path.with_suffix(path.suffix + ".tmp")
|
||||
tmp.write_text("\n".join(out).rstrip() + "\n", encoding="utf-8")
|
||||
tmp.chmod(0o600)
|
||||
tmp.replace(path)
|
||||
PY
|
||||
}
|
||||
|
||||
shared443_write_stream_config() {
|
||||
local domain="$1"
|
||||
local xray_domain="${2:-}"
|
||||
local xray_target="${3:-}"
|
||||
local telemt_target="${4:-127.0.0.1:${SHARED443_TELEMT_PORT}}"
|
||||
|
||||
mkdir -p "$(dirname "$SHARED443_STREAM_CONF")"
|
||||
{
|
||||
echo "# goTelegram Pro shared TCP/443 dispatcher"
|
||||
echo "# Browser/Telegram for goTelegram domain goes to telemt; telemt masks the site to nginx."
|
||||
echo "map \$ssl_preread_server_name \$gotelegram_shared443_backend {"
|
||||
echo " hostnames;"
|
||||
if [[ -n "$xray_domain" && -n "$xray_target" ]]; then
|
||||
echo " ${xray_domain} ${xray_target};"
|
||||
fi
|
||||
echo " default ${telemt_target};"
|
||||
echo "}"
|
||||
echo ""
|
||||
echo "server {"
|
||||
echo " listen 0.0.0.0:${SHARED443_PUBLIC_PORT};"
|
||||
echo " proxy_pass \$gotelegram_shared443_backend;"
|
||||
echo " ssl_preread on;"
|
||||
echo " proxy_connect_timeout 5s;"
|
||||
echo " proxy_timeout 10m;"
|
||||
echo "}"
|
||||
} > "$SHARED443_STREAM_CONF"
|
||||
|
||||
mkdir -p "$(dirname "$SHARED443_CONFIG")"
|
||||
if command -v jq >/dev/null 2>&1; then
|
||||
jq -n \
|
||||
--arg domain "$domain" \
|
||||
--arg telemt "$telemt_target" \
|
||||
--arg xdomain "$xray_domain" \
|
||||
--arg xtarget "$xray_target" \
|
||||
--arg updated "$(date -Iseconds)" \
|
||||
--argjson public_port "$SHARED443_PUBLIC_PORT" \
|
||||
'{
|
||||
enabled: true,
|
||||
dispatcher: "nginx-stream",
|
||||
public_port: $public_port,
|
||||
domain: $domain,
|
||||
telemt_target: $telemt,
|
||||
site_target: "127.0.0.1:8443",
|
||||
xray_routes: (if ($xdomain != "" and $xtarget != "") then [{public: ($xdomain + ":443"), target: $xtarget}] else [] end),
|
||||
updated_at: $updated
|
||||
}' > "$SHARED443_CONFIG"
|
||||
else
|
||||
cat > "$SHARED443_CONFIG" <<EOF
|
||||
{"enabled":true,"dispatcher":"nginx-stream","public_port":${SHARED443_PUBLIC_PORT},"domain":"${domain}","telemt_target":"${telemt_target}","site_target":"127.0.0.1:8443","xray_routes":[],"updated_at":"$(date -Iseconds)"}
|
||||
EOF
|
||||
fi
|
||||
chmod 600 "$SHARED443_CONFIG" 2>/dev/null || true
|
||||
}
|
||||
|
||||
shared443_enable() {
|
||||
local domain="$1"
|
||||
local xray_domain="${2:-}"
|
||||
local xray_target="${3:-}"
|
||||
local telemt_target="127.0.0.1:${SHARED443_TELEMT_PORT}"
|
||||
|
||||
[[ -n "$domain" ]] || domain="$(config_get domain 2>/dev/null || echo "")"
|
||||
[[ -n "$domain" ]] || {
|
||||
log_error "Не указан домен goTelegram Pro для shared-443"
|
||||
return 1
|
||||
}
|
||||
|
||||
install_nginx || return 1
|
||||
shared443_install_stream_module || {
|
||||
log_error "nginx stream/ssl_preread недоступен"
|
||||
return 1
|
||||
}
|
||||
shared443_ensure_nginx_include || return 1
|
||||
|
||||
shared443_rewrite_telemt_bind "$SHARED443_TELEMT_PORT" "$SHARED443_PUBLIC_PORT" "127.0.0.1" || return 1
|
||||
systemctl restart "$TELEMT_SERVICE" 2>/dev/null || true
|
||||
|
||||
shared443_write_stream_config "$domain" "$xray_domain" "$xray_target" "$telemt_target"
|
||||
if nginx -t 2>/dev/null; then
|
||||
systemctl restart nginx
|
||||
log_success "shared-443 включён: 0.0.0.0:${SHARED443_PUBLIC_PORT} -> nginx stream -> telemt ${telemt_target}"
|
||||
if [[ -n "$xray_domain" && -n "$xray_target" ]]; then
|
||||
log_success "Xray route: ${xray_domain}:443 -> ${xray_target}"
|
||||
fi
|
||||
else
|
||||
log_error "nginx -t не прошёл после настройки shared-443"
|
||||
nginx -t
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
shared443_detect_direct_conflict() {
|
||||
ss -ltnp 2>/dev/null | grep -E '(:|])443[[:space:]]' | grep -Eiv '(nginx|telemt)' || true
|
||||
}
|
||||
|
||||
shared443_status() {
|
||||
echo "shared-443 config: $SHARED443_CONFIG"
|
||||
[ -f "$SHARED443_CONFIG" ] && cat "$SHARED443_CONFIG" || echo "not enabled"
|
||||
local conflict
|
||||
conflict="$(shared443_detect_direct_conflict)"
|
||||
if [[ -n "$conflict" ]]; then
|
||||
echo ""
|
||||
echo "direct 443 listeners that need migration behind dispatcher:"
|
||||
echo "$conflict"
|
||||
fi
|
||||
}
|
||||
|
||||
export -f shared443_detect_nginx_stream shared443_install_stream_module shared443_ensure_nginx_include
|
||||
export -f shared443_rewrite_telemt_bind shared443_write_stream_config shared443_enable
|
||||
export -f shared443_detect_direct_conflict shared443_status
|
||||
Reference in New Issue
Block a user