From 10236a4cd4a90d552625261cab0adc3b12d5fbc9 Mon Sep 17 00:00:00 2001 From: Niranjan Date: Tue, 7 Apr 2026 11:42:19 +0530 Subject: [PATCH] new changes --- .../app/api/__pycache__/files.cpython-314.pyc | Bin 15756 -> 37512 bytes .../app/api/__pycache__/logs.cpython-314.pyc | Bin 5060 -> 5060 bytes .../app/api/__pycache__/site.cpython-314.pyc | Bin 26341 -> 28211 bytes .../app/api/__pycache__/ssl.cpython-314.pyc | Bin 17355 -> 23297 bytes YakPanel-server/backend/app/api/ssl.py | 143 ++++++++++++++--- .../core/__pycache__/utils.cpython-314.pyc | Bin 8927 -> 13656 bytes YakPanel-server/backend/app/core/utils.py | 83 ++++++++++ .../config_service.cpython-314.pyc | Bin 0 -> 3732 bytes .../__pycache__/site_service.cpython-314.pyc | Bin 38423 -> 43479 bytes .../backend/app/services/site_service.py | 146 ++++++++++++++---- .../__pycache__/__init__.cpython-314.pyc | Bin 0 -> 269 bytes .../__pycache__/celery_app.cpython-314.pyc | Bin 0 -> 746 bytes .../tasks/__pycache__/install.cpython-314.pyc | Bin 0 -> 2137 bytes .../frontend/src/pages/DomainsPage.tsx | 40 +++++ 14 files changed, 360 insertions(+), 52 deletions(-) create mode 100644 YakPanel-server/backend/app/services/__pycache__/config_service.cpython-314.pyc create mode 100644 YakPanel-server/backend/app/tasks/__pycache__/__init__.cpython-314.pyc create mode 100644 YakPanel-server/backend/app/tasks/__pycache__/celery_app.cpython-314.pyc create mode 100644 YakPanel-server/backend/app/tasks/__pycache__/install.cpython-314.pyc diff --git a/YakPanel-server/backend/app/api/__pycache__/files.cpython-314.pyc b/YakPanel-server/backend/app/api/__pycache__/files.cpython-314.pyc index b0cf38e5ac27d69893d749bb82619a9dd085f8b2..7d1ff311400cea5b89251efcb298b429a908a7e1 100644 GIT binary patch literal 37512 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

