- Fix RedisCache driver to handle MGET failures gracefully with fallback - Add comprehensive discovery context comparison debug tools - Identify root cause: WEB context discovery missing 166 items vs CLI - WEB context missing RequestFactory class entirely (52 vs 69 commands) - Improved exception handling with detailed binding diagnostics
320 lines
8.3 KiB
Bash
Executable File
320 lines
8.3 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
#
|
|
# Production SSL Certificate Setup Script for michaelschiemer.de
|
|
# Sets up Let's Encrypt SSL certificates on the production server
|
|
#
|
|
|
|
set -euo pipefail
|
|
|
|
# Configuration
|
|
SERVER_USER="deploy"
|
|
SERVER_IP="94.16.110.151"
|
|
REMOTE_PATH="/home/deploy/michaelschiemer"
|
|
DOMAIN="michaelschiemer.de"
|
|
EMAIL="michael@michaelschiemer.de" # Change this to your email
|
|
SSH_OPTS="-i ~/.ssh/production -o StrictHostKeyChecking=no"
|
|
|
|
# Colors for output
|
|
GREEN="\e[32m"
|
|
YELLOW="\e[33m"
|
|
RED="\e[31m"
|
|
BLUE="\e[34m"
|
|
RESET="\e[0m"
|
|
|
|
log_info() {
|
|
echo -e "${BLUE}[INFO]${RESET} $1"
|
|
}
|
|
|
|
log_success() {
|
|
echo -e "${GREEN}[SUCCESS]${RESET} $1"
|
|
}
|
|
|
|
log_warning() {
|
|
echo -e "${YELLOW}[WARNING]${RESET} $1"
|
|
}
|
|
|
|
log_error() {
|
|
echo -e "${RED}[ERROR]${RESET} $1"
|
|
}
|
|
|
|
# Check if domain resolves to production server
|
|
check_dns() {
|
|
log_info "Checking DNS resolution for $DOMAIN..."
|
|
local resolved_ip=$(dig +short "$DOMAIN" | head -1)
|
|
|
|
if [[ "$resolved_ip" == "$SERVER_IP" ]]; then
|
|
log_success "Domain $DOMAIN resolves correctly to $SERVER_IP"
|
|
else
|
|
log_warning "Domain $DOMAIN resolves to $resolved_ip (expected: $SERVER_IP)"
|
|
log_warning "SSL certificate might fail if DNS is incorrect"
|
|
fi
|
|
}
|
|
|
|
# Install certbot on production server
|
|
install_certbot() {
|
|
log_info "Installing certbot on production server..."
|
|
|
|
ssh $SSH_OPTS "$SERVER_USER@$SERVER_IP" '
|
|
# Update package list
|
|
sudo apt update
|
|
|
|
# Install snapd if not present
|
|
if ! command -v snap &> /dev/null; then
|
|
sudo apt install -y snapd
|
|
fi
|
|
|
|
# Install certbot via snap
|
|
if ! command -v certbot &> /dev/null; then
|
|
sudo snap install core; sudo snap refresh core
|
|
sudo snap install --classic certbot
|
|
sudo ln -sf /snap/bin/certbot /usr/bin/certbot
|
|
fi
|
|
|
|
# Verify certbot installation
|
|
certbot --version
|
|
'
|
|
|
|
log_success "Certbot installed successfully"
|
|
}
|
|
|
|
# Stop nginx temporarily for certificate generation
|
|
prepare_nginx() {
|
|
log_info "Preparing nginx for certificate generation..."
|
|
|
|
ssh $SSH_OPTS "$SERVER_USER@$SERVER_IP" "
|
|
cd $REMOTE_PATH
|
|
|
|
# Stop nginx container temporarily
|
|
docker compose down web 2>/dev/null || true
|
|
|
|
# Create ssl directory
|
|
mkdir -p ssl
|
|
|
|
# Create temporary nginx config for certbot
|
|
cat > ssl/nginx-temp.conf << 'EOF'
|
|
server {
|
|
listen 80;
|
|
server_name $DOMAIN;
|
|
|
|
location /.well-known/acme-challenge/ {
|
|
root /var/www/certbot;
|
|
}
|
|
|
|
location / {
|
|
return 301 https://\$server_name\$request_uri;
|
|
}
|
|
}
|
|
EOF
|
|
|
|
# Start temporary nginx for certificate validation
|
|
docker run -d --name nginx-temp \\
|
|
-p 80:80 \\
|
|
-v \$(pwd)/ssl/nginx-temp.conf:/etc/nginx/conf.d/default.conf \\
|
|
-v \$(pwd)/ssl/certbot-webroot:/var/www/certbot \\
|
|
nginx:alpine
|
|
"
|
|
|
|
log_success "Nginx prepared for certificate generation"
|
|
}
|
|
|
|
# Generate Let's Encrypt certificate
|
|
generate_certificate() {
|
|
log_info "Generating Let's Encrypt certificate for $DOMAIN..."
|
|
|
|
ssh $SSH_OPTS "$SERVER_USER@$SERVER_IP" "
|
|
cd $REMOTE_PATH
|
|
|
|
# Create webroot directory
|
|
mkdir -p ssl/certbot-webroot
|
|
|
|
# Generate certificate
|
|
docker run --rm \\
|
|
-v \$(pwd)/ssl/certbot-webroot:/var/www/certbot \\
|
|
-v \$(pwd)/ssl:/etc/letsencrypt \\
|
|
certbot/certbot certonly \\
|
|
--webroot \\
|
|
--webroot-path=/var/www/certbot \\
|
|
--email $EMAIL \\
|
|
--agree-tos \\
|
|
--no-eff-email \\
|
|
-d $DOMAIN
|
|
|
|
# Copy certificates to expected location
|
|
if [ -d \"ssl/live/$DOMAIN\" ]; then
|
|
cp ssl/live/$DOMAIN/fullchain.pem ssl/fullchain.pem
|
|
cp ssl/live/$DOMAIN/privkey.pem ssl/privkey.pem
|
|
chmod 644 ssl/fullchain.pem ssl/privkey.pem
|
|
log_success 'SSL certificates generated and copied'
|
|
else
|
|
log_error 'Certificate generation failed'
|
|
exit 1
|
|
fi
|
|
"
|
|
|
|
log_success "SSL certificate generated successfully"
|
|
}
|
|
|
|
# Clean up temporary nginx
|
|
cleanup_nginx() {
|
|
log_info "Cleaning up temporary nginx..."
|
|
|
|
ssh $SSH_OPTS "$SERVER_USER@$SERVER_IP" "
|
|
cd $REMOTE_PATH
|
|
|
|
# Stop and remove temporary nginx
|
|
docker stop nginx-temp 2>/dev/null || true
|
|
docker rm nginx-temp 2>/dev/null || true
|
|
|
|
# Clean up temporary files
|
|
rm -f ssl/nginx-temp.conf
|
|
rm -rf ssl/certbot-webroot
|
|
"
|
|
|
|
log_success "Temporary nginx cleaned up"
|
|
}
|
|
|
|
# Start the application with SSL
|
|
start_application() {
|
|
log_info "Starting application with SSL certificates..."
|
|
|
|
ssh $SSH_OPTS "$SERVER_USER@$SERVER_IP" "
|
|
cd $REMOTE_PATH
|
|
|
|
# Start all services
|
|
docker compose up -d
|
|
|
|
# Wait for services to start
|
|
sleep 10
|
|
|
|
# Check container status
|
|
docker compose ps
|
|
"
|
|
|
|
log_success "Application started with SSL certificates"
|
|
}
|
|
|
|
# Test SSL certificate
|
|
test_ssl() {
|
|
log_info "Testing SSL certificate..."
|
|
|
|
# Test HTTPS connection
|
|
if curl -sSf "https://$DOMAIN" > /dev/null 2>&1; then
|
|
log_success "HTTPS connection successful!"
|
|
else
|
|
log_warning "HTTPS connection test failed - checking certificate..."
|
|
fi
|
|
|
|
# Check certificate details
|
|
echo | openssl s_client -servername "$DOMAIN" -connect "$DOMAIN:443" 2>/dev/null | openssl x509 -noout -dates
|
|
|
|
log_info "SSL setup completed!"
|
|
log_success "Your site should now be accessible at: https://$DOMAIN"
|
|
}
|
|
|
|
# Setup certificate renewal
|
|
setup_renewal() {
|
|
log_info "Setting up automatic certificate renewal..."
|
|
|
|
ssh $SSH_OPTS "$SERVER_USER@$SERVER_IP" "
|
|
# Create renewal script
|
|
cat > /home/deploy/renew-certificates.sh << 'RENEWAL_SCRIPT'
|
|
#!/bin/bash
|
|
cd /home/deploy/michaelschiemer
|
|
|
|
# Stop nginx container
|
|
docker compose down web
|
|
|
|
# Renew certificate
|
|
docker run --rm \\
|
|
-v \$(pwd)/ssl:/etc/letsencrypt \\
|
|
-v \$(pwd)/ssl/certbot-webroot:/var/www/certbot \\
|
|
certbot/certbot renew \\
|
|
--webroot \\
|
|
--webroot-path=/var/www/certbot
|
|
|
|
# Copy renewed certificates
|
|
if [ -f \"ssl/live/$DOMAIN/fullchain.pem\" ]; then
|
|
cp ssl/live/$DOMAIN/fullchain.pem ssl/fullchain.pem
|
|
cp ssl/live/$DOMAIN/privkey.pem ssl/privkey.pem
|
|
chmod 644 ssl/fullchain.pem ssl/privkey.pem
|
|
fi
|
|
|
|
# Restart services
|
|
docker compose up -d
|
|
RENEWAL_SCRIPT
|
|
|
|
chmod +x /home/deploy/renew-certificates.sh
|
|
|
|
# Add cron job for automatic renewal (runs twice daily)
|
|
(crontab -l 2>/dev/null; echo '0 12,0 * * * /home/deploy/renew-certificates.sh >> /var/log/letsencrypt-renewal.log 2>&1') | crontab -
|
|
"
|
|
|
|
log_success "Automatic certificate renewal configured"
|
|
}
|
|
|
|
# Main execution
|
|
main() {
|
|
log_info "Starting SSL certificate setup for $DOMAIN"
|
|
|
|
# Check DNS
|
|
check_dns
|
|
|
|
# Install certbot
|
|
install_certbot
|
|
|
|
# Prepare nginx
|
|
prepare_nginx
|
|
|
|
# Generate certificate
|
|
generate_certificate
|
|
|
|
# Clean up temporary nginx
|
|
cleanup_nginx
|
|
|
|
# Start application
|
|
start_application
|
|
|
|
# Test SSL
|
|
test_ssl
|
|
|
|
# Setup renewal
|
|
setup_renewal
|
|
|
|
log_success "SSL certificate setup completed successfully!"
|
|
log_info "Next steps:"
|
|
echo " 1. Test your site: https://$DOMAIN"
|
|
echo " 2. Certificates will auto-renew twice daily"
|
|
echo " 3. Check renewal logs: ssh $SERVER_USER@$SERVER_IP 'tail -f /var/log/letsencrypt-renewal.log'"
|
|
}
|
|
|
|
# Show usage
|
|
show_usage() {
|
|
echo "Usage: $0 [--help]"
|
|
echo ""
|
|
echo "This script sets up Let's Encrypt SSL certificates for $DOMAIN"
|
|
echo ""
|
|
echo "Prerequisites:"
|
|
echo " - Domain $DOMAIN must point to $SERVER_IP"
|
|
echo " - SSH access to production server configured"
|
|
echo " - Docker and docker-compose installed on server"
|
|
echo ""
|
|
echo "Options:"
|
|
echo " --help Show this help message"
|
|
}
|
|
|
|
# Parse arguments
|
|
case "${1:-}" in
|
|
--help|-h)
|
|
show_usage
|
|
exit 0
|
|
;;
|
|
"")
|
|
main
|
|
;;
|
|
*)
|
|
log_error "Unknown option: $1"
|
|
show_usage
|
|
exit 1
|
|
;;
|
|
esac |