diff --git a/app.py b/app.py index 39c08dc..709d290 100644 --- a/app.py +++ b/app.py @@ -103,7 +103,7 @@ else: application_path = os.path.dirname(__file__) DATA_FILE = os.path.join(application_path, 'data.json') # legacy JSON; used only for one-shot import / export -CURRENT_VERSION = "v3.1.1" +CURRENT_VERSION = "v3.1.2" RELEASES_REPO_URL = repo_url() RELEASES_API_LATEST = api_latest_url() BIN_DIR = os.environ.get('TUNNEL_BIN_DIR', os.path.join(application_path, 'bin')) diff --git a/managers/xray_manager.py b/managers/xray_manager.py index 550eb1a..a98b6b3 100644 --- a/managers/xray_manager.py +++ b/managers/xray_manager.py @@ -26,7 +26,7 @@ class XrayManager: PROTOCOL = 'xray' CONTAINER_NAME = 'amnezia-xray' IMAGE_NAME = 'amneziavpn/amnezia-xray' - DEFAULT_PORT = 443 + DEFAULT_PORT = 8443 def __init__(self, ssh_manager, protocol='xray'): self.ssh = ssh_manager @@ -298,13 +298,15 @@ chmod 644 {_q(self._cert_path())} {_q(self._key_path())} stream = (inbound or {}).get('streamSettings') or {} return str(stream.get('security') or '').lower() == 'reality' - def install_protocol(self, port=443, domain=None, email=None, site_name=None, + def install_protocol(self, port=8443, domain=None, email=None, site_name=None, acme_method='cloudflare', cloudflare_token=None): """Install VLESS + XHTTP + TLS (Let's Encrypt via Cloudflare DNS or HTTP-01).""" results = [] domain = self._validate_domain(domain or site_name) email = self._validate_email(email) port = int(port or self.DEFAULT_PORT) + if port < 1 or port > 65535: + raise ValueError('Port must be between 1 and 65535') method = (acme_method or 'cloudflare').strip().lower() if method in ('cf', 'dns', 'dns-01', 'cloudflare_dns'): method = 'cloudflare' diff --git a/templates/server.html b/templates/server.html index b10a181..1e27572 100644 --- a/templates/server.html +++ b/templates/server.html @@ -801,6 +801,21 @@
{{ _('xray_ports_warning_cf') }}
+
+ +
+ + +
+ +
{{ _('xray_port_hint') }}
+
@@ -2444,6 +2459,47 @@ return el ? el.value : 'cloudflare'; } + function getXrayPortMode() { + const el = document.querySelector('input[name="xrayPortMode"]:checked'); + return el ? el.value : 'custom'; + } + + function syncXrayPortToInstall() { + const portInput = document.getElementById('installPort'); + const xrPort = document.getElementById('installXrayPort'); + if (!portInput || !xrPort) return; + if (getXrayPortMode() === 'standard') { + portInput.value = '443'; + xrPort.value = '443'; + } else { + const v = parseInt(xrPort.value, 10); + portInput.value = (v >= 1 && v <= 65535) ? String(v) : '8443'; + } + } + + function updateXrayPortUi() { + const mode = getXrayPortMode(); + const xrPort = document.getElementById('installXrayPort'); + const hint = document.getElementById('xrayPortHint'); + if (xrPort) { + if (mode === 'standard') { + xrPort.value = '443'; + xrPort.disabled = true; + } else { + xrPort.disabled = false; + if (!xrPort.value || xrPort.value === '443') { + xrPort.value = currentInstallAnother + ? String(nextSuggestedPort(currentInstallProto, 8443)) + : '8443'; + } + } + } + if (hint) { + hint.textContent = mode === 'standard' ? _('xray_port_hint_standard') : _('xray_port_hint'); + } + syncXrayPortToInstall(); + } + function updateXrayAcmeUi() { const method = getXrayAcmeMethod(); const cfGroup = document.getElementById('xrayCfTokenGroup'); @@ -2451,10 +2507,6 @@ if (cfGroup) cfGroup.style.display = method === 'cloudflare' ? '' : 'none'; if (warn) warn.textContent = method === 'cloudflare' ? _('xray_ports_warning_cf') : _('xray_ports_warning'); updateXrayDnsHint(); - const portHint = document.getElementById('installPortHint'); - if (portHint && protoBase(currentInstallProto) === 'xray' && !currentInstallAnother) { - portHint.textContent = method === 'cloudflare' ? _('port_xray_hint_cf') : _('port_xray_hint'); - } } function updateXrayDnsHint() { @@ -2503,15 +2555,18 @@ portInput.disabled = true; portHint.textContent = _('dns_internal_hint'); } else if (base === 'xray') { - portLabel.textContent = _('port') + ' (TCP)'; + if (portGroup) portGroup.style.display = 'none'; portInput.disabled = false; - portInput.value = currentInstallAnother ? nextSuggestedPort(currentInstallProto, 443) : '443'; - portHint.textContent = currentInstallAnother ? _('port_next_instance_hint') : _('port_xray_hint'); if (xrayOpts) xrayOpts.style.display = 'block'; const xrDomain = document.getElementById('installXrayDomain'); const xrEmail = document.getElementById('installXrayEmail'); if (xrDomain && !xrDomain.value && SERVER_SSL_DOMAIN) xrDomain.value = SERVER_SSL_DOMAIN; if (xrEmail && !xrEmail.value && SERVER_SSL_EMAIL) xrEmail.value = SERVER_SSL_EMAIL; + const stdRadio = document.querySelector('input[name="xrayPortMode"][value="standard"]'); + const customRadio = document.querySelector('input[name="xrayPortMode"][value="custom"]'); + if (customRadio) customRadio.checked = true; + if (stdRadio) stdRadio.checked = false; + updateXrayPortUi(); updateXrayAcmeUi(); } else if (base === 'telemt') { portLabel.textContent = _('port') + ' (TCP)'; @@ -2599,10 +2654,16 @@ const xrEmail = (document.getElementById('installXrayEmail')?.value || '').trim(); const acme = getXrayAcmeMethod(); const cfToken = (document.getElementById('installXrayCfToken')?.value || '').trim(); + syncXrayPortToInstall(); + const xrPort = parseInt(document.getElementById('installPort')?.value, 10); if (!xrDomain || !xrEmail) { showToast(_('xray_domain') + ' / ' + _('xray_email'), 'error'); return; } + if (!(xrPort >= 1 && xrPort <= 65535)) { + showToast(_('xray_listen_port'), 'error'); + return; + } if (acme === 'cloudflare' && !cfToken) { showToast(_('xray_cf_token'), 'error'); return; @@ -2667,6 +2728,8 @@ params.hysteria_domain = document.getElementById('installHysteriaDomain').value.trim(); params.hysteria_email = document.getElementById('installHysteriaEmail').value.trim(); } else if (protoBase(currentInstallProto) === 'xray') { + syncXrayPortToInstall(); + params.port = document.getElementById('installPort').value; params.xray_domain = (document.getElementById('installXrayDomain')?.value || '').trim(); params.xray_email = (document.getElementById('installXrayEmail')?.value || '').trim(); params.xray_acme_method = getXrayAcmeMethod(); diff --git a/translations/en.json b/translations/en.json index 041779a..57e2c5d 100644 --- a/translations/en.json +++ b/translations/en.json @@ -82,15 +82,20 @@ "no_connections_desc": "Add your first connection to generate a VPN configuration", "install_protocol": "Install protocol", "port_default_hint": "Default port: 55424. Make sure it\u0027s not busy", - "port_xray_hint": "Default 443/TCP. Prefer Cloudflare DNS ACME — port 80 is not needed. Point domain A-record (DNS only / grey cloud) to this server.", - "port_xray_hint_cf": "Default 443/TCP. Certificate via Cloudflare DNS — port 80 is not used. Keep Cloudflare proxy off (grey cloud).", + "port_xray_hint": "Choose standard 443/TCP or any free custom TCP port. Prefer Cloudflare DNS ACME — port 80 is not needed.", + "port_xray_hint_cf": "Choose 443 or a custom TCP port. Certificate via Cloudflare DNS — port 80 is not used. Keep Cloudflare proxy off (grey cloud).", "xray_domain": "Domain", "xray_email": "Let\u0027s Encrypt email", "xray_dns_hint": "Create DNS record:", "xray_dns_hint_cf": "Domain must be on Cloudflare. A-record (DNS only):", - "xray_install_hint": "Installs VLESS + XHTTP + TLS (Xray-core). Prefer Cloudflare API token (DNS-01) so TCP 80 stays free.", - "xray_ports_warning": "TCP 80 must be free during install (Let\u0027s Encrypt HTTP-01). Reinstall replaces the previous Xray stack.", - "xray_ports_warning_cf": "Cloudflare DNS ACME does not use port 80. Token needs Zone → DNS → Edit. Keep proxy off (grey cloud). Reinstall replaces the previous Xray stack.", + "xray_install_hint": "Installs VLESS + XHTTP + TLS (Xray-core). Prefer Cloudflare API token (DNS-01) so TCP 80 stays free. Port 443 is optional.", + "xray_ports_warning": "TCP 80 must be free during install (Let\u0027s Encrypt HTTP-01). Listen port can be 443 or any free TCP port. Reinstall replaces the previous Xray stack.", + "xray_ports_warning_cf": "Cloudflare DNS ACME does not use port 80. Listen on 443 or any free TCP port. Token needs Zone → DNS → Edit. Keep proxy off (grey cloud).", + "xray_listen_port": "Listen port (TCP)", + "xray_port_standard": "Standard — 443/TCP", + "xray_port_custom": "Custom port", + "xray_port_hint": "Any free TCP port (default 8443). Open it in the firewall. Does not occupy 443.", + "xray_port_hint_standard": "Uses 443/TCP. Make sure nothing else is bound to 443 on this server.", "xray_acme_method": "Certificate method", "xray_acme_cloudflare": "Cloudflare DNS (API token) — recommended, no port 80", "xray_acme_http": "HTTP-01 — needs free TCP 80", diff --git a/translations/fa.json b/translations/fa.json index dbb059b..86d1f85 100644 --- a/translations/fa.json +++ b/translations/fa.json @@ -80,15 +80,20 @@ "no_connections_desc": "اولین اتصال خود را برای ایجاد پیکربندی VPN اضافه کنید", "install_protocol": "نصب پروتکل", "port_default_hint": "پورت پیش‌فرض: 55424. مطمئن شوید این پورت آزاد است.", - "port_xray_hint": "Default 443/TCP. Prefer Cloudflare DNS ACME — port 80 is not needed.", - "port_xray_hint_cf": "Default 443/TCP. Certificate via Cloudflare DNS — port 80 is not used.", + "port_xray_hint": "Choose standard 443/TCP or any free custom TCP port. Prefer Cloudflare DNS ACME — port 80 is not needed.", + "port_xray_hint_cf": "Choose 443 or a custom TCP port. Certificate via Cloudflare DNS — port 80 is not used.", "xray_domain": "Domain", "xray_email": "Let\u0027s Encrypt email", "xray_dns_hint": "Create DNS record:", "xray_dns_hint_cf": "Domain must be on Cloudflare. A-record (DNS only):", - "xray_install_hint": "Installs VLESS + XHTTP + TLS. Prefer Cloudflare API token (DNS-01) so TCP 80 stays free.", - "xray_ports_warning": "TCP 80 must be free during install (Let\u0027s Encrypt HTTP-01).", - "xray_ports_warning_cf": "Cloudflare DNS ACME does not use port 80. Token needs Zone → DNS → Edit. Keep proxy off (grey cloud).", + "xray_install_hint": "Installs VLESS + XHTTP + TLS. Prefer Cloudflare API token (DNS-01) so TCP 80 stays free. Port 443 is optional.", + "xray_ports_warning": "TCP 80 must be free during install (Let\u0027s Encrypt HTTP-01). Listen port can be 443 or any free TCP port.", + "xray_ports_warning_cf": "Cloudflare DNS ACME does not use port 80. Listen on 443 or any free TCP port. Token needs Zone → DNS → Edit. Keep proxy off (grey cloud).", + "xray_listen_port": "Listen port (TCP)", + "xray_port_standard": "Standard — 443/TCP", + "xray_port_custom": "Custom port", + "xray_port_hint": "Any free TCP port (default 8443). Open it in the firewall. Does not occupy 443.", + "xray_port_hint_standard": "Uses 443/TCP. Make sure nothing else is bound to 443 on this server.", "xray_acme_method": "Certificate method", "xray_acme_cloudflare": "Cloudflare DNS (API token) — recommended, no port 80", "xray_acme_http": "HTTP-01 — needs free TCP 80", diff --git a/translations/fr.json b/translations/fr.json index d124425..398c5e5 100644 --- a/translations/fr.json +++ b/translations/fr.json @@ -80,15 +80,20 @@ "no_connections_desc": "Ajoutez votre première connexion pour générer un fichier VPN", "install_protocol": "Installer le protocole", "port_default_hint": "Port par défaut : 55424. Assurez-vous qu\u0027il est libre.", - "port_xray_hint": "Default 443/TCP. Prefer Cloudflare DNS ACME — port 80 is not needed.", - "port_xray_hint_cf": "Default 443/TCP. Certificate via Cloudflare DNS — port 80 is not used.", + "port_xray_hint": "Choose standard 443/TCP or any free custom TCP port. Prefer Cloudflare DNS ACME — port 80 is not needed.", + "port_xray_hint_cf": "Choose 443 or a custom TCP port. Certificate via Cloudflare DNS — port 80 is not used.", "xray_domain": "Domain", "xray_email": "Let\u0027s Encrypt email", "xray_dns_hint": "Create DNS record:", "xray_dns_hint_cf": "Domain must be on Cloudflare. A-record (DNS only):", - "xray_install_hint": "Installs VLESS + XHTTP + TLS. Prefer Cloudflare API token (DNS-01) so TCP 80 stays free.", - "xray_ports_warning": "TCP 80 must be free during install (Let\u0027s Encrypt HTTP-01).", - "xray_ports_warning_cf": "Cloudflare DNS ACME does not use port 80. Token needs Zone → DNS → Edit. Keep proxy off (grey cloud).", + "xray_install_hint": "Installs VLESS + XHTTP + TLS. Prefer Cloudflare API token (DNS-01) so TCP 80 stays free. Port 443 is optional.", + "xray_ports_warning": "TCP 80 must be free during install (Let\u0027s Encrypt HTTP-01). Listen port can be 443 or any free TCP port.", + "xray_ports_warning_cf": "Cloudflare DNS ACME does not use port 80. Listen on 443 or any free TCP port. Token needs Zone → DNS → Edit. Keep proxy off (grey cloud).", + "xray_listen_port": "Listen port (TCP)", + "xray_port_standard": "Standard — 443/TCP", + "xray_port_custom": "Custom port", + "xray_port_hint": "Any free TCP port (default 8443). Open it in the firewall. Does not occupy 443.", + "xray_port_hint_standard": "Uses 443/TCP. Make sure nothing else is bound to 443 on this server.", "xray_acme_method": "Certificate method", "xray_acme_cloudflare": "Cloudflare DNS (API token) — recommended, no port 80", "xray_acme_http": "HTTP-01 — needs free TCP 80", diff --git a/translations/ru.json b/translations/ru.json index 0225cd2..52f7368 100644 --- a/translations/ru.json +++ b/translations/ru.json @@ -82,15 +82,20 @@ "no_connections_desc": "Добавьте первое подключение для генерации VPN конфигурации", "install_protocol": "Установить протокол", "port_default_hint": "Порт по умолчанию: 55424. Убедитесь, что он не занят", - "port_xray_hint": "По умолчанию 443/TCP. Лучше Cloudflare DNS ACME — порт 80 не нужен. A-запись домена (только DNS / серое облако) на этот сервер.", - "port_xray_hint_cf": "По умолчанию 443/TCP. Сертификат через Cloudflare DNS — порт 80 не используется. Прокси Cloudflare выключите (серое облако).", + "port_xray_hint": "Можно взять стандартный 443/TCP или любой свободный порт. Лучше Cloudflare DNS ACME — порт 80 не нужен.", + "port_xray_hint_cf": "443 или свой TCP-порт. Сертификат через Cloudflare DNS — порт 80 не используется. Прокси Cloudflare выключите (серое облако).", "xray_domain": "Домен", "xray_email": "Email для Let\u0027s Encrypt", "xray_dns_hint": "Создайте DNS-запись:", "xray_dns_hint_cf": "Домен должен быть в Cloudflare. A-запись (только DNS):", - "xray_install_hint": "Ставит VLESS + XHTTP + TLS (Xray-core). Рекомендуется токен Cloudflare (DNS-01) — TCP 80 не занимается.", - "xray_ports_warning": "На время установки TCP 80 должен быть свободен (Let\u0027s Encrypt HTTP-01). Переустановка заменяет предыдущий Xray.", - "xray_ports_warning_cf": "Cloudflare DNS ACME не использует порт 80. Токену нужно Zone → DNS → Edit. Прокси выключите (серое облако). Переустановка заменяет предыдущий Xray.", + "xray_install_hint": "Ставит VLESS + XHTTP + TLS (Xray-core). Рекомендуется токен Cloudflare (DNS-01) — TCP 80 не занимается. Порт 443 необязателен.", + "xray_ports_warning": "На время установки TCP 80 должен быть свободен (Let\u0027s Encrypt HTTP-01). Слушающий порт — 443 или любой свободный. Переустановка заменяет предыдущий Xray.", + "xray_ports_warning_cf": "Cloudflare DNS ACME не использует порт 80. Слушайте на 443 или любом свободном TCP. Токену нужно Zone → DNS → Edit. Прокси выключите (серое облако).", + "xray_listen_port": "Порт прослушивания (TCP)", + "xray_port_standard": "Стандартный — 443/TCP", + "xray_port_custom": "Свой порт", + "xray_port_hint": "Любой свободный TCP-порт (по умолчанию 8443). Откройте его в файрволе. Порт 443 не занимает.", + "xray_port_hint_standard": "Использует 443/TCP. Убедитесь, что 443 на сервере свободен.", "xray_acme_method": "Способ выпуска SSL", "xray_acme_cloudflare": "Cloudflare DNS (API-токен) — рекомендуется, без порта 80", "xray_acme_http": "HTTP-01 — нужен свободный TCP 80", diff --git a/translations/zh.json b/translations/zh.json index d43bf8f..fe396f2 100644 --- a/translations/zh.json +++ b/translations/zh.json @@ -80,15 +80,20 @@ "no_connections_desc": "添加首个连接以生成 VPN 配置文件", "install_protocol": "安装协议", "port_default_hint": "默认端口: 55424。请确保端口未被占用。", - "port_xray_hint": "Default 443/TCP. Prefer Cloudflare DNS ACME — port 80 is not needed.", - "port_xray_hint_cf": "Default 443/TCP. Certificate via Cloudflare DNS — port 80 is not used.", + "port_xray_hint": "Choose standard 443/TCP or any free custom TCP port. Prefer Cloudflare DNS ACME — port 80 is not needed.", + "port_xray_hint_cf": "Choose 443 or a custom TCP port. Certificate via Cloudflare DNS — port 80 is not used.", "xray_domain": "Domain", "xray_email": "Let\u0027s Encrypt email", "xray_dns_hint": "Create DNS record:", "xray_dns_hint_cf": "Domain must be on Cloudflare. A-record (DNS only):", - "xray_install_hint": "Installs VLESS + XHTTP + TLS. Prefer Cloudflare API token (DNS-01) so TCP 80 stays free.", - "xray_ports_warning": "TCP 80 must be free during install (Let\u0027s Encrypt HTTP-01).", - "xray_ports_warning_cf": "Cloudflare DNS ACME does not use port 80. Token needs Zone → DNS → Edit. Keep proxy off (grey cloud).", + "xray_install_hint": "Installs VLESS + XHTTP + TLS. Prefer Cloudflare API token (DNS-01) so TCP 80 stays free. Port 443 is optional.", + "xray_ports_warning": "TCP 80 must be free during install (Let\u0027s Encrypt HTTP-01). Listen port can be 443 or any free TCP port.", + "xray_ports_warning_cf": "Cloudflare DNS ACME does not use port 80. Listen on 443 or any free TCP port. Token needs Zone → DNS → Edit. Keep proxy off (grey cloud).", + "xray_listen_port": "Listen port (TCP)", + "xray_port_standard": "Standard — 443/TCP", + "xray_port_custom": "Custom port", + "xray_port_hint": "Any free TCP port (default 8443). Open it in the firewall. Does not occupy 443.", + "xray_port_hint_standard": "Uses 443/TCP. Make sure nothing else is bound to 443 on this server.", "xray_acme_method": "Certificate method", "xray_acme_cloudflare": "Cloudflare DNS (API token) — recommended, no port 80", "xray_acme_http": "HTTP-01 — needs free TCP 80",