new changes

This commit is contained in:
Niranjan
2026-04-07 12:00:10 +05:30
parent f1b0a88dff
commit df015e4d5a
3 changed files with 71 additions and 3 deletions

View File

@@ -2,6 +2,7 @@
import os import os
import re import re
import shutil import shutil
import socket
import subprocess import subprocess
import sys import sys
from fastapi import APIRouter, Depends, HTTPException from fastapi import APIRouter, Depends, HTTPException
@@ -12,7 +13,7 @@ from typing import Optional
from app.core.database import get_db from app.core.database import get_db
from app.core.config import get_runtime_config from app.core.config import get_runtime_config
from app.core.utils import environment_with_system_path, read_file, nginx_reload_all_known, nginx_binary_candidates from app.core.utils import environment_with_system_path, exec_shell_sync, read_file, nginx_reload_all_known, nginx_binary_candidates
from app.api.auth import get_current_user from app.api.auth import get_current_user
from app.models.user import User from app.models.user import User
from app.models.site import Site, Domain from app.models.site import Site, Domain
@@ -125,6 +126,23 @@ def _reload_panel_and_common_nginx() -> tuple[bool, str]:
return nginx_reload_all_known(timeout=60) return nginx_reload_all_known(timeout=60)
def _localhost_accepts_tcp(port: int, timeout: float = 2.0) -> bool:
"""True if something accepts a TCP connection on this machine (checks IPv4 loopback)."""
try:
with socket.create_connection(("127.0.0.1", port), timeout=timeout):
return True
except OSError:
return False
def _ss_reports_listen_443() -> bool | None:
"""Parse ss/netstat output; None if the probe could not run."""
out, _ = exec_shell_sync("ss -tln 2>/dev/null || netstat -tln 2>/dev/null", timeout=5)
if not out or not out.strip():
return None
return bool(re.search(r":443\b", out))
@router.get("/domains") @router.get("/domains")
async def ssl_domains( async def ssl_domains(
current_user: User = Depends(get_current_user), current_user: User = Depends(get_current_user),
@@ -362,9 +380,27 @@ async def ssl_diagnostics(current_user: User = Depends(get_current_user)):
"Add the include below (or symlink this directory into /etc/nginx/conf.d/)." "Add the include below (or symlink this directory into /etc/nginx/conf.d/)."
) )
if effective_listen_443: localhost_443_open = _localhost_accepts_tcp(443)
ss_443 = _ss_reports_listen_443()
if not localhost_443_open and not effective_listen_443:
hints.append( hints.append(
"Loaded nginx configuration includes a 443 listener. If HTTPS still fails, open TCP port 443 on the OS firewall and cloud/VPS security group." "This server is not accepting TCP on 127.0.0.1:443 — nothing is listening on 443 yet. "
"Fix nginx (listen 443 ssl + include panel vhosts) first; opening only the cloud firewall will not fix ERR_CONNECTION_REFUSED until nginx binds 443."
)
elif effective_listen_443 and localhost_443_open:
hints.append(
"Nginx loads HTTPS and 127.0.0.1:443 accepts connections on this host. "
"If browsers off this machine still see connection refused, allow inbound TCP 443: "
"sudo ufw allow 443/tcp && sudo ufw reload (or firewalld), and your VPS Security Group / provider firewall."
)
elif effective_listen_443 and not localhost_443_open:
hints.append(
"nginx -T reports listen 443, but connecting to 127.0.0.1:443 failed — check nginx error.log; nginx may have failed to bind (permission or address already in use)."
)
elif localhost_443_open and not effective_listen_443:
hints.append(
"127.0.0.1:443 accepts TCP, but nginx -T from panel binaries did not show listen 443 — another process may own 443; check ss -tlnp and which nginx serves port 80."
) )
return { return {
@@ -375,6 +411,8 @@ async def ssl_diagnostics(current_user: User = Depends(get_current_user)):
"nginx_effective_listen_443": effective_listen_443, "nginx_effective_listen_443": effective_listen_443,
"panel_vhost_path_in_nginx_t": panel_include_in_effective_config, "panel_vhost_path_in_nginx_t": panel_include_in_effective_config,
"nginx_t_probe_errors": nginx_t_errors, "nginx_t_probe_errors": nginx_t_errors,
"localhost_443_accepts_tcp": localhost_443_open,
"ss_reports_443_listen": ss_443,
"hints": hints, "hints": hints,
} }

View File

@@ -25,6 +25,10 @@ interface SslDiagnostics {
nginx_effective_listen_443: boolean nginx_effective_listen_443: boolean
panel_vhost_path_in_nginx_t: boolean panel_vhost_path_in_nginx_t: boolean
nginx_t_probe_errors: string[] nginx_t_probe_errors: string[]
/** Something accepted TCP when connecting to 127.0.0.1:443 from the panel process */
localhost_443_accepts_tcp: boolean
/** ss/netstat reported :443 in listen table, or null if probe unavailable */
ss_reports_443_listen: boolean | null
hints: string[] hints: string[]
} }
@@ -114,6 +118,32 @@ export function DomainsPage() {
) : null} ) : null}
<div className="text-secondary mb-1">Include YakPanel vhosts inside the <code>http</code> block of the nginx process that serves your sites:</div> <div className="text-secondary mb-1">Include YakPanel vhosts inside the <code>http</code> block of the nginx process that serves your sites:</div>
<code className="d-block user-select-all bg-body-secondary p-2 rounded small text-break">{diag.include_snippet}</code> <code className="d-block user-select-all bg-body-secondary p-2 rounded small text-break">{diag.include_snippet}</code>
<div className="mt-3 small">
<strong>Port 443 on this machine</strong>
<ul className="mb-0 ps-3 mt-1">
<li>
Localhost TCP (127.0.0.1:443):{' '}
{diag.localhost_443_accepts_tcp ? (
<span className="text-success">accepting connections</span>
) : (
<span className="text-danger">refused / nothing listening</span>
)}
</li>
<li>
Kernel listen table (ss):{' '}
{diag.ss_reports_443_listen === null ? (
<span className="text-secondary">not checked</span>
) : diag.ss_reports_443_listen ? (
<span className="text-success">443 in LISTEN</span>
) : (
<span className="text-danger">no 443 in LISTEN</span>
)}
</li>
</ul>
<p className="text-secondary mt-2 mb-0">
The panel cannot see your cloud provider firewall. If localhost shows open but browsers off-network fail, open TCP 443 in the VPS control panel (security group) and OS firewall.
</p>
</div>
{diag.vhosts.length > 0 ? ( {diag.vhosts.length > 0 ? (
<div className="mt-2 text-secondary"> <div className="mt-2 text-secondary">
Panel configs scanned:{' '} Panel configs scanned:{' '}