new changes
This commit is contained in:
Binary file not shown.
@@ -2,6 +2,7 @@
|
|||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import sys
|
||||||
from fastapi import APIRouter, Depends, HTTPException
|
from fastapi import APIRouter, Depends, HTTPException
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
from sqlalchemy import select
|
from sqlalchemy import select
|
||||||
@@ -17,15 +18,83 @@ from app.services.site_service import regenerate_site_vhost
|
|||||||
|
|
||||||
router = APIRouter(prefix="/ssl", tags=["ssl"])
|
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")
|
def _certbot_command() -> list[str] | None:
|
||||||
if w:
|
"""Resolve argv prefix to run certbot: [binary] or [python, -m, certbot]."""
|
||||||
return w
|
env = environment_with_system_path()
|
||||||
for p in ("/usr/bin/certbot", "/usr/local/bin/certbot"):
|
path_var = env.get("PATH", "")
|
||||||
if os.path.isfile(p):
|
|
||||||
return p
|
exe = getattr(sys, "executable", None) or ""
|
||||||
return "certbot"
|
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")
|
@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")
|
raise HTTPException(status_code=400, detail="Webroot must be under www_root or setup_path")
|
||||||
|
|
||||||
dom = body.domain.split(":")[0].strip()
|
dom = body.domain.split(":")[0].strip()
|
||||||
certbot_bin = _certbot_executable()
|
prefix = _certbot_command()
|
||||||
cmd = [
|
if not prefix:
|
||||||
certbot_bin,
|
raise HTTPException(status_code=500, detail=_certbot_missing_message())
|
||||||
|
|
||||||
|
cmd = prefix + [
|
||||||
"certonly",
|
"certonly",
|
||||||
"--webroot",
|
"--webroot",
|
||||||
"-w",
|
"-w",
|
||||||
@@ -93,19 +164,17 @@ async def ssl_request_cert(
|
|||||||
"--no-eff-email",
|
"--no-eff-email",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
env = environment_with_system_path()
|
||||||
try:
|
try:
|
||||||
proc = subprocess.run(
|
proc = subprocess.run(
|
||||||
cmd,
|
cmd,
|
||||||
capture_output=True,
|
capture_output=True,
|
||||||
text=True,
|
text=True,
|
||||||
timeout=180,
|
timeout=180,
|
||||||
env=environment_with_system_path(),
|
env=env,
|
||||||
)
|
)
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
raise HTTPException(
|
raise HTTPException(status_code=500, detail=_certbot_missing_message()) from None
|
||||||
status_code=500,
|
|
||||||
detail="certbot not found. Install it (e.g. apt install certbot) and ensure it is on PATH.",
|
|
||||||
) from None
|
|
||||||
except subprocess.TimeoutExpired:
|
except subprocess.TimeoutExpired:
|
||||||
raise HTTPException(status_code=500, detail="certbot timed out (180s)") from None
|
raise HTTPException(status_code=500, detail="certbot timed out (180s)") from None
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,9 @@ python-dotenv>=1.0.0
|
|||||||
redis>=5.0.0
|
redis>=5.0.0
|
||||||
celery>=5.3.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
|
# Utils
|
||||||
psutil>=5.9.0
|
psutil>=5.9.0
|
||||||
croniter>=2.0.0
|
croniter>=2.0.0
|
||||||
|
|||||||
Reference in New Issue
Block a user