From 88424b8836d20bef2f038a2d1f608bec666d40cf Mon Sep 17 00:00:00 2001 From: Niranjan Date: Tue, 7 Apr 2026 10:35:44 +0530 Subject: [PATCH] new changes --- .../app/api/__pycache__/ssl.cpython-314.pyc | Bin 12089 -> 14833 bytes YakPanel-server/backend/app/api/ssl.py | 52 ++++++++++++++++-- .../__pycache__/site_service.cpython-314.pyc | Bin 36883 -> 37225 bytes .../backend/app/services/site_service.py | 16 +++--- .../webserver/templates/nginx_site.conf | 5 +- 5 files changed, 60 insertions(+), 13 deletions(-) diff --git a/YakPanel-server/backend/app/api/__pycache__/ssl.cpython-314.pyc b/YakPanel-server/backend/app/api/__pycache__/ssl.cpython-314.pyc index 87744e90da1ed08739e9efa826dab38bb2be1c29..228b2b2529106d9e274a7ed383d6d53ab5617349 100644 GIT binary patch delta 4917 zcmaJ_du&_Rc|VtzPf>i6qA2lkMLj7+k{`0<*r_8&aV=YpOJ6b48qlUG@=9V%k?grt zB+Ia+VA*1K>m1>^AutJgmU7YGoq%{nPkAoWf_iXlLNVa4P`MKkoD zecvT1Yu=jk$9KPbzUR5;oZtD*{l^OrWow7kQbnL$d~H4R=ix6ionDf)7aK$u@NSh4iyq)> zRKD?iD0+%5YF(U{wR5fAwIK1KB+K=bT#;h4hd_inkkp^I_VA_dVhdP)4K3NHVB60* z7^iXT+A97Ig?hM>=6OQ{IbTzGJIILwcxreoMnvQqNu-haH9K~jG%KYN@}!i_CgjVx z6tnPu&Ar9$@PDBTfXl$$9<4{uMcC=8>s%XKt2*ZQL$_j2q$FA#%NG-={M1x3m!<=% zcBgq+bJ`0mtp)NHN9*7b;b=WPWXv&4(Vn7jmBdlt0VpRFhO7&m z`6Ma_k@(q=kZ(h`N!`NvJ z^iXvBWvNLZmr)Z_b8>^+LzOOTOV3g)5bri4a1cxT`QJd)1ro31Kq|9aXeROUl#)lC zTo);5;@XOvsGc>{xft(oaU*QC&7&2$9*+H2z!%Vnyr>oVp0a9z|35~z^==`~9RUvGwX~1y+C5SctL)^fG9d-+{}+ihM`~^DFctqh z^_Jj>w&J3o8$I_Vq>+YE`^nHbQcA;P+tn!NaaSP7-3?o%b0C=Cfd0-C@^S2uh< z2iEX$=?h?>?vu}eSsdebCuU>ok+H08&gYcn2*fiR2+HTmE zOzXz*rm^~_@rLo+&RgC^?}npc)zNS}vgUYV-PrkWw&Cmimd$Z<=Els;Yd5Yfr8aEg z4{hOJSG%_?wwt3jMmH>hRZCzgwPp!l*KC?Ce|ZFC74Q7I(ZAVOa{rq1uc{x~h&{%A zZYTCyaBK7~H7pG*9lC8=Zd~>(Us|a>a{rkPDy?MeJ0} zvYbt%^Ha%8PNq}PGk5nbSAgRd+57IB%?Q4Vz9d!*GtwB%=ZlI?0`)9C0m6ue*0U>~ zIz2k00rp)_6PVujbm>)yJ;`=FSN0V_rs8#f39s|0i)0Z6xJAVF)0{&A#V5%DLIEeRpby z-BC>Zu@oEZDq;2`jBzNxC`l797r6|Ky9OK(RR>rv9p1y$Lvib zrf4UY4hMI!zv5-0OZ9@YsW#Cj+T#c_YOC1s4$;Ye9tec^3gAw1@%M$^py|85Q#s@%mKf90*+f4*Pe{x zN7>)i`DtcGbKBg1>Vn7VWNK}gh>kEm3*wAG`K&-TaCH|EPUrDiGg-niB zdZYc2iMuXlfkaFfeiE~a;XYiS&g zin&Vj%30Zb!0WNXI2>Z@qxq}IEAyvogM8KeeNM4mv~Z-GZ^U92?IPl?bbgQ2Ku&1R zoK|VAK;pfXaq3AL_Kcqt%zMWudShlBy|}wlV&+MWXepSVHfOjDIm!n}h66v(?C}G2 zB5uh?ezc-Zo%A}pXqnXPnXqTs8^P8_o7nisKWbF`8pxUdIK*eTNC*3E@V1T)K@j$O z=pVRl78P1KKbsW}az9{i3)kk)Dtft?EKbXr9jMXf`UaA@T)qgW_c)d0$#UILDj3Se z0oDeY@k}aNltAqp(~?{~A}IWnJfT(wbLOrYsGvJ9&D(30sBLeGgn4WKf(ahCW zN|a(|N=gg)X((v+AKoWN=6n^2G@B`cXeLvf6jBgRn0^l|g@H*ab?J!k?Ac-Ac=vH= z0@OT0aT02v(orE4pr$CwLNQ za@d^~GCASv$xBhJ6^@oaV?I~$Az)Dk5ilqk{`AX{RRw-QY28K5~@W4=ugU(5_>ruYF6}AF49ba{uv4+ zBzhz^Ac}5gQlb*Q$hO0wc?WinBT)-0ytk;;P3g2YP9-l%FefrSgn|JicnzV5Y!uOu z9zcRvLvfqXgFtYZ!O>3DC(KsFL$9H%bfP0Sj9La*DD(LlDXs7@8A^3|4J2}TI;B*> zlAO*K@xWIMKoT@RqnM~PA>|SUDk+xTb(Vnq6i%Wp^vS2D(zFdZZGq-f^jj)B33IH# zi9Dm|R1fqzbjw&}_q9M7`*KAhil1vgyHtFGod zV?P}K{`i`!bK%TyyuMp=i*t8c-mZDGYa`sd8t(ncOFzBx?v?wg)xJ|};nN%8=xR8+ za!y&feZM8SA z-nhE-CmXhw4{a@5&d{bm725Ph*M~<|MlWuRrdLPPE7FTA+1%P_er>q$k+-m;<6YKm z!dt96Mq+ARH@1D^uDNw`@#L*Di)U{8m#?lIJG`WVf4IpCS;|EoT|fZ1coq0g=tW%)c{yujlVyxbOL>=j6I|aK$+I zn<~e`z{iHFt(uPIXWrr2FPj&SeKw>a&gZ$$^u%+V`(metRJ(Qvhw-fS%lt}jeC7Ow zm3U&M=i<6GxiT@iVx0WLHjfH_*y-n3qUFSV9dSJQ-}2Al!~bcM803~6Kz=q*2lPEJ z9EjX|hn{%?9`84B(GKnV;dHs?VS4$tz6;8&eI^sjmjia!2BlO3r~D+XC#>$xGUyGom(8n`d348Op|R=JB;bI-zE z9O>KX(i8p^thK(Y(O*P|5%$gYo*I=s3GWe3;bzrZwgvtlthe{JXaSF9BZwBrJ?>u1 zKbh1T67={>(&dP$f*<=j+^1eahgh%gxoPQTz(l|!otnC0#7m^Q_jCxtGQEiESenUL zPpG>J0)MNcUiUM2|NY&+?P%ia+Z96s_H-(dD23}oBNa!w*nd9pv4+~&gU(P2Q3)^% zumfP^2u5_I{~4t48HoHl tcB1PD*UqkXH5q^B#NQm-?d;92uRE}~hAWQ7x2-{T`x>)!w`sA;{U0*LeMs zC(EwUN^JuqMbWCtB5i>dMIQX17ARmtZtM1;DEfm0QIghh0H+55=|h3O^g%*hG-!(7w*qVKcFQ(dOWmCcJ|EIU5#gfT zAy5}}_Y>Y(b(R=wTYsBebbapv`SUsY#F07LZ#_x#MCuGhXG@Bi;Xo#mmo;<}nXY zy+|#Q!Ci(P^9Zm_8?3ZnbPtNvX*~|6zFKdjDpTLCDW4w{0?(LA;Qsu_?jQ+noN=#^adZ+3 zBAA=BKiyQ~;vsz>`%6=3vYaZsCFr;FH&c*MwJh{g>kl z!7Iz=*4CMF@#gNCftD6cHHMyJ5>9-8ePvrOS^1^33a(7#B)ooj+=vyGA|>lvXKfe;fSLe|Yokx}C2 z>yg`|xwaaq_82O1Rz}}rn}fg#3OW48W}~hgUbEQ-`77~Odse1y+DMzS{H+1cIoh0+ zXbWwn`?EsET4V0@)I+_rt=DyMZ%U}xau}dydwPb3fRMurFLLODB-Ym#L}pd19-TtJrQ)dn zhtm!kI_T$3o!;eXO9t=bnU?FRP2_rO(jY!JXqm&+z8?2jng06usyr7xG6GE`wy3<)Z+2^0T? z-yerWm89eR7m2r=hC@^I#Y(a)O+ILfNR9EMfVzj)dM^lH79@5ebUYEe52LhgBlj=zrOd7JL7xYEV5a+cy?(DwW z5oMQv#PSH25%7sHI|9ZOOY%3nBN;Qhn^~7(Wn_H_hY&D)7`_pPVTSf0buzPugRm)F zkr5hkSz5ZPFojLFX ztHAvxDha%&XGh#}h2H2(O3qd1cbq)ccl*MYJFqU^8M`n2>dc4k6Mt(s@sC!|kB+S! z`{|Y2*`F*t3im$<_uo76o6)AA32&H zIbshSv4@VXm9dX)jxBHZ`g8nA-lRC^W9^X>R#lB_oa z{BFz-_~*6|;?Q&L(7o*roDB+Zr(+<$<7!3hXhR%1H3;3iJ!CRweYZCN@}>h7Hap2= zmvu9SmNt(M1HN}84EVmsh8P^!KN%H2Xlg=?T4CygE;5 str: ) +def _reload_panel_and_common_nginx() -> None: + """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) + + @router.get("/domains") async def ssl_domains( current_user: User = Depends(get_current_user), @@ -144,6 +166,25 @@ async def ssl_request_cert( raise HTTPException(status_code=400, detail="Webroot must be under www_root or setup_path") dom = body.domain.split(":")[0].strip() + webroot_norm = webroot_abs.rstrip(os.sep) + + result_dom = await db.execute(select(Domain).where(Domain.name == dom).limit(1)) + dom_row = result_dom.scalar_one_or_none() + if dom_row: + regen_pre = await regenerate_site_vhost(db, dom_row.pid) + if not regen_pre.get("status"): + raise HTTPException( + status_code=500, + detail="Cannot refresh nginx vhost before certificate request: " + str(regen_pre.get("msg", "")), + ) + _reload_panel_and_common_nginx() + + challenge_dir = os.path.join(webroot_norm, ".well-known", "acme-challenge") + try: + os.makedirs(challenge_dir, mode=0o755, exist_ok=True) + except OSError as e: + raise HTTPException(status_code=500, detail=f"Cannot create ACME webroot directory: {e}") from e + prefix = _certbot_command() if not prefix: raise HTTPException(status_code=500, detail=_certbot_missing_message()) @@ -152,7 +193,7 @@ async def ssl_request_cert( "certonly", "--webroot", "-w", - body.webroot, + webroot_norm, "-d", dom, "--non-interactive", @@ -180,10 +221,13 @@ async def ssl_request_cert( if proc.returncode != 0: msg = (proc.stderr or proc.stdout or "").strip() or f"certbot exited with code {proc.returncode}" - raise HTTPException(status_code=500, detail=msg[:8000]) + hint = ( + " Check: DNS A/AAAA for this domain points to this server; port 80 is reachable; " + "the website is enabled in YakPanel; nginx on port 80 loads this site’s vhost (same server as panel nginx if used)." + ) + raise HTTPException(status_code=500, detail=(msg + hint)[:8000]) - result = await db.execute(select(Domain).where(Domain.name == dom).limit(1)) - row = result.scalar_one_or_none() + row = dom_row if row: regen = await regenerate_site_vhost(db, row.pid) if not regen.get("status"): 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 bb05cbcc275cd062b9a207cc162283c303db8997..540cc0c519b76d5e6b97e397b604d88eb0c9555b 100644 GIT binary patch delta 4069 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 delta 3572 zcmaKvdr(x@8NkoEd+)yAcOS4U?D7z@upogI6+vBM6ygS!6|WK~1`u==$>uJIi7^nJ zBv>`ko_4gEG-KOjYW``=+;pO8QpM3|;%ki>)0DK0waLWPW-(IhOlR8fTy`OuPJ3th zeUEeQx%b@f`_4Ih^$Ug^WQ-+7gBHQ{?CvYk_Qp4j8#3xEv2p?d#;x|G0^|*oHOYaz zqeNytsiK;iY8t9(5%khgO;3FWsu_{dk~CG4;~6>S)V3m}W`YMz%z!6#tLgJnmmZ`7 zA@rxrgX;@!1#UQa}Sa?+*SO5_{5stXkSmiQVL{ zHAk%Cb1>+qn*Mds{w-^|qWy6zpv$W322eO(``n&Tf2xU8Mk^4st@^(XwI}; zThW_7>lYjrr_Yj_fIZfCJabazF5t8#flRr?P`JV4Tjx zjXw6Y>w$S-oaL*4=d?i=i1V`wfEP5l(eGg|Xz7p_@-bzhOrK0YB{`^ckYmA7?3U{5 zwkz?+eb zBeG=JUw~VrU$-p9_zsy|Sq1b9h1@-8Zy~FMKk09RCRzcF;@6}+ds56I}_a-5`AJ~VB2NK)1%AA z^$yZ1Zp53&DRK7j1e6n0(%)eG?LkH;#A7TLIChN7qIzy7Wi=Mm?AQVw=qFUvbHa-S z9eW~I_LK&x>!cD3M)sttE(47By*y>W4Lohef`vV8d5{I;oFixialQZxHun6iLSeWN zU(f}S;AAiAf*6_-1_xz<-0xBa7ToNm$^vkG}5_(X{b|!>#Bn`T!q&wV6V!r z_pzFe@v%;(QKm(vO{P;xTRoKB@cj@**`KbbIAl$YlD4dnsij;b|Tf9iNZ@Z7PfqG1OW1E3d zenkh7i*?yJc;mTX)5^-m^Cl=>4JD~~w^9}-1G00f8W`xBzNV|8PEGc#A!N~NKl$gD zEPWu=A;z{FNkhO*Dq3yC5w=)V5p_fpV5gd6+)OL8Y6VHCZKR_~rAs{_rW6#!(ra^d z;CVv`t%WjlqX-kxMc9abHj|H1caJ<{WB#vNwcQST!kQ%+Dy?yi2R0OwNUi(__uZh*h4bn@&{F)9*o#CA^>y z7n6x@o3cXjux`pvF0|@q8)ACFP?WlTZKnKrY+-(8ytEdvJCR`c(X&o+NzI#M#`e;5 zi=c=&$cyW;d1uV@J#R(_BKy|4*bWpk%Tp|)Q`D5DZzPv`ZSqttf@OND_jkH%Fi&f0 zp5+L|tb#RML4KakE3Dx_N>-7(>t}f~D;15*@(P4BC8%>;Q#J|i#5y3`V^Pc6w@%C<()97PoSJWnnrBclt=zOqJ< z*6vdAmq76rd19kGujNV4is(R(cWpG@+11yx*6-cC{;~LgxBsyLZ)f*FbaM~+YV>RT z4Y|5=KE~vQJ}0^Vhc?(in%g|&H_e%NAt~RKy_)V&;sJ{Py~xv61|}maD4?K__&kM< z!T|6&{%e0GpKZ#ky-qvGd%@HOP0cQfFDO_#8b_g|SVw&`dxV4Z@5&@QcV%lcp;caL zOyuycM_MfWe&;^te)m52f$oF;t2wg|JC76{pL^M|eB_~Vvvt2}pK8B;pZ>rjZ#2B# zaA?8do`kRFvblDo;S-ha`K`}v-P?IZ<^05)aiHKJmnf=Fm>Lpl^7^6{Y5(qiTrqCU zI#7Rj$=eNYHXMl`uYPYh5pKB_ZoL$4O|*3-*22~^c-gplWZ5`t9DU+I(G@n2gkKPb z=OW`$eA|ue5q$5uwG9quvtAa)l zXQ180p5Y3qUJ^uMEBir75QFt$sRMYHmAjp@;;@rF#}|O>+}zTzi#?w`OHD;-ofmuw z6TKy2RZ_aRu!pq1*oh~}Z(ls(qvu!gOA2~k6X{7zq$ehk?!Y45FGRZ5i<#u*y)Ilp z-rn0Af`6Ot_TduDPqt$Yo9~)+05?6iPd<&av1xKKw&Tjlau$0hjXZSr(*w}tQbvuH RlMWYd#doV=N09e`{{S*Vg#Q2l diff --git a/YakPanel-server/backend/app/services/site_service.py b/YakPanel-server/backend/app/services/site_service.py index c5c53fc0..933bcf2b 100644 --- a/YakPanel-server/backend/app/services/site_service.py +++ b/YakPanel-server/backend/app/services/site_service.py @@ -126,9 +126,10 @@ def _build_ssl_server_block( f" error_page 404 /404.html;\n" f" error_page 502 /502.html;\n" f" location ^~ /.well-known/acme-challenge/ {{\n" + f" root {root_path};\n" f' default_type "text/plain";\n' f" allow all;\n" - f" try_files $uri =404;\n" + f" access_log off;\n" f" }}\n" f"{redirect_block}\n" r" location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ {" + "\n" @@ -480,16 +481,17 @@ async def set_site_status(db: AsyncSession, site_id: int, status: int) -> dict: async def regenerate_site_vhost(db: AsyncSession, site_id: int) -> dict: - """Regenerate nginx vhost for a site (e.g. after redirect changes).""" + """Regenerate nginx vhost for a site (e.g. after redirect changes or before LE validation).""" result = await db.execute(select(Site).where(Site.id == site_id)) site = result.scalar_one_or_none() if not site: return {"status": False, "msg": "Site not found"} cfg = get_runtime_config() - vhost_path = os.path.join(cfg["setup_path"], "panel", "vhost", "nginx") - conf_path = os.path.join(vhost_path, f"{site.name}.conf") - if site.status != 1: - return {"status": True, "msg": "Site disabled, vhost not active"} + conf_path, disabled_path = _vhost_path(site.name) + if site.status == 1: + write_path = conf_path + else: + write_path = disabled_path if os.path.isfile(disabled_path) else conf_path panel_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) template_path = os.path.join(panel_root, "webserver", "templates", "nginx_site.conf") if not os.path.exists(template_path): @@ -507,7 +509,7 @@ async def regenerate_site_vhost(db: AsyncSession, site_id: int) -> dict: content = _render_vhost( template, server_names, site.path, cfg["www_logs"], site.name, php_ver, fhttps, redirects, le_hosts ) - write_file(conf_path, content) + 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") diff --git a/YakPanel-server/webserver/templates/nginx_site.conf b/YakPanel-server/webserver/templates/nginx_site.conf index d5e87dc1..62f9a373 100644 --- a/YakPanel-server/webserver/templates/nginx_site.conf +++ b/YakPanel-server/webserver/templates/nginx_site.conf @@ -8,11 +8,12 @@ server { error_page 404 /404.html; error_page 502 /502.html; - # ACME HTTP-01 (Let's Encrypt). Prefix match wins over regex locations. + # ACME HTTP-01 (Let's Encrypt). Prefix match beats regex; explicit root; no try_files so server error_page cannot mask failures. location ^~ /.well-known/acme-challenge/ { + root {ROOT_PATH}; default_type "text/plain"; allow all; - try_files $uri =404; + access_log off; } # Force HTTPS (skipped for ACME — see if block)