mb-admin/scripts/ssl-manager/ssl_manager.sh

227 lines
7.0 KiB
Bash

#!/bin/bash
set -euo pipefail
# Log file setup
LOG_DIR="/var/log/mb-ssl"
LOG_FILE="$LOG_DIR/ssl-manager.log"
mkdir -p "$LOG_DIR"
chmod 0755 "$LOG_DIR"
exec > >(tee -a "$LOG_FILE") 2>&1
# Function to log messages
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S') $1"
}
# Function to send email via Postmark
send_email() {
local subject="$1"
local body="$2"
local recipient="${EMAIL:-}"
if [[ -n "$recipient" ]]; then
log "Sending email notification to $recipient..."
curl -s "https://api.postmarkapp.com/email" \
-X POST \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "X-Postmark-Server-Token: d88b25c4-2fdb-43d3-9097-f6c655a9742b" \
-d "{
\"From\": \"admin@mightybox.io\",
\"To\": \"$recipient\",
\"Subject\": \"$subject\",
\"HtmlBody\": \"$body\",
\"MessageStream\": \"outbound\"
}" > /dev/null && log "Email sent successfully." || log "Failed to send email."
else
log "Email not provided. Skipping email notification."
fi
}
# Function to validate IP address
validate_ip() {
local ip=$1
[[ "$ip" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]] && return 0 || return 1
}
# Function to validate domain
validate_domain() {
local domain=$1
[[ "$domain" =~ ^([a-zA-Z0-9](-*[a-zA-Z0-9])*\.)+[a-zA-Z]{2,}$ ]] && return 0 || return 1
}
# Function to validate email
validate_email() {
local email=$1
[[ "$email" =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]] && return 0 || return 1
}
# Function to validate DNS resolution
validate_dns_resolution() {
log "Validating DNS resolution for $DOMAIN..."
RESOLVED_IPS=$(dig +short "$DOMAIN" A)
if echo "$RESOLVED_IPS" | grep -q "$PUBLIC_IP"; then
log "DNS validation successful. $DOMAIN resolves to the expected public IP ($PUBLIC_IP)."
return 0
else
log "DNS validation failed. $DOMAIN does not resolve to the expected public IP ($PUBLIC_IP)."
return 1
fi
}
# Function to validate HTTP access
validate_http_access() {
log "Validating HTTP access for $DOMAIN..."
ACME_DIR="/var/www/webroot/ROOT/.well-known/acme-challenge"
mkdir -p "$ACME_DIR"
chmod 0755 "$ACME_DIR"
TOKEN=$(openssl rand -hex 16)
echo "$TOKEN" > "$ACME_DIR/test-token"
# Test HTTP access by retrieving the token
RESPONSE=$(curl -s "http://$DOMAIN/.well-known/acme-challenge/test-token")
if [[ "$RESPONSE" == "$TOKEN" ]]; then
log "HTTP validation successful. $DOMAIN is accessible."
return 0
else
log "HTTP validation failed. Unable to retrieve the test token from $DOMAIN."
return 1
fi
}
# Function to validate the domain connection
validate_domain_connection() {
if validate_dns_resolution; then
log "Domain validation succeeded via DNS."
return 0
elif validate_http_access; then
log "Domain validation succeeded via HTTP."
return 0
else
log "Domain validation failed. $DOMAIN does not point to the correct IP or is not accessible via HTTP."
send_email "SSL Setup Failed" "The domain $DOMAIN could not be validated. Ensure the DNS and HTTP settings are correct."
exit 1
fi
}
# Function to update LiteSpeed configuration
update_litespeed_config() {
local config_file="/var/www/conf/httpd_config.xml"
local key_file="/etc/letsencrypt/live/$DOMAIN/privkey.pem"
local cert_file="/etc/letsencrypt/live/$DOMAIN/fullchain.pem"
log "Updating LiteSpeed configuration..."
if grep -q "$DOMAIN" "$config_file"; then
log "Domain $DOMAIN already exists in the configuration. Updating..."
sed -i "/<listener>/,/<\/listener>/s|<keyFile>.*</keyFile>|<keyFile>$key_file</keyFile>|" "$config_file"
sed -i "/<listener>/,/<\/listener>/s|<certFile>.*</certFile>|<certFile>$cert_file</certFile>|" "$config_file"
else
log "Domain $DOMAIN not found in configuration. Adding new listener..."
sed -i "/<\/listenerList>/i\
<listener>\
<name>HTTPS-$DOMAIN</name>\
<address>*:443</address>\
<secure>1</secure>\
<keyFile>$key_file</keyFile>\
<certFile>$cert_file</certFile>\
<certChain>1</certChain>\
</listener>" "$config_file"
fi
log "LiteSpeed configuration updated successfully."
}
# Function to set up automatic renewal
setup_cron_job() {
log "Setting up cron job for Certbot renewal..."
# Ensure crond is running
if ! systemctl is-active --quiet crond; then
log "Starting crond service..."
sudo systemctl start crond
sudo systemctl enable crond
fi
# Add cron job for Certbot renewal
if ! crontab -l 2>/dev/null | grep -q "certbot renew"; then
(crontab -l 2>/dev/null; echo "0 3 * * * /usr/bin/certbot renew --quiet") | crontab -
log "Cron job added for Certbot renewal."
else
log "Cron job for Certbot renewal already exists."
fi
# Verify cron job
log "Verifying cron job..."
if crontab -l | grep -q "certbot renew"; then
log "Cron job successfully set up."
else
log "Failed to set up cron job. Please check manually."
exit 1
fi
}
# Parse input parameters
for arg in "$@"; do
case $arg in
--public-ip=*)
PUBLIC_IP="${arg#*=}"
;;
--domain=*)
DOMAIN="${arg#*=}"
;;
--email=*)
EMAIL="${arg#*=}"
;;
*)
echo "Invalid argument: $arg"
exit 1
;;
esac
done
# Input validation
log "Validating inputs..."
if [[ -z "${PUBLIC_IP:-}" || -z "${DOMAIN:-}" ]]; then
echo "Error: --public-ip and --domain are mandatory."
exit 1
fi
validate_ip "$PUBLIC_IP" || { echo "Invalid public IP: $PUBLIC_IP"; exit 1; }
validate_domain "$DOMAIN" || { echo "Invalid domain: $DOMAIN"; exit 1; }
if [[ -n "${EMAIL:-}" ]]; then
validate_email "$EMAIL" || { echo "Invalid email: $EMAIL"; exit 1; }
fi
# Validate the domain connection
validate_domain_connection
# Install Certbot
log "Installing Certbot..."
if ! command -v certbot > /dev/null; then
if [[ -f /etc/debian_version ]]; then
apt-get update && apt-get install -y certbot
elif [[ -f /etc/redhat-release ]]; then
yum install -y certbot
else
echo "Unsupported OS. Install Certbot manually."
exit 1
fi
fi
# Issue SSL certificate
CERTBOT_CMD="certbot certonly --webroot -w /var/www/webroot/ROOT -d $DOMAIN --agree-tos --non-interactive"
[[ -n "${EMAIL:-}" ]] && CERTBOT_CMD+=" --email $EMAIL"
if $CERTBOT_CMD; then
log "SSL certificate issued successfully for $DOMAIN."
update_litespeed_config
sudo systemctl reload lsws
send_email "$DOMAIN SSL Certificate Issued Successfully" "The SSL certificate for $DOMAIN has been successfully installed."
setup_cron_job
else
log "Certbot failed."
send_email "SSL Certificate Installation Failed" "An error occurred while installing the SSL certificate for $DOMAIN."
exit 1
fi