Fix PMA gateway LE cert domain resolution

main
Anthony 2026-02-26 20:30:22 +08:00
parent 20d3d016c2
commit 7dd77c6ccd
2 changed files with 90 additions and 30 deletions

View File

@ -1029,7 +1029,7 @@ actions:
user: root
commands:
- bash /home/litespeed/mbmanager/scripts/dbreset.sh >/dev/null
- bash /home/litespeed/mbmanager/pma-gateway/create_pma_gateway.sh --validity="${settings.validity}" --slug="${settings.slug}"
- bash /home/litespeed/mbmanager/pma-gateway/create_pma_gateway.sh --validity="${settings.validity}" --slug="${settings.slug}" --cert-domain="${env.domain}" --email="${user.email}"
- return:
type: info
message: "Gateway URL: ${response.out}"

View File

@ -4,19 +4,23 @@
# Script: create_pma_gateway.sh
# Purpose: Create a time-limited gateway URL for phpMyAdmin on Virtuozzo LLSMP.
# Uses Let's Encrypt cert in the dedicated phpMyAdmin vhost (port 8443).
# Dynamically detects Let's Encrypt certificate paths.
# Usage: create_pma_gateway.sh --validity=30 [--slug=myalias]
# Resolves certs for the environment domain and can issue cert on demand.
# Usage: create_pma_gateway.sh --validity=30 [--slug=myalias] [--cert-domain=env.example.com] [--email=admin@example.com]
# Outputs: Prints the generated URL.
# ==============================================================================
set -euo pipefail
SLUG=""
VALIDITY=30 # minutes
CERT_DOMAIN=""
CONTACT_EMAIL=""
for arg in "$@"; do
case $arg in
--slug=*) SLUG="${arg#*=}" ;;
--validity=*) VALIDITY="${arg#*=}" ;;
--cert-domain=*) CERT_DOMAIN="${arg#*=}" ;;
--email=*) CONTACT_EMAIL="${arg#*=}" ;;
*) echo "ERROR: Unknown argument $arg"; exit 1 ;;
esac
done
@ -25,13 +29,30 @@ if [[ -z "$SLUG" ]]; then
SLUG=$(openssl rand -hex 4) # 8-char random
fi
# Determine environment public host (no node prefix) - used for certificate lookup and URL
if [[ -n "${JELASTIC_ENV_DOMAIN:-}" ]]; then
ENV_HOST="$JELASTIC_ENV_DOMAIN"
else
ENV_HOST=$(hostname -f)
ENV_HOST=${ENV_HOST#node*-} # strip nodeXXXX-
# Reject unresolved template placeholders if they are passed through literally.
if [[ "$CERT_DOMAIN" == *'${'* ]]; then
CERT_DOMAIN=""
fi
if [[ "$CONTACT_EMAIL" == *'${'* ]]; then
CONTACT_EMAIL=""
fi
# Prefer explicit cert domain and fallback to Jelastic environment domain.
if [[ -z "$CERT_DOMAIN" ]]; then
if [[ -n "${JELASTIC_ENV_DOMAIN:-}" ]]; then
CERT_DOMAIN="$JELASTIC_ENV_DOMAIN"
else
CERT_DOMAIN=$(hostname -f)
CERT_DOMAIN=${CERT_DOMAIN#node*-} # strip nodeXXXX-
fi
fi
# Fallback for email when not explicitly passed.
if [[ -z "$CONTACT_EMAIL" ]] && [[ -n "${JELASTIC_USER_EMAIL:-}" ]]; then
CONTACT_EMAIL="$JELASTIC_USER_EMAIL"
fi
ENV_HOST="$CERT_DOMAIN"
PMADB_DIR="/usr/share/phpMyAdmin"
GATEWAY_FILE="$PMADB_DIR/access-db-$SLUG.php"
@ -57,41 +78,80 @@ token="$base.$mac"
VHOST_CONFIG="/usr/share/phpMyAdmin/vhost.conf"
NEEDS_RESTART=0
# --- MODIFICATION: Dynamically determine Let's Encrypt Cert Paths ---
# --- Let's Encrypt certificate resolution for ENV_HOST ---
LE_LIVE_DIR="/etc/letsencrypt/live"
LE_CERT_DIR=""
# Attempt to find the directory matching ENV_HOST
if [[ -d "$LE_LIVE_DIR/$ENV_HOST" ]]; then
# Attempt exact match first.
if [[ -d "$LE_LIVE_DIR/$ENV_HOST" ]] && [[ -f "$LE_LIVE_DIR/$ENV_HOST/privkey.pem" ]] && [[ -f "$LE_LIVE_DIR/$ENV_HOST/fullchain.pem" ]]; then
LE_CERT_DIR="$LE_LIVE_DIR/$ENV_HOST"
echo "INFO: Found Let's Encrypt cert directory matching ENV_HOST: $LE_CERT_DIR" >&2
else
# If not found, iterate through subdirectories in $LE_LIVE_DIR to find a suitable one
# This is a fallback, assuming there might be only one relevant cert directory.
# Or, you could add more logic here to match patterns if needed.
for dir in "$LE_LIVE_DIR"/*/; do
if [[ -d "$dir" ]]; then
candidate_dir=$(basename "$dir")
echo "INFO: Checking Let's Encrypt cert directory: $candidate_dir" >&2
# Add more specific checks here if multiple domains exist and you need to pick the right one.
# For now, just pick the first one that has the required files.
if [[ -f "$dir/privkey.pem" ]] && [[ -f "$dir/fullchain.pem" ]]; then
LE_CERT_DIR="$dir"
echo "INFO: Found Let's Encrypt cert directory with required files: $LE_CERT_DIR" >&2
break
fi
echo "INFO: Found exact Let's Encrypt cert directory: $LE_CERT_DIR" >&2
fi
# Then try certbot-suffixed directories (e.g., domain-0001).
if [[ -z "$LE_CERT_DIR" ]]; then
for dir in "$LE_LIVE_DIR/$ENV_HOST"-*/; do
if [[ -d "$dir" ]] && [[ -f "$dir/privkey.pem" ]] && [[ -f "$dir/fullchain.pem" ]]; then
LE_CERT_DIR="${dir%/}"
echo "INFO: Found suffixed Let's Encrypt cert directory: $LE_CERT_DIR" >&2
break
fi
done
fi
# If no cert exists yet, attempt one-time issuance for ENV_HOST.
if [[ -z "$LE_CERT_DIR" ]]; then
echo "WARNING: No Let's Encrypt certificate found for '$ENV_HOST'. Attempting to issue one now..." >&2
CERTBOT_CMD=""
if command -v certbot >/dev/null 2>&1; then
CERTBOT_CMD="certbot"
elif [[ -x "/opt/certbot/certbot-auto" ]]; then
CERTBOT_CMD="/opt/certbot/certbot-auto"
fi
if [[ -z "$CERTBOT_CMD" ]]; then
echo "FATAL: certbot is not available and no existing Let's Encrypt certificate was found for '$ENV_HOST'." >&2
exit 1
fi
WEBROOT_PATH="/var/www/webroot/ROOT"
ACME_CHALLENGE_DIR="$WEBROOT_PATH/.well-known/acme-challenge"
sudo mkdir -p "$ACME_CHALLENGE_DIR"
if [[ -n "$CONTACT_EMAIL" ]]; then
if ! sudo "$CERTBOT_CMD" certonly --webroot -w "$WEBROOT_PATH" -d "$ENV_HOST" --non-interactive --agree-tos --email "$CONTACT_EMAIL"; then
echo "FATAL: Failed to issue Let's Encrypt certificate for '$ENV_HOST' using contact email '$CONTACT_EMAIL'." >&2
exit 1
fi
else
if ! sudo "$CERTBOT_CMD" certonly --webroot -w "$WEBROOT_PATH" -d "$ENV_HOST" --non-interactive --agree-tos --register-unsafely-without-email; then
echo "FATAL: Failed to issue Let's Encrypt certificate for '$ENV_HOST' without contact email." >&2
exit 1
fi
fi
# Re-check exact and suffixed certificate directories after issuance.
if [[ -d "$LE_LIVE_DIR/$ENV_HOST" ]] && [[ -f "$LE_LIVE_DIR/$ENV_HOST/privkey.pem" ]] && [[ -f "$LE_LIVE_DIR/$ENV_HOST/fullchain.pem" ]]; then
LE_CERT_DIR="$LE_LIVE_DIR/$ENV_HOST"
else
for dir in "$LE_LIVE_DIR/$ENV_HOST"-*/; do
if [[ -d "$dir" ]] && [[ -f "$dir/privkey.pem" ]] && [[ -f "$dir/fullchain.pem" ]]; then
LE_CERT_DIR="${dir%/}"
break
fi
done
fi
fi
# Set the final key and cert file paths based on the found directory
if [[ -n "$LE_CERT_DIR" ]]; then
LE_KEY_FILE="$LE_CERT_DIR/privkey.pem"
LE_CERT_FILE="$LE_CERT_DIR/fullchain.pem"
else
echo "FATAL: Let's Encrypt certificate directory could not be found in $LE_LIVE_DIR for ENV_HOST: $ENV_HOST" >&2
echo "FATAL: Let's Encrypt certificate directory could not be found for ENV_HOST: $ENV_HOST" >&2
echo " Checked specific path: $LE_LIVE_DIR/$ENV_HOST" >&2
echo " Checked other subdirectories for privkey.pem and fullchain.pem." >&2
echo " Checked suffixed paths: $LE_LIVE_DIR/${ENV_HOST}-*" >&2
exit 1
fi