i(E@KWtw|zj*qK(`n_gwDJk-aO;f4G4jNe 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
?yvsuT&Q`mT*@cW~8sCyBe1ZSC>=%)e=XOMYvj- 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 X)cl!AK0gT{$vdcE!LJOe=;QwYcmgN= delta 5680 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 diff --git a/YakPanel-server/backend/app/api/__pycache__/logs.cpython-314.pyc b/YakPanel-server/backend/app/api/__pycache__/logs.cpython-314.pyc index cd885d1c4ad507309b68fa42339b8a36466af63f..a846d498433c51f4f014ec16c2b75ecd74250f49 100644 GIT binary patch delta 213 zcmX@2eng#Hn~#@^0SI2WUfIYk&&u?2!ekxRmyDW|#n?_V%5HwZHjP=LNF1o3ir+84 zL?KZjC9^0sxg@`+vPfcbAD4ujEKsh9A4uF{%`8dHE!N~K(gX>yfC#zCN4OLjl_x*r zvS!l;321Cq=Qd+v)ZQG&dzOh&VzQ2ant&ouLX+_pTWV2Jeo=9e_~ax3LvCa<<_UO- hD}xlVfh{U>1epXi?!Q0{Bct5p8lhUCn|}$N0s!&oG?D-S delta 213 zcmX@2eng#Hn~#@^0SKm?y}XfIo|P$c;$$7xmy8;d#n?_V%4~kXHjP>0w!i*zO@2^exCn=wzo iOI!)0hz)E}kt4_?sB!-VY8V-1C)Wto0^R&e=oA229W^-s diff --git a/YakPanel-server/backend/app/api/__pycache__/site.cpython-314.pyc b/YakPanel-server/backend/app/api/__pycache__/site.cpython-314.pyc index 08a1d1c11bb106351aae5db6e20c4cca514a009a..cb856c85483b683cf9a452cd8a9c138fc2f6ea16 100644 GIT binary patch delta 4786 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 F None: +def _reload_panel_and_common_nginx() -> tuple[bool, str]: """Reload nginx so new vhost (ACME path) is live before certbot HTTP-01.""" - cfg = get_runtime_config() - seen: set[str] = set() - binaries: list[str] = [] - panel_ngx = os.path.join(cfg.get("setup_path") or "", "nginx", "sbin", "nginx") - if os.path.isfile(panel_ngx): - binaries.append(panel_ngx) - seen.add(os.path.realpath(panel_ngx)) - for alt in ("/usr/sbin/nginx", "/usr/bin/nginx", "/usr/local/nginx/sbin/nginx"): - if not os.path.isfile(alt): - continue - rp = os.path.realpath(alt) - if rp in seen: - continue - binaries.append(alt) - seen.add(rp) - for ngx in binaries: - exec_shell_sync(f'"{ngx}" -t && "{ngx}" -s reload', timeout=60) + return nginx_reload_all_known(timeout=60) @router.get("/domains") @@ -199,7 +183,12 @@ async def ssl_request_cert( status_code=500, detail="Cannot refresh nginx vhost before certificate request: " + str(regen_pre.get("msg", "")), ) - _reload_panel_and_common_nginx() + ok_ngx, err_ngx = _reload_panel_and_common_nginx() + if not ok_ngx: + raise HTTPException( + status_code=500, + detail="Nginx test/reload failed before certificate request (fix config, then retry): " + err_ngx, + ) challenge_dir = os.path.join(webroot_norm, ".well-known", "acme-challenge") try: @@ -278,6 +267,118 @@ async def ssl_request_cert( } +@router.get("/diagnostics") +async def ssl_diagnostics(current_user: User = Depends(get_current_user)): + """ + Help debug HTTP vs HTTPS: compares panel-written vhosts with what nginx -T actually loads. + ERR_CONNECTION_REFUSED on 443 usually means no listen 443 in the active nginx, or a firewall. + """ + cfg = get_runtime_config() + setup_abs = os.path.abspath((cfg.get("setup_path") or "").strip() or ".") + vhost_dir = os.path.join(setup_abs, "panel", "vhost", "nginx") + include_snippet = "include " + vhost_dir.replace(os.sep, "/") + "/*.conf;" + + vhost_summaries: list[dict] = [] + if os.path.isdir(vhost_dir): + try: + names = sorted(os.listdir(vhost_dir)) + except OSError: + names = [] + for fn in names: + if not fn.endswith(".conf") or fn.startswith("."): + continue + fp = os.path.join(vhost_dir, fn) + if not os.path.isfile(fp): + continue + body = read_file(fp) or "" + vhost_summaries.append({ + "file": fn, + "has_listen_80": bool(re.search(r"\blisten\s+80\b", body)), + "has_listen_443": bool(re.search(r"\blisten\s+.*443", body)), + "has_ssl_directives": "ssl_certificate" in body, + }) + + any_vhost_443 = any( + v.get("has_listen_443") and v.get("has_ssl_directives") for v in vhost_summaries + ) + effective_listen_443 = False + panel_include_in_effective_config = False + nginx_t_errors: list[str] = [] + norm_vhost = vhost_dir.replace(os.sep, "/") + env = environment_with_system_path() + + for ngx in nginx_binary_candidates(): + try: + r = subprocess.run( + [ngx, "-T"], + capture_output=True, + text=True, + timeout=25, + env=env, + ) + except (FileNotFoundError, OSError, subprocess.TimeoutExpired) as e: + nginx_t_errors.append(f"{ngx}: {e}") + continue + dump = (r.stdout or "") + (r.stderr or "") + if r.returncode != 0: + nginx_t_errors.append(f"{ngx}: " + (dump.strip()[:800] or f"-T exit {r.returncode}")) + continue + if re.search(r"\blisten\s+.*443", dump): + effective_listen_443 = True + if norm_vhost in dump or "panel/vhost/nginx" in dump: + panel_include_in_effective_config = True + + hints: list[str] = [] + if not os.path.isdir(vhost_dir): + hints.append(f"The panel vhost directory is missing ({vhost_dir}). Create a website in YakPanel first.") + elif not vhost_summaries: + hints.append("There are no .conf files under the panel nginx vhost directory.") + + le_live = "/etc/letsencrypt/live" + le_present = False + if os.path.isdir(le_live): + try: + le_present = any( + n and not n.startswith(".") + for n in os.listdir(le_live) + ) + except OSError: + le_present = False + + if le_present and vhost_summaries and not any_vhost_443: + hints.append( + "Let's Encrypt certs exist on this server but panel vhosts do not include an HTTPS (listen 443 ssl) block. " + "Regenerate the vhost: edit the site and save, or use Request SSL again." + ) + + if any_vhost_443 and not effective_listen_443: + hints.append( + "Your panel .conf files define HTTPS, but nginx -T does not show any listen 443 — the daemon that handles traffic is not loading YakPanel vhosts. " + "Add the include line below inside http { } for that nginx (e.g. /etc/nginx/nginx.conf), then nginx -t && reload." + ) + elif vhost_summaries and not panel_include_in_effective_config: + hints.append( + "If http://domain shows the default 'Welcome to nginx' page, stock nginx is answering and likely does not include YakPanel vhosts. " + "Add the include below (or symlink this directory into /etc/nginx/conf.d/)." + ) + + if effective_listen_443: + 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." + ) + + return { + "vhost_dir": vhost_dir, + "include_snippet": include_snippet, + "vhosts": vhost_summaries, + "any_vhost_listen_ssl": any_vhost_443, + "nginx_effective_listen_443": effective_listen_443, + "panel_vhost_path_in_nginx_t": panel_include_in_effective_config, + "nginx_t_probe_errors": nginx_t_errors, + "hints": hints, + } + + @router.get("/certificates") async def ssl_list_certificates(current_user: User = Depends(get_current_user)): """List existing Let's Encrypt certificates""" diff --git a/YakPanel-server/backend/app/core/__pycache__/utils.cpython-314.pyc b/YakPanel-server/backend/app/core/__pycache__/utils.cpython-314.pyc index ee5fcc94dc63724a82abf3e187802d3b2829674b..0e15d6a90e25768af50d35846e92680fb5b0865d 100644 GIT binary patch delta 4453 zcmb_fZ){uD6~FI2|Ids6+i{b)eo5LS29lJfEuo>MEp;d=3gOi_L-KGP`^9nV*ycV5 zw^8Xc+MgzDB8?tX(~T|pP(&+DS`la&J#;%Y-~F=W<@HU7H#DJ? zHAUsjyb&Z5k#ZJ(JKq2jTd`SrAKwVFxgy(m3rJSQ*Uodi4J3QT=HT0S2guHf>;%~b zvb!R?_;$VtWX}T?g`3|7Vl$C)O<-&RskLJB@Kgu#cf8Y1Jx(2d_KE%Bd_IpenOyj6 z^mI0w7E-;j%w+ia=;;w6^h`#@oPf7vQNS;OJQj_e7Si$XJ7e??4|Pqx(EK;5@J_zv z15H;J&IMb63}Xz`Z^TpZC^L8}jlIN{BIKO>JolLHJYgmIXPlp!m6y3Y^7k4K$iH$M z%{&vqN(IDeRN$UR)v@WLf?SlH*>8JUrGRKPZF&HKjaYodi*1zsHI(| za(ISlBp_u9i{w6cc5-Ck2BLGRz>^ciTqK%~OA&QH_$Oez0RQ3{cnb>XFAdH&jx0WT z`N_rM%fnY6U2EO@Y3tsSrD?{pZt7eybr+u4pp9DZI_sVres#Fi=w8qiS#PPuSF*WE z&X$tZvDu(&G|f;Oc4RPKIQPoAi!ZL~Jtd2E?#%3&HH*J!@h?2QI3QgfP=zJDX5Mwf zylch0dxj}loEKwj?t?}6^YvY)-eccpubwY@4;C#4i-v>$5qe>w$aekj!6CM!WOA?I zfucK5^zFO;;(O=bK6gD`^ahHSK+zB=H8={-{C#sLYTW)t{+Fh;?!z~_4;LGbY$8hQ zg~VTvEwstwGcSK;XuY$+fbPy_^Zk7jcR7D84#JP{fj2;*4-ae)45DR<3k)#JZET>Q zS?-|-->)TfkQ>^~eB8ng^)MfIQH1Z&0*#SNT)D^u^p*cx`{ggG9=Y4gHusU*Nh?K2 zEjn~rlS+y?Y?KcBFa`lwr4!pT05 zR&L+scwlRpDy~6M(pk|^4(g<~egU%61NTZ>Tb)@=I{~NLijF^kNcp<^tRScqs!hr2 zM#mn7eB$a99^G%ZwHfdu-E*%YT{R6KI{p$uMzkH)Qc6y(kV7GHL27$R-M;4{TP4MZ zyy)ql)|C*qJa2bM+N=)r(W>6BpB@_~eGvzJQ4}Wyk;`ScOjf|roWNz$`#Gh(>lp*I zOaUN|C$X4&NUa0V@=a#aoOl+Ry-D!PO#uAIh4@q!9LLT=afqgf*5B)=%Jzhii{L3K zol8y%kys`@o=lWYBEW1mLY$Q9P}V9?S=NY}SiCXf_L-DHec`fcUZk(hP*HD;1hk8R!Y^@FU_mAY~oQf;P3xMC0+Yp}Gq^ z4>mym%fy9=jVB;WK}eSk)q^V=m7|KJ6K7y*Dp#g)Rw)KbDX0_!sjOBp(uPLy*+>iu zLNX3#Enja`0!(?k`QPE2iy*C)Qma`MJW;QgdtJ*t*qzNk6Z@#Llw|Cl*I9 zk1mB*yt~)D14Zw^^|AN6e!K6JM^>yS3Qw);jTiE-@+_BkXuk)8i=SSCEJ8!slE+to7yH?qUZ|RUVNX;pmg=9|`RZ8vOfOC2k=&Y2?{I>efPydPX3ni7mzHMEut z?3`iNaM3Qk#@=+1g*V)YbrMu>LDnV!@>(tzpZ}co0g4;BJDcW;%~i5FUp+#UuCK)% za84hxy+`+<-*x!{9{QtwtpOLa?4$_wGzPl0%Uu-EZ@_W|G7)`?mk%2|;d8-3!zaQ` zO`G={Ujyog07Ss#Qdbaq8Ca2E1NkJdQ{SO(D)dTVLwUaY+;8@LfH$>5P@N504U2e9NC)jLQ-?fztH@JZORD9=(;>R12DpY0 z+7bQMl2tB5R~ICo0KAS+zhU|prXch{9K7-Mgz%&PsstbT_6 zqM@!0^8 z9F_Zu4WmWPXt8fpWt6wvPYwGi{5shwHBILq^ix4UJq)@8s9+2q@^35aBawI}7KtdB z3$Q5QPB3ASkSY1Awr5=h!p;&xnqu`Jugg!jH=BM9GPy0{SvlJ-wBGK9&+xB~QqUsZ L9@x5yN-qBfMFHIi delta 325 zcmcbSb>Edwn~#@^0SJt(u4FC}n8+u=^o?PnMs2-#5W6@-5QjKJjzA7$311K=kjDk$ zmGB2i1aSj-JWx4-Aju$JAfFG)7YyPD@&v$Yg@UAl1c5vusGM++bdWHRF9PL@0QsUo zz8I7*8pNo~pea-3x;cQ+mXT3#^EoCJ2}aGypQYY2)^C0+y_-ciAL!U30U+U5R0t$B zIg3grZ&VOwte$*S!G^6CBwII`T~U*Bn1poj5 diff --git a/YakPanel-server/backend/app/core/utils.py b/YakPanel-server/backend/app/core/utils.py index dc92b065..53bad7eb 100644 --- a/YakPanel-server/backend/app/core/utils.py +++ b/YakPanel-server/backend/app/core/utils.py @@ -130,3 +130,86 @@ def exec_shell_sync(cmd: str, timeout: Optional[float] = None, cwd: Optional[str return "", "Timed out" except Exception as e: return "", str(e) + + +def nginx_test_and_reload(nginx_bin: str, timeout: float = 60.0) -> Tuple[bool, str]: + """Run ``nginx -t`` then ``nginx -s reload``. Returns (success, error_message).""" + if not nginx_bin or not os.path.isfile(nginx_bin): + return True, "" + env = environment_with_system_path() + try: + t = subprocess.run( + [nginx_bin, "-t"], + capture_output=True, + text=True, + timeout=timeout, + env=env, + ) + except (FileNotFoundError, OSError, subprocess.TimeoutExpired) as e: + return False, str(e) + if t.returncode != 0: + err = (t.stderr or t.stdout or "").strip() + return False, err or f"nginx -t exited {t.returncode}" + try: + r = subprocess.run( + [nginx_bin, "-s", "reload"], + capture_output=True, + text=True, + timeout=timeout, + env=env, + ) + except (FileNotFoundError, OSError, subprocess.TimeoutExpired) as e: + return False, str(e) + if r.returncode != 0: + err = (r.stderr or r.stdout or "").strip() + return False, err or f"nginx -s reload exited {r.returncode}" + return True, "" + + +def nginx_binary_candidates() -> list[str]: + """Nginx binaries to operate on: panel-bundled first, then common system paths (deduped by realpath).""" + from app.core.config import get_runtime_config + + cfg = get_runtime_config() + seen: set[str] = set() + binaries: list[str] = [] + panel_ngx = os.path.join(cfg.get("setup_path") or "", "nginx", "sbin", "nginx") + if os.path.isfile(panel_ngx): + binaries.append(panel_ngx) + try: + seen.add(os.path.realpath(panel_ngx)) + except OSError: + seen.add(panel_ngx) + for alt in ("/usr/sbin/nginx", "/usr/bin/nginx", "/usr/local/nginx/sbin/nginx"): + if not os.path.isfile(alt): + continue + try: + rp = os.path.realpath(alt) + except OSError: + rp = alt + if rp in seen: + continue + binaries.append(alt) + seen.add(rp) + return binaries + + +def nginx_reload_all_known(timeout: float = 60.0) -> Tuple[bool, str]: + """ + Test and reload panel nginx (setup_path/nginx/sbin/nginx) and distinct system nginx + binaries so vhost changes apply regardless of which daemon serves sites. + """ + binaries = nginx_binary_candidates() + if not binaries: + return True, "" + errs: list[str] = [] + ok_any = False + for ngx in binaries: + ok, err = nginx_test_and_reload(ngx, timeout=timeout) + if ok: + ok_any = True + else: + errs.append(f"{ngx}: {err}") + if ok_any: + return True, "" + return False, "; ".join(errs) if errs else "nginx reload failed for all candidates" diff --git a/YakPanel-server/backend/app/services/__pycache__/config_service.cpython-314.pyc b/YakPanel-server/backend/app/services/__pycache__/config_service.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..91173071742e3e35adf6214b3f20e1930bdcc400 GIT binary patch literal 3732 zcmd5IzvHHd9Y8xyc$JHpz+;xd^%CfjUgwr3{U zMEbDQK2&Tgg+dF>Lm&F$V?pSP59)g%X@uATsn84fW>|vw*8e}dvztxPQY+E}^PlhB zX3qKk|2yZ*K%^l=Abs`ITBg-U$ZuHil2``CF8~yXMjUdHXu^arE;?d2VsSzmmmQg7 zX~H+|cl;d76M^xd6YM6MuY+j*4w7wh>a+mhAjcuC4seL$uoebf&vCuh064;NgVqSR ziQ|aY47i2kMy)kU)E$@iy|2&4b(3b51InmnUdl`>Hf0MLgDU+wUT;&!$(Yl&stRuX zh`nSQ=c#RHEECFpn`WuuASw;UKGW1md4miA7L5-kKRgmV#ZzDkBtb5UCq5x04RyQ8 zyTXj12}x)vB~46v%n?nh;vosa2(kxwa{fs*E%)B8oUN6}W!#Q2D*qrXz z`2Ak@;^=TPpU*SPa*|8>EMMH9Va+8y1`f>WwnJI9j6^_rN;hVynNI4tT(ZoKoisRC zuujg^U~b8+Po;Fzv>e@`sT6C3Z`Q$M_kbyoCqx!v8)%k4dW_l4D9>(1d1Vng5u>tR zC?Ho?2$73_0_Y{(oUgdYB-D8+iH!1;ls$B`+%F#RYN~m)S3Fp)^-w}MF;0j#-pkKI zynX=RSriJ=IbVq6#Do|Rdt<8k(K5_Q3F);mPB)-;6H>gs+RsB#i2W!DkaPQvNf|+v zE_a-zj#8plSI)Q3Gy(E>dG2T!c$zxLVhjpP`I0WZG@94Lz%~lx5PC z#Zo5Zu8+S(l^L$J)D2?Ap3ge2#H_rHFWI|SQCI}u(1f8|_ADRBc0o0F<9Ps&zzGjq z+rA$Da(MaD_la-K^{&IKU59VJ{^Rfu!?#;kkG!?k_4Zop*m}cQVeEdWX+0EO4Mo>N zeTC6qcXobyB~(V^x8H-$+S1oE#p}+%#cBKNt+_pwPa7 z2E!UM3~R`489ck4=4}i|7?n7M0)G4oM)w#*>i;gfA$p%1-Eu;%L^rr)H@OfqQLj9` z)0rS~RR6Y=gma;kF0^Rk@v_!Eg>}Pj7;pA^RC7;J+Z70Bg20vY9;hc+R!`IUZR(j+ zMIQ6qyJ{V4g%?-F!**a1qnov%!4PmIJ)L&_ur1DI9M!iyKsvA=hOCXN*}FwKu;JG# zrwcmpNU;F?7v%&(_jm02yzXHzblrc||JlMf(R+;p_k#QHhw87ZSJi6+>vG%Aa@$4& z3TmUC_}ZV^`{0|Psxv*Psxx~~Rfv0zfxX)hK}Jnivjp2oehB# z;Lzb(Lh;-X7;baVQ%@(f+vo^Xk0_`cXqHELRuT%dRZ@92auHWlAj!%B-~~o}>!DE| z2Kp8*AHuCPPp3+UnBpwu;6yj4Gv?xcMbGKR4Bf9-IcjDz4z+WXrd0?Q^r{=Fj7s6C z8-!1*v_rPw4q4mI`d|=W6}r1Xeh+tCJG~z6Uk&%K$o-`y;k3P}|7(Jo0;5?EnCJ0| zor+an`;gGSWr=4mlh-!nwM;4m{d`Wz>CTMDU5Hnuu!_ZS+Q>Ij=jz2aTtMva6sy6cD(rt#j|KOaJrdb<)8SpQubp33^dc$JWtHlkJUm6*ne|&3X z+%p)y4E@A#V%yyrJOwYG&(hQE4QR!k(moF6u_Oq>FXZ3@GW3A#`GdqBkp4|S{5@<& X;F7i34kyQE2(~#iQEr}Kk^AE>zvh;O literal 0 HcmV?d00001 diff --git a/YakPanel-server/backend/app/services/__pycache__/site_service.cpython-314.pyc b/YakPanel-server/backend/app/services/__pycache__/site_service.cpython-314.pyc index 657ff2c00a3bae9adbe018cd0f7aa671e7f54d8d..9a73273755671a071106c3187a436edf730985f9 100644 GIT binary patch delta 14435 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 Jwt+s?{|}_IHd_Dy delta 10103 zcma)C3v?7!nyy=2{eGmA?sRva-60`KL*7I{1T;Y)kr1#FgSe5NknTWBC*9nt$U}!l z-8q5|3*kC~&O>x`gdN?5i8G_FGb4)P+dyE!T72!!o?T{k&jd8bQFo5}|F`nO!@$&m zum1a}x>fi7|M!2lI%kH(eb0!lnJ%YIfaA!(skpywz!gY8N(5oMAPcInMvzG}Q3*eb zst9MX+0bNA4Na0N1+m@GY-}>ACT>g3<|d13;kL2a+GJC0O?K7J%cf>WlT&qa+uZDG z%1|?!+^UWJ8q~{wscf?ZOv=kGL-&JUQ#2_o;c@{0y3eZiMl}3Wh-t zq|ZJw4DNET6xsTSm!0?28l(=1g*`jjdo!)>x3-c=i)SV;R2k8LeTLCMFfl9P7I? zPLq9_VO>nsjEYL*Db3WCO2zu3nw08N*Rx(gtOnBG{%`7jN#4 zrPMgwz!X<{;)z(;#D3$e$QDy6It_X&CV&t>sF#`jL0dIc@X2aqHU1+(qtSWJmHS}d z8CTf}SJ@d?<&dlLVBHyK{RwCNuyZyu1nR}lOziuC8>R)}%43DOOACc#*9HJz%W81J z>3E@iX@%kVOtQ3seNygc=l7MdztlO{;v9Fg8!pkTN?eUa`nq~!nr&@Y_lEvdBpRnQ z6WYQe&B88*c%K?3)C0DHUO$cEBT`&g4wdXDIWvfF@XegN$eIGI#h25JaRu(AnG13T~t*z#bIhJFoU{fUeUIg(j*NVX)Rt_hnJdCG}aT}tdTyA^e9HCDlLU+f=L?4 z^BAv(a^>KmJPTQ(sN(O{*+$^&+RYx6{*{rm4szgltgIr zH8t0UD&u{jXe)3hROsuS>%)8g(Ir0Ki*P ziMYzH4c3-4VA%jyXi_9bsb;vdE1`)|Rev#Det5B6!93#%=y=`Wv%yl5&|hqQQc-bf z6n#AmnuL?7uZk3ncVBT?n&ECrApizlG4WnNcv5|4(NkMS(0s0)*H9nZUX@ca8=?&u zmdK)PkR{nDOVx%H>4eMmBPHeu?82^D?6F*bpo0_(vXp|3DX9Yja4}f|1Eq|NG-Ml0 zE3NFF8$1wEMeRQJ^b9XMyxzh_Z^pBg<$CSx*=n<)MZntyS!$-ov8uEl*9wl5nU7I( zla;+-a!JefPW19tnPtmFH%livC_g$Z<5Zloc36AhHS&dJuL^9Jqe$%Zu|q7M4Mi;O zl&y1u8CE@7VPju=3-Q53*~(UwWT)*Nh8RR}zOZU=?n8pGPC|PzS(Xc&VNV&_O(_XV zMFMAz4ud`p&O?V`jW8GDB+9RlZ7IiccZZ=9C!Qa3=S{TPp-q$>DThot9I~OqAR9Yi znvsRX&Jg>eq*D2IYWMn3%i<8awGvvpC6tKY8LOTjP4;%h`xaLB^d}PC>%pu_ z#d@y`rQ+QiSm*S)z8n}%BlEs;UebZ>pI(&C)Z8tL+uIhmE|OQTY>%`wcPyrpo;wFF zq)QM&cnf19xe45~6f4jpc^qkmzT_qflPgg4D>@56bE-+TD-ls*-AM>%EwinyC9?R| zmCbT<>(a=L4XfMebtk+CE z$wV|pHS5ItXaN6Q-Co{^< zdi*<&oVAim^>>xSqo^i%qbHZJ7>#)1- zjC<}0_uOIkyd4c6d%PdG1Lv~+`&JFC+SfVIc_2KTUA<$;IZyV!IRkU{Ef`pEz<0(| ze$rEp{Q|jk3z+pnP{=ME39(4IJO|RAu%~2+MffEF_;nV*QQLgLSImoSaC*(}LM$x;eBI() z5-_~(Crbj5FScFJdB`$8cRIfw8p{htwLb+p?FyM8$$l8F0fv1itcYp!Pr4dlt5{Xl zN^e8Uo}%$PH^jD}D~B!I|7ZmJad(__QSOXuumNcnaz!87>i{%qZI=?$#GYvtP_A_h9zX?5Xvs$el5&K+>jh z_P?`o<{;68CC<522Aif3(EqRW=6ACN_1odie_J0DNzP!&oEpP5Kpuh~R!w-dn{L92 z%?Mi%@CoQvggC-o2zRrc^HvvQzD0-bk0+uL^k^kU;VC0)6UpukbT_o#J!rhHgYXy1 z8SI~LCux1<)L3sS0eS1Mj-}ZlIJ#qz^{Sdu=-qIuR?U%s@};R~Yy$ALCuiYG6Ce%> zj4a#>Q}EEjqlR3*_-VX)JHkB(_afZKl8rZ!ZS2Ly#`NR_@#V*L;x9+}eEI1BR{YgT zgIodgg}?yD-%FpO9ay~+;Q@pP5xx(gk(6e{R|N`E0x+?9ckWnX0{j3ws_X}g!nu46 zoDm8X1T%jpUPONg&4a?=*+mv{0iSQPPSSe5Mj^sI2C~Byo#j)36)XV-#hR9!3ICWs zR#d@^SPIGji%$Kv5m>6;E|oq3b#P77($lx{QN`$5$}h`^ZSGF=M`IB#>f+H>T{lP+ za?{wl;j>)Td(R83zv%{8yI(bxi%yJLO`KcP8n)3T?2k9ybnBCN6C9B~h446bFs4x5 z(SO8>pJN5th&utLKcOmCD3@{x2PA#zE5$a0qEYBCpvQS(aM!Z$>7GmZ5d3D-@Q(cT z94VT-Bi5}()Ga9pdGJ>rEqk#84^yN5qWm3YtmXdN2G*5a^$TcMHUgkfx}KyP$ptty zl5-aChyjh?+nggtG(I;8cGrlRn-;;9^-%Gy)gxA3vSbWshWV z(~V{(H?stj?ScnQ>VsjsEdb+(U1083GkI|^(7MOO#NtAB#|mGDQ_ho}^|*>~r1BXl zM&;xs`K+?lUsS2r3qnV}Ly+@17Su`Ox+o~HqwO^|&~}BO?SgWMZM@mXmfd14+ieyW z8(R7R#TE)kTKZ<@ zXoHPTsGG)s4WpVEkA?%(j$>goasQ*}rc-ngCLPVBJE&&q?b;B7ZHz)qSZ(NvMm1wk zqF-6B=cwjOZ2mDE77Xt&8_=gWrOjoX{gnXUJ4x@Xh<+wR%6Cw|5pI%y7_v-tO4yMN|^RR>oe zTy}WtP@wUYWfA-SgMswn`scmB^S|I9vNsG#4HvtKkTLV3MR3<#3<<{Ui!OjKFM0*< z>k!mQPl=q}K`> z=0o9l4q1^Y9nW1f7Yc8Cg4g4zu4si7F%7 zinm~$9&c=O_soSlNsjH}yOaHWs%8MS5YEv(JBZz%Mc|&o{n(PEn9kO2q3^O!yZz}y z*vvx|Ih@C-W`?gHU8+hc&(A!_r;Lo2IS)U*1RHB8=}ay{ z*Rg|rwazAfM`E=DZ19owFNtj99gP`Q*$$r$$9deuQg;N|knCa4?)8K+aL3tMHhz7F z3Ao%*Cr+^V-fgv2use6c?%Y)^76U&6U!UWc;F!x%0^as<-p*kEy`e0POSOdl8t^L@ zr@+3X8tMV(i0ZWQ8)%`wMfe@UQG~Y;-T@e=&1ejCbSxUq{+9nx?k}A1{t2%^{?n|H zh}yLls3oGAqG^7m?oycN=${cT!?b!%cn@y?vY|H#`W9J|o&*S+br0g#qVv$R2;8AG zv_1k*aPTpaF-BbQ*dBOpow>e&X1<<`RX=<)`$6xCh3>2g=4v~Tf4ZRRu=#o4%l=_^ z^A+jqwxK}HDN8L7S1?^BxR#KMHo>@@Xi}#p<%|(j97emhL2RlbMh)D#ur_ZvB zsfyYs;Xag?ao!dD0sxzBeSTd)47$|hWJAqx*+#Zv3xRu)6iL`Kki+ZB|YrIlOrd`y;wvF3}^lgUaEWKAMlz#B23U7|9DAx*o<*2 zHvbRa*K%1e9Km)Rm$MYT2$q7LeyQHgo|r5A02&$JC)i-hHp74A27vQGGoQdmfO!M+ z*n)>=4KCQUXbO$#k%RQxst@-|9FxC4e|4N>*cnf(_>?W{)zZ&D;1l3}6KSrIAkQJ9 z08Sgw`n}UVVnl;0;62i=86#$199O~ny{DZ8BUWB#1O2-ry300V=S2qy-#zLNaz~uJ zh?1BWGkDRBS~wF;ok1~(#}7LgZ1;YnSZCuj8n~;%jX2{Np-0{u= z{Kz8b$nFVt4YDKKf@C?X&GL{S>g4J8HH#k|LEzS0j(Jmca)+?;W_Dy{0jqf^V-0X^ zK5%Wp7}rWI&jPwe-W+Au{P=kilVu9I(-%GV+gMSOo(Ny zI1Zo{_NSt(a#fyql(2o@D@nhJEfc+E2^V#bV{&uq*qt+{diDR@d@0SBndjiI4=iQi2;MjP1hjJn)0d;F(=_kjBfz zvSx|K6_ig=uEpTfY7*YWO&U_@l%KKR?%|pN|#m=XXlpF7N|m z3pX71;cvRrq`}&O36t4hzt_ougwatpk&rfXSU5;uwr1!9h>k+n2p*i032sWKX zK&pZ**_bElK9!3Db0)(301N5AxF83ytcN|eY0%ESB?$ui&n=VU`cy&na6#?iiqi$x zzwCdbbVy!3?7r=a3j2}|1n>h5>)BU)Q!PsE3niR@=D`!7yw2eA+Q#KI*hLLxQ1z;{ zp$1OJ<~5k%^g1C;PU&^A(F%n(oCJ^u@cDfWW%woIs=D-R!fxIlhB&%we~$RMiA$02 zBRxiT;*mo5@&x)KD9M?Zcx;yJk+UY0h>s0D5+v7gCE`PuZC(K5@}t8CF6-r({VkXE zfy?^G#D}3JpNovrF)85~6B!{k@{=4AV7A9Pow$PfMh{$&DUZG4=7Qj9sMd7^mj(q_ zlm_hm1C=C;{pG;)DT-iHU1y*Na9O~K>oP9gzBRK0KaIm@w{@|;809Jm>~YO2zm(P;k78;A7^lmX;{w{BMx5@@~SZr+#lh&}L z8CEu})Ia-jce@6jGi+?dBV3`GBd}rWjzsv!SxuxdcIfGHVqhnqzB{d%;WKIq{P)B zhXr}WB)GG7Z+&3vQ0{kzGrG1rKJm;L65MCKz9AuV)C7MeHCksU&e423@s8%hA8m}b z5F1qH))UhgePkx_EE?@3M&ka$Z3oE5-xNk~6bnek=nVwEN{!Y?BsA*sK<^6NV~yS< TT8L@XhZ+2fc_m~nf0O?Q32S}) diff --git a/YakPanel-server/backend/app/services/site_service.py b/YakPanel-server/backend/app/services/site_service.py index b10fc10d..4bc09fb1 100644 --- a/YakPanel-server/backend/app/services/site_service.py +++ b/YakPanel-server/backend/app/services/site_service.py @@ -8,13 +8,55 @@ from sqlalchemy import select from app.models.site import Site, Domain from app.models.redirect import SiteRedirect from app.core.config import get_runtime_config, get_settings -from app.core.utils import path_safe_check, write_file, read_file, exec_shell_sync +from app.core.utils import path_safe_check, write_file, read_file, exec_shell_sync, nginx_reload_all_known DOMAIN_REGEX = re.compile(r"^([\w\-\*]{1,100}\.){1,8}([\w\-]{1,24}|[\w\-]{1,24}\.[\w\-]{1,24})$") LETSENCRYPT_LIVE = "/etc/letsencrypt/live" SSL_EXPIRING_DAYS = 14 +_SAN_CACHE: dict[str, tuple[float, frozenset[str]]] = {} + + +def _normalize_hostname(h: str) -> str: + return (h or "").strip().lower().split(":")[0] + + +def _iter_le_pairs_sorted() -> list[tuple[str, str]]: + if not os.path.isdir(LETSENCRYPT_LIVE): + return [] + try: + names = sorted(os.listdir(LETSENCRYPT_LIVE)) + except OSError: + return [] + out: list[tuple[str, str]] = [] + for entry in names: + if entry.startswith(".") or ".." in entry: + continue + fc = os.path.join(LETSENCRYPT_LIVE, entry, "fullchain.pem") + pk = os.path.join(LETSENCRYPT_LIVE, entry, "privkey.pem") + if os.path.isfile(fc) and os.path.isfile(pk): + out.append((fc, pk)) + return out + + +def _cert_san_names(fullchain: str) -> frozenset[str]: + try: + st = os.stat(fullchain) + mtime = st.st_mtime + except OSError: + return frozenset() + hit = _SAN_CACHE.get(fullchain) + if hit is not None and hit[0] == mtime: + return hit[1] + out, _err = exec_shell_sync(f'openssl x509 -in "{fullchain}" -noout -text', timeout=8) + names: set[str] = set() + if out: + for m in re.finditer(r"DNS:([^,\s\n]+)", out, flags=re.IGNORECASE): + names.add(m.group(1).strip().lower()) + froz = frozenset(names) + _SAN_CACHE[fullchain] = (mtime, froz) + return froz def _nginx_site_template_path() -> str | None: @@ -77,30 +119,40 @@ def _parse_cert_not_after(cert_path: str) -> datetime | None: def _best_ssl_for_hostnames(hostnames: list[str]) -> dict: - """Match LE certs by live//fullchain.pem; pick longest validity.""" + """Pick the LE cert (live/ or SAN) that covers site hostnames with longest validity.""" none = {"status": "none", "days_left": None, "cert_name": None} - live_root = LETSENCRYPT_LIVE + seen: set[str] = set() + want_list: list[str] = [] + for host in hostnames: + n = _normalize_hostname(host) + if n and ".." not in n and n not in seen: + seen.add(n) + want_list.append(n) + if not want_list: + return none + want = set(want_list) try: - if not os.path.isdir(live_root): + if not os.path.isdir(LETSENCRYPT_LIVE): return none best_days: int | None = None best_name: str | None = None - for host in hostnames: - h = (host or "").split(":")[0].strip().lower() - if not h: + for fc, _pk in _iter_le_pairs_sorted(): + live_name = os.path.basename(os.path.dirname(fc)).lower() + if live_name in want: + match_names = {live_name} + else: + match_names = want & _cert_san_names(fc) + if not match_names: continue - folder = os.path.join(live_root, h) - if not os.path.isdir(folder): - continue - fullchain = os.path.join(folder, "fullchain.pem") - end = _parse_cert_not_after(fullchain) + end = _parse_cert_not_after(fc) if end is None: continue now = datetime.now(timezone.utc) days = int((end - now).total_seconds() // 86400) + pick = min(match_names) if best_days is None or days > best_days: best_days = days - best_name = h + best_name = pick if best_days is None: return none if best_days < 0: @@ -127,6 +179,31 @@ def _letsencrypt_paths(hostname: str) -> tuple[str, str] | None: return None +def _letsencrypt_paths_any(hostnames: list[str]) -> tuple[str, str] | None: + """First matching LE cert: exact live//, then live dir name, then SAN match.""" + seen: set[str] = set() + want_ordered: list[str] = [] + for h in hostnames: + n = _normalize_hostname(h) + if n and ".." not in n and n not in seen: + seen.add(n) + want_ordered.append(n) + if not want_ordered: + return None + want = set(want_ordered) + for n in want_ordered: + p = _letsencrypt_paths(n) + if p: + return p + for fc, pk in _iter_le_pairs_sorted(): + live_name = os.path.basename(os.path.dirname(fc)).lower() + if live_name in want: + return fc, pk + if want & _cert_san_names(fc): + return fc, pk + return None + + def _build_ssl_server_block( server_names: str, root_path: str, @@ -307,13 +384,16 @@ async def create_site( ) write_file(conf_path, content) - # Reload Nginx if available - nginx_bin = os.path.join(setup_path, "nginx", "sbin", "nginx") - if os.path.exists(nginx_bin): - exec_shell_sync(f"{nginx_bin} -t && {nginx_bin} -s reload") + reload_ok, reload_err = nginx_reload_all_known() await db.commit() - return {"status": True, "msg": "Site created", "id": site.id} + if reload_ok: + return {"status": True, "msg": "Site created", "id": site.id} + return { + "status": True, + "msg": f"Site created but nginx reload failed (HTTPS may not work): {reload_err}", + "id": site.id, + } async def list_sites(db: AsyncSession) -> list[dict]: @@ -364,12 +444,12 @@ async def delete_site(db: AsyncSession, site_id: int) -> dict: if os.path.exists(conf_path): os.remove(conf_path) - nginx_bin = os.path.join(cfg["setup_path"], "nginx", "sbin", "nginx") - if os.path.exists(nginx_bin): - exec_shell_sync(f"{nginx_bin} -s reload") + reload_ok, reload_err = nginx_reload_all_known() await db.commit() - return {"status": True, "msg": "Site deleted"} + if reload_ok: + return {"status": True, "msg": "Site deleted"} + return {"status": True, "msg": f"Site deleted but nginx reload failed: {reload_err}"} async def get_site_count(db: AsyncSession) -> int: @@ -462,9 +542,10 @@ async def update_site( template, server_names, site.path, cfg["www_logs"], site.name, php_ver, fhttps, redirects, le_hosts ) write_file(conf_path, content) - nginx_bin = os.path.join(cfg["setup_path"], "nginx", "sbin", "nginx") - if os.path.exists(nginx_bin): - exec_shell_sync(f"{nginx_bin} -t && {nginx_bin} -s reload") + reload_ok, reload_err = nginx_reload_all_known() + if not reload_ok: + await db.commit() + return {"status": False, "msg": f"Vhost updated but nginx test/reload failed: {reload_err}"} await db.commit() return {"status": True, "msg": "Site updated"} @@ -503,9 +584,12 @@ async def set_site_status(db: AsyncSession, site_id: int, status: int) -> dict: site.status = status await db.commit() - nginx_bin = os.path.join(get_runtime_config()["setup_path"], "nginx", "sbin", "nginx") - if os.path.exists(nginx_bin): - exec_shell_sync(f"{nginx_bin} -t && {nginx_bin} -s reload") + reload_ok, reload_err = nginx_reload_all_known() + if not reload_ok: + return { + "status": False, + "msg": f"Site {'enabled' if status == 1 else 'disabled'} but nginx test/reload failed: {reload_err}", + } return {"status": True, "msg": "Site " + ("enabled" if status == 1 else "disabled")} @@ -543,7 +627,7 @@ async def regenerate_site_vhost(db: AsyncSession, site_id: int) -> dict: template, server_names, site.path, cfg["www_logs"], site.name, php_ver, fhttps, redirects, le_hosts ) write_file(write_path, content) - nginx_bin = os.path.join(cfg["setup_path"], "nginx", "sbin", "nginx") - if os.path.exists(nginx_bin): - exec_shell_sync(f"{nginx_bin} -t && {nginx_bin} -s reload") + reload_ok, reload_err = nginx_reload_all_known() + if not reload_ok: + return {"status": False, "msg": f"Vhost written but nginx test/reload failed: {reload_err}"} return {"status": True, "msg": "Vhost regenerated"} diff --git a/YakPanel-server/backend/app/tasks/__pycache__/__init__.cpython-314.pyc b/YakPanel-server/backend/app/tasks/__pycache__/__init__.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e86154e9bf23e0f2fc402ee1fa8968f86e768d9d GIT binary patch literal 269 zcmdPquI&U67cUnxmJTpBodIm>mG(=;kICm!uXU_{FJ3Wk7yXVsdtB zUP=tmsu-|UG4b)4d6^~g@p=W7w>WHa^HWN5QtgU3fwnLLaWOxT_`uA_$oP~&`vJFj Mhh7tV5j#)}0A?jh?EnA( literal 0 HcmV?d00001 diff --git a/YakPanel-server/backend/app/tasks/__pycache__/celery_app.cpython-314.pyc b/YakPanel-server/backend/app/tasks/__pycache__/celery_app.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..76ab0a4c6e0730e5cbf076ee0507be11c8fd7a36 GIT binary patch literal 746 zcmZuv&x_MQ6rTJ}leBT|($&RoTlQj+?MYY>*-J0G7b#&ygw!xiW=m|EgvrFxp6bbi z7Z3gsdiUQDEFKyM_OSR56jnSt=?`=9G0c4L&HLV)_c4zuWeqU<^zDcLnFHWg?(9t6 zg4?eQ%z*_6cnvJ>f;;C4-^ek4A)JduY=FMl0*|-pMC$V`U|VAdYUV^%7W**pXN*vRu8U&gxKT(@Na!9$NgCvx z|D~wJAEQ|mBC4Sf4g%z)#C_h@sNy(Ycf1ev+#J2FtA7UYos>LW6 zd4A%gIH1~w=P(8p^K2@ou?GqI0&a8V=*#X?dor2eC?fV0j@AOOvSWLv!}^;12!(nd9+2*61%Jn9uhB literal 0 HcmV?d00001 diff --git a/YakPanel-server/backend/app/tasks/__pycache__/install.cpython-314.pyc b/YakPanel-server/backend/app/tasks/__pycache__/install.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..015cf9c884c77aa9eade8cb45092abbd20c2b218 GIT binary patch literal 2137 zcmZt{OKclOboOUE_QvriZCaW%+cy1JiIa+?H1q>a-4?2BxyaZIQ1&AGGG}vxNag@|00AHX z5CjMTbOD3`A^@V?Ek^-*0Ac`fIX)J(`PaCtYu`87rgE>G=tFX{50ztOX2KKN0hu{~ zQakDs*OgLM(Q#QyOBZ#^R?20`R;-dG9WivAE|j%GNzy#QElrUW(@ssN7$;o7WlU;$ z#WWp3FKYU7U98lso8`2H$t_Ik(TYMeMVvlk70yud(+ zbkf1Yqj%pA|o?7khF))cK9(Cvcvt#g2dr1qxVnR7Fr^U^(P)*LaPS9IO56&vUCq!%phhH32uw1WObaVEq3=Hd^>H(mN!vc28{ z4OF21`=bjOh@0PPfx|1P6Kj@c=s)8cn()q=>>iZkeQ`G6a~--5-tinOqGwr|0=(bj zp1#S=aoJEu)8}rW$tAdj>+}{t<9}Z5N#?MpTVbaZ_#fK>3C zM$oo73pVB07*}Nn&;gXASLzPXgC5b3OrfKfgV@_+R+#YKbo-8JgDj0aO1EQ%5ReK>l=>!Qj%Sr*$O2UK~#Bu`Af9xvI1w|`kmC%cH1Xp-sTH6L2 z(++EtNQ{1Frx&MULsd%Df+~TH>6GXMvzK1VU!KZBXTY`-wyN_cF$&m%enG0b6DAnE z(+ki-s7VzJxD-x9ufguV05z_ePIR{I`T1p2gO25NonJ0slUgM7)uaNhkFG<|;7Ua& z08Ok~wjGXsl))CQ7f2cmlBChZytL*0+aY7Hy$hzb4QK^z2T&yO?(jRqx7A1CeJhzw zHY#M8C-FUZ_P)Qj6&+vCtRHKN&$kjgTYCmuy?xtVLL%GG%sY()AWM*3HoA0qo& z$=!EOzjt~gIoV83u3q@~@<*53{Q8xR#F>YQGhg*JXI^P0&OA!I+Q_te`|mEU1=jiX z;yvrj+UK?VZ+tuP_{D59InxwpTCrVshgJh?{F-*Juh}!z3{Cy@B(h^8GW0Mqw2c_y zDnnI{tX^0EG5V2>i|z zI(ra(y(>xa$Wg%G31lWNWgi=8#n9sux0@~z$ z_@2`X{dCmrr=y)e6`>7)NL0>KnVbAikozv%_Y*o*G1O`qzd(+G7OgpJ84$S2Fh8Ob zKcV=~Xm~S(1hH|g#V2l0xA@-X&O([]) const [certificates, setCertificates] = useState([]) + const [diag, setDiag] = useState(null) const [loading, setLoading] = useState(true) const [error, setError] = useState('') const [requesting, setRequesting] = useState(null) @@ -86,6 +98,34 @@ export function DomainsPage() { Request Let's Encrypt certificates for your site domains. Requires certbot and nginx configured for the domain. + {diag ? ( +

+
HTTPS / nginx check
+ {diag.hints.length ? ( +
    + {diag.hints.map((h, i) => ( +
  • + {h} +
  • + ))} +
+ ) : null} +
Include YakPanel vhosts inside the http block of the nginx process that serves your sites:
+ {diag.include_snippet} + {diag.vhosts.length > 0 ? ( +
+ Panel configs scanned:{' '} + {diag.vhosts.map((v) => `${v.file}${v.has_listen_443 && v.has_ssl_directives ? ' (HTTPS block)' : ''}`).join(', ')} +
+ ) : null} + {diag.nginx_t_probe_errors.length > 0 ? ( +
+ nginx -T probe: {diag.nginx_t_probe_errors.join(' | ')} +
+ ) : null} +
+ ) : null} +