mirror of
https://github.com/usmannasir/cyberpanel.git
synced 2025-12-16 05:19:43 +01:00
Remove SECURITY_INSTALLATION.md and implement SSL reconciliation features in manageSSL module. Add new views and URLs for SSL reconciliation, enhance mobile responsiveness in templates, and update SSL utilities for improved functionality. Update upgrade script for scheduled SSL reconciliation tasks.
This commit is contained in:
1
plogical/management/__init__.py
Normal file
1
plogical/management/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
# Management commands for plogical module
|
||||
1
plogical/management/commands/__init__.py
Normal file
1
plogical/management/commands/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
# Management commands for plogical module
|
||||
98
plogical/management/commands/ssl_reconcile.py
Normal file
98
plogical/management/commands/ssl_reconcile.py
Normal file
@@ -0,0 +1,98 @@
|
||||
#!/usr/local/CyberCP/bin/python
|
||||
"""
|
||||
Django management command for SSL reconciliation
|
||||
Usage: python manage.py ssl_reconcile [--all|--domain <domain>]
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import django
|
||||
|
||||
# Add CyberPanel to Python path
|
||||
sys.path.append('/usr/local/CyberCP')
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "CyberCP.settings")
|
||||
django.setup()
|
||||
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from plogical.sslReconcile import SSLReconcile
|
||||
from plogical.CyberCPLogFileWriter import CyberCPLogFileWriter as logging
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Reconcile SSL certificates and ACME challenge configurations'
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument(
|
||||
'--all',
|
||||
action='store_true',
|
||||
help='Reconcile SSL for all domains',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--domain',
|
||||
type=str,
|
||||
help='Reconcile SSL for a specific domain',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--fix-acme',
|
||||
action='store_true',
|
||||
help='Fix ACME challenge contexts for all domains',
|
||||
)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
if options['all']:
|
||||
self.stdout.write('Starting SSL reconciliation for all domains...')
|
||||
try:
|
||||
success = SSLReconcile.reconcile_all()
|
||||
if success:
|
||||
self.stdout.write(
|
||||
self.style.SUCCESS('SSL reconciliation completed successfully!')
|
||||
)
|
||||
else:
|
||||
self.stdout.write(
|
||||
self.style.ERROR('SSL reconciliation failed. Check logs for details.')
|
||||
)
|
||||
except Exception as e:
|
||||
raise CommandError(f'SSL reconciliation failed: {str(e)}')
|
||||
|
||||
elif options['domain']:
|
||||
domain = options['domain']
|
||||
self.stdout.write(f'Starting SSL reconciliation for domain: {domain}')
|
||||
try:
|
||||
success = SSLReconcile.reconcile_domain(domain)
|
||||
if success:
|
||||
self.stdout.write(
|
||||
self.style.SUCCESS(f'SSL reconciliation completed for {domain}!')
|
||||
)
|
||||
else:
|
||||
self.stdout.write(
|
||||
self.style.ERROR(f'SSL reconciliation failed for {domain}. Check logs for details.')
|
||||
)
|
||||
except Exception as e:
|
||||
raise CommandError(f'SSL reconciliation failed for {domain}: {str(e)}')
|
||||
|
||||
elif options['fix_acme']:
|
||||
self.stdout.write('Fixing ACME challenge contexts for all domains...')
|
||||
try:
|
||||
from plogical.sslUtilities import sslUtilities
|
||||
from websiteFunctions.models import Websites
|
||||
|
||||
fixed_count = 0
|
||||
for website in Websites.objects.all():
|
||||
if sslUtilities.fix_acme_challenge_context(website.domain):
|
||||
fixed_count += 1
|
||||
self.stdout.write(f'Fixed ACME context for: {website.domain}')
|
||||
|
||||
self.stdout.write(
|
||||
self.style.SUCCESS(f'Fixed ACME challenge contexts for {fixed_count} domains!')
|
||||
)
|
||||
except Exception as e:
|
||||
raise CommandError(f'Failed to fix ACME contexts: {str(e)}')
|
||||
|
||||
else:
|
||||
self.stdout.write(
|
||||
self.style.WARNING('Please specify --all, --domain <domain>, or --fix-acme')
|
||||
)
|
||||
self.stdout.write('Usage examples:')
|
||||
self.stdout.write(' python manage.py ssl_reconcile --all')
|
||||
self.stdout.write(' python manage.py ssl_reconcile --domain example.com')
|
||||
self.stdout.write(' python manage.py ssl_reconcile --fix-acme')
|
||||
419
plogical/sslReconcile.py
Normal file
419
plogical/sslReconcile.py
Normal file
@@ -0,0 +1,419 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
SSL Reconciliation Module for CyberPanel
|
||||
Integrates the acme_reconcile_all.sh functionality into CyberPanel core
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import shlex
|
||||
import hashlib
|
||||
from plogical.CyberCPLogFileWriter import CyberCPLogFileWriter as logging
|
||||
from plogical.processUtilities import ProcessUtilities
|
||||
from plogical import installUtilities
|
||||
|
||||
|
||||
class SSLReconcile:
|
||||
"""SSL Certificate Reconciliation and Management"""
|
||||
|
||||
VHOSTS_DIR = "/usr/local/lsws/conf/vhosts"
|
||||
VHROOT_BASE = "/home"
|
||||
ACME_HOME = "/root/.acme.sh"
|
||||
RELOAD_CMD = "systemctl restart lsws"
|
||||
|
||||
@staticmethod
|
||||
def trim(text):
|
||||
"""Trim whitespace from text"""
|
||||
return text.strip()
|
||||
|
||||
@staticmethod
|
||||
def pick_lineage_conf(vhost):
|
||||
"""Pick the appropriate acme.sh lineage configuration file"""
|
||||
ecc_conf = f"{SSLReconcile.ACME_HOME}/{vhost}_ecc/{vhost}.conf"
|
||||
reg_conf = f"{SSLReconcile.ACME_HOME}/{vhost}/{vhost}.conf"
|
||||
|
||||
if os.path.exists(ecc_conf):
|
||||
return ecc_conf
|
||||
elif os.path.exists(reg_conf):
|
||||
return reg_conf
|
||||
else:
|
||||
# Create ECC lineage directory and file
|
||||
os.makedirs(f"{SSLReconcile.ACME_HOME}/{vhost}_ecc", exist_ok=True)
|
||||
with open(ecc_conf, 'w') as f:
|
||||
f.write('')
|
||||
return ecc_conf
|
||||
|
||||
@staticmethod
|
||||
def set_kv(config_file, key, value):
|
||||
"""Set key-value pair in configuration file"""
|
||||
try:
|
||||
# Read existing content
|
||||
if os.path.exists(config_file):
|
||||
with open(config_file, 'r') as f:
|
||||
lines = f.readlines()
|
||||
else:
|
||||
lines = []
|
||||
|
||||
# Check if key exists and update or add
|
||||
key_found = False
|
||||
for i, line in enumerate(lines):
|
||||
if line.startswith(f"{key}="):
|
||||
lines[i] = f"{key}='{value}'\n"
|
||||
key_found = True
|
||||
break
|
||||
|
||||
if not key_found:
|
||||
lines.append(f"{key}='{value}'\n")
|
||||
|
||||
# Write back to file
|
||||
with open(config_file, 'w') as f:
|
||||
f.writelines(lines)
|
||||
|
||||
except Exception as e:
|
||||
logging.writeToFile(f"Error setting {key}={value} in {config_file}: {str(e)}")
|
||||
raise
|
||||
|
||||
@staticmethod
|
||||
def issuer_cn(pem_file):
|
||||
"""Get issuer CN from certificate"""
|
||||
if not os.path.exists(pem_file):
|
||||
return ""
|
||||
|
||||
try:
|
||||
cmd = f"openssl x509 -in {pem_file} -noout -issuer"
|
||||
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
|
||||
if result.returncode == 0:
|
||||
issuer_line = result.stdout.strip()
|
||||
# Extract CN from issuer line
|
||||
cn_match = re.search(r'CN=([^,]+)', issuer_line)
|
||||
if cn_match:
|
||||
return cn_match.group(1)
|
||||
except Exception as e:
|
||||
logging.writeToFile(f"Error getting issuer CN from {pem_file}: {str(e)}")
|
||||
|
||||
return ""
|
||||
|
||||
@staticmethod
|
||||
def sha256fp(pem_file):
|
||||
"""Get SHA256 fingerprint of certificate"""
|
||||
if not os.path.exists(pem_file):
|
||||
return ""
|
||||
|
||||
try:
|
||||
cmd = f"openssl x509 -in {pem_file} -noout -fingerprint -sha256"
|
||||
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
|
||||
if result.returncode == 0:
|
||||
fingerprint_line = result.stdout.strip()
|
||||
# Extract fingerprint value
|
||||
fp_match = re.search(r'=([A-F0-9:]+)', fingerprint_line)
|
||||
if fp_match:
|
||||
return fp_match.group(1)
|
||||
except Exception as e:
|
||||
logging.writeToFile(f"Error getting SHA256 fingerprint from {pem_file}: {str(e)}")
|
||||
|
||||
return ""
|
||||
|
||||
@staticmethod
|
||||
def fix_context_location(vconf_path, docroot):
|
||||
"""Fix ACME challenge context location in vhost configuration"""
|
||||
try:
|
||||
# Read current configuration
|
||||
with open(vconf_path, 'r') as f:
|
||||
content = f.read()
|
||||
|
||||
want_uri = '/.well-known/acme-challenge/'
|
||||
want_loc = f"{docroot}/.well-known/acme-challenge/"
|
||||
|
||||
# Create challenge directory
|
||||
os.makedirs(want_loc, exist_ok=True)
|
||||
os.chmod(docroot, 0o755)
|
||||
os.chmod(f"{docroot}/.well-known", 0o755)
|
||||
os.chmod(want_loc, 0o755)
|
||||
|
||||
# Check if context already exists
|
||||
context_pattern = r'context\s+/.well-known/acme-challenge/?\s*{'
|
||||
if re.search(context_pattern, content):
|
||||
# Update existing context
|
||||
content = re.sub(
|
||||
r'(context\s+)/.well-known/acme-challenge/?(\s*{)',
|
||||
rf'\1{want_uri}\2',
|
||||
content
|
||||
)
|
||||
content = re.sub(
|
||||
r'(location\s+).*acme-challenge/?',
|
||||
rf'\1{want_loc}',
|
||||
content
|
||||
)
|
||||
else:
|
||||
# Add new context
|
||||
context_block = f"""
|
||||
|
||||
context {want_uri} {{
|
||||
location {want_loc}
|
||||
addDefaultCharset off
|
||||
}}
|
||||
"""
|
||||
content += context_block
|
||||
|
||||
# Write updated configuration
|
||||
with open(vconf_path, 'w') as f:
|
||||
f.write(content)
|
||||
|
||||
logging.writeToFile(f"Fixed ACME challenge context for {vconf_path}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logging.writeToFile(f"Error fixing context location for {vconf_path}: {str(e)}")
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def needs_force_issue(vhost, dconf_path, docroot, live_fullchain):
|
||||
"""Determine if certificate needs to be force re-issued"""
|
||||
try:
|
||||
# Read lineage configuration
|
||||
le_api = ""
|
||||
webroot = ""
|
||||
|
||||
if os.path.exists(dconf_path):
|
||||
with open(dconf_path, 'r') as f:
|
||||
for line in f:
|
||||
if line.startswith("Le_API="):
|
||||
le_api = line.split("'")[1] if "'" in line else ""
|
||||
elif line.startswith("Le_Webroot="):
|
||||
webroot = line.split("'")[1] if "'" in line else ""
|
||||
|
||||
# Check for staging API
|
||||
if 'acme-staging' in le_api:
|
||||
return True
|
||||
|
||||
# Check for wrong webroot
|
||||
if webroot and webroot != docroot:
|
||||
return True
|
||||
|
||||
# Check if live files are missing
|
||||
if not os.path.exists(live_fullchain):
|
||||
return True
|
||||
|
||||
# Check for fingerprint mismatch
|
||||
acme_chain = ""
|
||||
ecc_chain = f"{SSLReconcile.ACME_HOME}/{vhost}_ecc/fullchain.cer"
|
||||
reg_chain = f"{SSLReconcile.ACME_HOME}/{vhost}/fullchain.cer"
|
||||
|
||||
if os.path.exists(ecc_chain):
|
||||
acme_chain = ecc_chain
|
||||
elif os.path.exists(reg_chain):
|
||||
acme_chain = reg_chain
|
||||
|
||||
if acme_chain:
|
||||
acme_fp = SSLReconcile.sha256fp(acme_chain)
|
||||
live_fp = SSLReconcile.sha256fp(live_fullchain)
|
||||
if acme_fp and live_fp and acme_fp != live_fp:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
logging.writeToFile(f"Error checking force issue for {vhost}: {str(e)}")
|
||||
return True # Force issue on error
|
||||
|
||||
@staticmethod
|
||||
def reconcile_one(vconf_path):
|
||||
"""Reconcile SSL configuration for a single vhost"""
|
||||
try:
|
||||
vhost = os.path.basename(os.path.dirname(vconf_path))
|
||||
|
||||
# Read docRoot from vhost configuration
|
||||
docroot = ""
|
||||
with open(vconf_path, 'r') as f:
|
||||
for line in f:
|
||||
if re.match(r'^\s*docRoot\s+', line):
|
||||
docroot = SSLReconcile.trim(line.split()[1])
|
||||
break
|
||||
|
||||
if not docroot:
|
||||
logging.writeToFile(f"[skip] {vhost}: no docRoot")
|
||||
return False
|
||||
|
||||
# Resolve $VH_ROOT variable
|
||||
if docroot.startswith('$VH_ROOT/'):
|
||||
docroot = docroot.replace('$VH_ROOT', f"{SSLReconcile.VHROOT_BASE}/{vhost}")
|
||||
|
||||
# 1) Fix context location
|
||||
if not SSLReconcile.fix_context_location(vconf_path, docroot):
|
||||
return False
|
||||
|
||||
# 2) Configure lineage
|
||||
dconf_path = SSLReconcile.pick_lineage_conf(vhost)
|
||||
SSLReconcile.set_kv(dconf_path, "Le_Webroot", docroot)
|
||||
SSLReconcile.set_kv(dconf_path, "Le_API", "https://acme-v02.api.letsencrypt.org/directory")
|
||||
|
||||
# 3) Define live targets
|
||||
live_dir = f"/etc/letsencrypt/live/{vhost}"
|
||||
live_key = f"{live_dir}/privkey.pem"
|
||||
live_full = f"{live_dir}/fullchain.pem"
|
||||
live_cert = f"{live_dir}/cert.pem"
|
||||
os.makedirs(live_dir, exist_ok=True)
|
||||
|
||||
# 4) Check if force issue is needed
|
||||
if SSLReconcile.needs_force_issue(vhost, dconf_path, docroot, live_full):
|
||||
# Build SAN set
|
||||
alt_domains = []
|
||||
if os.path.exists(dconf_path):
|
||||
with open(dconf_path, 'r') as f:
|
||||
for line in f:
|
||||
if line.startswith("Le_Alt="):
|
||||
alt = line.split("'")[1] if "'" in line else ""
|
||||
if alt:
|
||||
alt_domains.append(alt)
|
||||
|
||||
# Add www subdomain for base domains
|
||||
if not alt_domains and not vhost.startswith('www.'):
|
||||
alt_domains.append(f"www.{vhost}")
|
||||
|
||||
# Issue certificate
|
||||
cmd_parts = [f"{SSLReconcile.ACME_HOME}/acme.sh", "--issue", "-d", vhost]
|
||||
for alt in alt_domains:
|
||||
cmd_parts.extend(["-d", alt])
|
||||
cmd_parts.extend(["-w", docroot, "--ecc", "--server", "letsencrypt", "--force"])
|
||||
|
||||
result = subprocess.run(cmd_parts, capture_output=True, text=True)
|
||||
if result.returncode != 0:
|
||||
logging.writeToFile(f"Certificate issuance failed for {vhost}: {result.stderr}")
|
||||
return False
|
||||
|
||||
logging.writeToFile(f"[issue] {vhost} certificate issued")
|
||||
|
||||
# 5) Set installation targets
|
||||
SSLReconcile.set_kv(dconf_path, "Le_RealKeyPath", live_key)
|
||||
SSLReconcile.set_kv(dconf_path, "Le_RealFullChainPath", live_full)
|
||||
SSLReconcile.set_kv(dconf_path, "Le_RealCertPath", live_cert)
|
||||
|
||||
# 6) Install certificate if needed
|
||||
if (not os.path.exists(live_full) or not os.path.exists(live_key) or
|
||||
os.path.getsize(live_full) == 0 or os.path.getsize(live_key) == 0):
|
||||
|
||||
cmd_parts = [
|
||||
f"{SSLReconcile.ACME_HOME}/acme.sh", "--install-cert", "-d", vhost, "--ecc",
|
||||
"--key-file", live_key,
|
||||
"--fullchain-file", live_full,
|
||||
"--cert-file", live_cert,
|
||||
"--reloadcmd", SSLReconcile.RELOAD_CMD
|
||||
]
|
||||
|
||||
result = subprocess.run(cmd_parts, capture_output=True, text=True)
|
||||
if result.returncode == 0:
|
||||
logging.writeToFile(f"[install] {vhost} -> {live_dir}")
|
||||
else:
|
||||
logging.writeToFile(f"Certificate installation failed for {vhost}: {result.stderr}")
|
||||
return False
|
||||
else:
|
||||
# Check if sync is needed
|
||||
acme_chain = ""
|
||||
ecc_chain = f"{SSLReconcile.ACME_HOME}/{vhost}_ecc/fullchain.cer"
|
||||
reg_chain = f"{SSLReconcile.ACME_HOME}/{vhost}/fullchain.cer"
|
||||
|
||||
if os.path.exists(ecc_chain):
|
||||
acme_chain = ecc_chain
|
||||
elif os.path.exists(reg_chain):
|
||||
acme_chain = reg_chain
|
||||
|
||||
if acme_chain:
|
||||
acme_fp = SSLReconcile.sha256fp(acme_chain)
|
||||
live_fp = SSLReconcile.sha256fp(live_full)
|
||||
if acme_fp and live_fp and acme_fp != live_fp:
|
||||
# Sync needed
|
||||
cmd_parts = [
|
||||
f"{SSLReconcile.ACME_HOME}/acme.sh", "--install-cert", "-d", vhost, "--ecc",
|
||||
"--key-file", live_key,
|
||||
"--fullchain-file", live_full,
|
||||
"--cert-file", live_cert,
|
||||
"--reloadcmd", SSLReconcile.RELOAD_CMD
|
||||
]
|
||||
|
||||
result = subprocess.run(cmd_parts, capture_output=True, text=True)
|
||||
if result.returncode == 0:
|
||||
logging.writeToFile(f"[sync] {vhost} live files updated")
|
||||
else:
|
||||
logging.writeToFile(f"Certificate sync failed for {vhost}: {result.stderr}")
|
||||
return False
|
||||
else:
|
||||
logging.writeToFile(f"[ok] {vhost} unchanged")
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logging.writeToFile(f"Error reconciling {vconf_path}: {str(e)}")
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def reconcile_all():
|
||||
"""Reconcile SSL configuration for all vhosts"""
|
||||
try:
|
||||
changed = 0
|
||||
vhosts_dir = SSLReconcile.VHOSTS_DIR
|
||||
|
||||
if not os.path.exists(vhosts_dir):
|
||||
logging.writeToFile(f"VHosts directory not found: {vhosts_dir}")
|
||||
return False
|
||||
|
||||
# Process all vhost configurations
|
||||
for vhost_name in os.listdir(vhosts_dir):
|
||||
vconf_path = os.path.join(vhosts_dir, vhost_name, "vhost.conf")
|
||||
if os.path.exists(vconf_path):
|
||||
if SSLReconcile.reconcile_one(vconf_path):
|
||||
changed += 1
|
||||
|
||||
# Restart LiteSpeed
|
||||
try:
|
||||
subprocess.run(SSLReconcile.RELOAD_CMD, shell=True, check=True)
|
||||
logging.writeToFile(f"LiteSpeed restarted successfully")
|
||||
except subprocess.CalledProcessError as e:
|
||||
logging.writeToFile(f"Failed to restart LiteSpeed: {str(e)}")
|
||||
|
||||
logging.writeToFile(f"[done] processed={changed} vhosts")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logging.writeToFile(f"Error in reconcile_all: {str(e)}")
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def reconcile_domain(domain):
|
||||
"""Reconcile SSL configuration for a specific domain"""
|
||||
try:
|
||||
vconf_path = os.path.join(SSLReconcile.VHOSTS_DIR, domain, "vhost.conf")
|
||||
|
||||
if not os.path.exists(vconf_path):
|
||||
logging.writeToFile(f"VHost configuration not found for {domain}")
|
||||
return False
|
||||
|
||||
if SSLReconcile.reconcile_one(vconf_path):
|
||||
# Restart LiteSpeed
|
||||
try:
|
||||
subprocess.run(SSLReconcile.RELOAD_CMD, shell=True, check=True)
|
||||
logging.writeToFile(f"LiteSpeed restarted successfully for {domain}")
|
||||
except subprocess.CalledProcessError as e:
|
||||
logging.writeToFile(f"Failed to restart LiteSpeed for {domain}: {str(e)}")
|
||||
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
logging.writeToFile(f"Error reconciling domain {domain}: {str(e)}")
|
||||
return False
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
if sys.argv[1] == "--all":
|
||||
SSLReconcile.reconcile_all()
|
||||
elif sys.argv[1] == "--domain" and len(sys.argv) > 2:
|
||||
SSLReconcile.reconcile_domain(sys.argv[2])
|
||||
else:
|
||||
print("Usage: python sslReconcile.py [--all|--domain <domain>]")
|
||||
else:
|
||||
SSLReconcile.reconcile_all()
|
||||
@@ -997,4 +997,58 @@ def issueSSLForDomain(domain, adminEmail, sslpath, aliasDomain=None, isHostname=
|
||||
return [0, "210 Failed to install SSL for domain. [issueSSLForDomain]"]
|
||||
|
||||
except BaseException as msg:
|
||||
return [0, "347 " + str(msg) + " [issueSSLForDomain]"]
|
||||
return [0, "347 " + str(msg) + " [issueSSLForDomain]"]
|
||||
|
||||
@staticmethod
|
||||
def reconcile_ssl_all():
|
||||
"""Reconcile SSL configuration for all domains using the new reconciliation module"""
|
||||
try:
|
||||
from plogical.sslReconcile import SSLReconcile
|
||||
return SSLReconcile.reconcile_all()
|
||||
except Exception as e:
|
||||
logging.CyberCPLogFileWriter.writeToFile(f"Error in reconcile_ssl_all: {str(e)}")
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def reconcile_ssl_domain(domain):
|
||||
"""Reconcile SSL configuration for a specific domain using the new reconciliation module"""
|
||||
try:
|
||||
from plogical.sslReconcile import SSLReconcile
|
||||
return SSLReconcile.reconcile_domain(domain)
|
||||
except Exception as e:
|
||||
logging.CyberCPLogFileWriter.writeToFile(f"Error in reconcile_ssl_domain for {domain}: {str(e)}")
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def fix_acme_challenge_context(virtualHostName):
|
||||
"""Fix ACME challenge context for a specific domain"""
|
||||
try:
|
||||
from plogical.sslReconcile import SSLReconcile
|
||||
|
||||
vconf_path = f"{sslUtilities.Server_root}/conf/vhosts/{virtualHostName}/vhost.conf"
|
||||
|
||||
if not os.path.exists(vconf_path):
|
||||
logging.CyberCPLogFileWriter.writeToFile(f"VHost configuration not found: {vconf_path}")
|
||||
return False
|
||||
|
||||
# Read docRoot from vhost configuration
|
||||
docroot = ""
|
||||
with open(vconf_path, 'r') as f:
|
||||
for line in f:
|
||||
if line.strip().startswith('docRoot'):
|
||||
docroot = line.split()[1]
|
||||
break
|
||||
|
||||
if not docroot:
|
||||
logging.CyberCPLogFileWriter.writeToFile(f"No docRoot found for {virtualHostName}")
|
||||
return False
|
||||
|
||||
# Resolve $VH_ROOT variable
|
||||
if docroot.startswith('$VH_ROOT/'):
|
||||
docroot = docroot.replace('$VH_ROOT', f"/home/{virtualHostName}")
|
||||
|
||||
return SSLReconcile.fix_context_location(vconf_path, docroot)
|
||||
|
||||
except Exception as e:
|
||||
logging.CyberCPLogFileWriter.writeToFile(f"Error fixing ACME challenge context for {virtualHostName}: {str(e)}")
|
||||
return False
|
||||
@@ -3789,6 +3789,7 @@ vmail
|
||||
0 2 * * * /usr/local/CyberCP/bin/python /usr/local/CyberCP/plogical/upgradeCritical.py >/dev/null 2>&1
|
||||
0 0 * * 4 /usr/local/CyberCP/bin/python /usr/local/CyberCP/plogical/renew.py >/dev/null 2>&1
|
||||
7 0 * * * "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" > /dev/null
|
||||
0 1 * * * /usr/local/CyberCP/bin/python /usr/local/CyberCP/manage.py ssl_reconcile --all >/dev/null 2>&1
|
||||
*/3 * * * * if ! find /home/*/public_html/ -maxdepth 2 -type f -newer /usr/local/lsws/cgid -name '.htaccess' -exec false {} +; then /usr/local/lsws/bin/lswsctrl restart; fi
|
||||
* * * * * /usr/local/CyberCP/bin/python /usr/local/CyberCP/manage.py run_scheduled_scans >/usr/local/lscp/logs/scheduled_scans.log 2>&1
|
||||
"""
|
||||
@@ -3838,6 +3839,7 @@ vmail
|
||||
0 2 * * * /usr/local/CyberCP/bin/python /usr/local/CyberCP/plogical/upgradeCritical.py >/dev/null 2>&1
|
||||
0 0 * * 4 /usr/local/CyberCP/bin/python /usr/local/CyberCP/plogical/renew.py >/dev/null 2>&1
|
||||
7 0 * * * "/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh" > /dev/null
|
||||
0 1 * * * /usr/local/CyberCP/bin/python /usr/local/CyberCP/manage.py ssl_reconcile --all >/dev/null 2>&1
|
||||
0 0 * * * /usr/local/CyberCP/bin/python /usr/local/CyberCP/IncBackups/IncScheduler.py Daily
|
||||
0 0 * * 0 /usr/local/CyberCP/bin/python /usr/local/CyberCP/IncBackups/IncScheduler.py Weekly
|
||||
* * * * * /usr/local/CyberCP/bin/python /usr/local/CyberCP/manage.py run_scheduled_scans >/usr/local/lscp/logs/scheduled_scans.log 2>&1
|
||||
|
||||
@@ -74,7 +74,7 @@ rewrite {
|
||||
}
|
||||
|
||||
context /.well-known/acme-challenge {
|
||||
location /usr/local/lsws/Example/html/.well-known/acme-challenge
|
||||
location $VH_ROOT/public_html/.well-known/acme-challenge
|
||||
allowBrowse 1
|
||||
|
||||
rewrite {
|
||||
@@ -158,16 +158,16 @@ extprocessor {externalApp} {
|
||||
}
|
||||
|
||||
rewrite {
|
||||
enable 1
|
||||
enable 1
|
||||
autoLoadHtaccess 1
|
||||
}
|
||||
|
||||
context /.well-known/acme-challenge {
|
||||
location /usr/local/lsws/Example/html/.well-known/acme-challenge
|
||||
location $VH_ROOT/public_html/.well-known/acme-challenge
|
||||
allowBrowse 1
|
||||
|
||||
rewrite {
|
||||
enable 0
|
||||
enable 0
|
||||
}
|
||||
addDefaultCharset off
|
||||
|
||||
@@ -185,7 +185,7 @@ context /.well-known/acme-challenge {
|
||||
ServerAdmin {administratorEmail}
|
||||
SuexecUserGroup {externalApp} {externalApp}
|
||||
DocumentRoot /home/{virtualHostName}/public_html
|
||||
Alias /.well-known/acme-challenge /usr/local/lsws/Example/html/.well-known/acme-challenge
|
||||
Alias /.well-known/acme-challenge /home/{virtualHostName}/public_html/.well-known/acme-challenge
|
||||
CustomLog /home/{virtualHostName}/logs/{virtualHostName}.access_log combined
|
||||
AddHandler application/x-httpd-php{php} .php .php7 .phtml
|
||||
<IfModule LiteSpeed>
|
||||
@@ -203,7 +203,7 @@ context /.well-known/acme-challenge {
|
||||
ServerAdmin {administratorEmail}
|
||||
SuexecUserGroup {externalApp} {externalApp}
|
||||
DocumentRoot {path}
|
||||
Alias /.well-known/acme-challenge /usr/local/lsws/Example/html/.well-known/acme-challenge
|
||||
Alias /.well-known/acme-challenge /home/{virtualHostName}/public_html/.well-known/acme-challenge
|
||||
CustomLog /home/{masterDomain}/logs/{masterDomain}.access_log combined
|
||||
AddHandler application/x-httpd-php{php} .php .php7 .phtml
|
||||
<IfModule LiteSpeed>
|
||||
@@ -220,7 +220,7 @@ context /.well-known/acme-challenge {
|
||||
ServerAdmin {administratorEmail}
|
||||
SuexecUserGroup {externalApp} {externalApp}
|
||||
DocumentRoot /home/{virtualHostName}/public_html/
|
||||
Alias /.well-known/acme-challenge /usr/local/lsws/Example/html/.well-known/acme-challenge
|
||||
Alias /.well-known/acme-challenge /home/{virtualHostName}/public_html/.well-known/acme-challenge
|
||||
<Proxy "unix:{sockPath}{virtualHostName}.sock|fcgi://php-fpm-{externalApp}">
|
||||
ProxySet disablereuse=off
|
||||
</proxy>
|
||||
@@ -371,11 +371,11 @@ accesslog $VH_ROOT/logs/$VH_NAME.access_log {
|
||||
}
|
||||
|
||||
context /.well-known/acme-challenge {
|
||||
location /usr/local/lsws/Example/html/.well-known/acme-challenge
|
||||
location $VH_ROOT/public_html/.well-known/acme-challenge
|
||||
allowBrowse 1
|
||||
|
||||
rewrite {
|
||||
enable 0
|
||||
enable 0
|
||||
}
|
||||
addDefaultCharset off
|
||||
|
||||
|
||||
Reference in New Issue
Block a user