new changes

This commit is contained in:
Niranjan
2026-04-07 10:29:29 +05:30
parent 09d0e2e033
commit 097087519b
3 changed files with 88 additions and 16 deletions

View File

@@ -2,6 +2,7 @@
import os
import shutil
import subprocess
import sys
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
@@ -17,15 +18,83 @@ from app.services.site_service import regenerate_site_vhost
router = APIRouter(prefix="/ssl", tags=["ssl"])
_CERTBOT_PATH_CANDIDATES = (
"/usr/bin/certbot",
"/usr/local/bin/certbot",
"/snap/bin/certbot",
)
def _certbot_executable() -> str:
w = shutil.which("certbot")
if w:
return w
for p in ("/usr/bin/certbot", "/usr/local/bin/certbot"):
if os.path.isfile(p):
return p
return "certbot"
def _certbot_command() -> list[str] | None:
"""Resolve argv prefix to run certbot: [binary] or [python, -m, certbot]."""
env = environment_with_system_path()
path_var = env.get("PATH", "")
exe = getattr(sys, "executable", None) or ""
if exe and os.path.isfile(exe):
try:
r = subprocess.run(
[exe, "-m", "certbot", "--version"],
capture_output=True,
text=True,
timeout=20,
env=env,
)
if r.returncode == 0:
return [exe, "-m", "certbot"]
except (FileNotFoundError, OSError, subprocess.TimeoutExpired):
pass
tried: list[str] = []
w = shutil.which("certbot", path=path_var)
if w and os.path.isfile(w):
tried.append(w)
for p in _CERTBOT_PATH_CANDIDATES:
if p not in tried and os.path.isfile(p):
tried.append(p)
for exe in tried:
try:
r = subprocess.run(
[exe, "--version"],
capture_output=True,
text=True,
timeout=15,
env=env,
)
if r.returncode == 0:
return [exe]
except (FileNotFoundError, OSError, subprocess.TimeoutExpired):
continue
for py_name in ("python3", "python"):
py = shutil.which(py_name, path=path_var)
if not py or not os.path.isfile(py):
continue
try:
r = subprocess.run(
[py, "-m", "certbot", "--version"],
capture_output=True,
text=True,
timeout=20,
env=env,
)
if r.returncode == 0:
return [py, "-m", "certbot"]
except (FileNotFoundError, OSError, subprocess.TimeoutExpired):
continue
return None
def _certbot_missing_message() -> str:
return (
"certbot is not installed or not reachable from the panel process. "
"On the server, run one of: apt install certbot | dnf install certbot | yum install certbot | snap install certbot. "
"Alternatively: pip install certbot (panel can use python3 -m certbot). "
"If certbot is already installed, ensure /usr/bin is on PATH for the YakPanel service."
)
@router.get("/domains")
@@ -75,9 +144,11 @@ 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()
certbot_bin = _certbot_executable()
cmd = [
certbot_bin,
prefix = _certbot_command()
if not prefix:
raise HTTPException(status_code=500, detail=_certbot_missing_message())
cmd = prefix + [
"certonly",
"--webroot",
"-w",
@@ -93,19 +164,17 @@ async def ssl_request_cert(
"--no-eff-email",
]
env = environment_with_system_path()
try:
proc = subprocess.run(
cmd,
capture_output=True,
text=True,
timeout=180,
env=environment_with_system_path(),
env=env,
)
except FileNotFoundError:
raise HTTPException(
status_code=500,
detail="certbot not found. Install it (e.g. apt install certbot) and ensure it is on PATH.",
) from None
raise HTTPException(status_code=500, detail=_certbot_missing_message()) from None
except subprocess.TimeoutExpired:
raise HTTPException(status_code=500, detail="certbot timed out (180s)") from None

View File

@@ -20,6 +20,9 @@ python-dotenv>=1.0.0
redis>=5.0.0
celery>=5.3.0
# Let's Encrypt (optional if system certbot/snap not used; enables python -m certbot from panel venv)
certbot>=3.0.0
# Utils
psutil>=5.9.0
croniter>=2.0.0