#!/bin/bash # Configuration variables DOMAIN="example.com" # Replace with your domain (e.g., example.com) WEBSITE_URL="mail.example.com" # Replace with website URL for web interface EMAIL="admin@example.com" # Replace with your email for Let's Encrypt LETSENCRYPT_EXPORT_PATH="/opt/PyMTA-server/email_server/ssl_certs/" # Path to export .crt and .key files APP_USERNAME="appuser" # Replace with the username of the user running the SMTP app NGINX_CONF_DIR="/etc/nginx" SITES_AVAILABLE="$NGINX_CONF_DIR/sites-available/$DOMAIN" SITES_ENABLED="$NGINX_CONF_DIR/sites-enabled/$DOMAIN" SITE_APP="$NGINX_CONF_DIR/sites-enabled/$WEBSITE_URL" WEB_ROOT="/var/www/$DOMAIN/html" ERROR_PAGE_DIR="$WEB_ROOT/errors" CLOUDFLARE_DNS_PLUGIN="certbot-dns-cloudflare" # https://medium.com/@life-is-short-so-enjoy-it/homelab-nginx-proxy-manager-setup-ssl-certificate-with-domain-name-in-cloudflare-dns-732af64ddc0b CLOUDFLARE_API_TOKEN_HERE="" # <<<< Set up here your cloudflare API token CLOUDFLARE_CREDENTIALS="/root/.cloudflare/credentials.ini" VENV_DIR="/opt/certbot-venv" # Exit on error set -e # List of common HTTP error codes with brief messages # hides Nginx error pages for custom declare -A ERROR_MESSAGES=( [400]="Bad Request" [401]="Unauthorized" [403]="Forbidden" [404]="Not Found" [500]="Internal Server Error" [502]="Bad Gateway" [503]="Service Unavailable" [504]="Gateway Timeout" ) # Check if running as root if [[ $EUID -ne 0 ]]; then echo "This script must be run as root or with sudo" >&2 exit 1 fi # Update system and install required packages echo "Updating system and installing dependencies..." apt update && apt upgrade -y apt install -y nginx certbot python3 python3-pip python3-venv python3-dev # Create and activate a virtual environment for certbot-dns-cloudflare echo "Creating Python virtual environment for certbot-dns-cloudflare..." mkdir -p "$VENV_DIR" python3 -m venv "$VENV_DIR" source "$VENV_DIR/bin/activate" # Upgrade pip in the virtual environment echo "Upgrading pip..." pip3 install --upgrade pip # Install Cloudflare DNS plugin for Certbot echo "Installing certbot-dns-cloudflare..." if ! pip3 install "$CLOUDFLARE_DNS_PLUGIN"; then echo "Failed to install $CLOUDFLARE_DNS_PLUGIN. Please check your network or Python environment." >&2 deactivate exit 1 fi # Deactivate virtual environment deactivate # Create web root and error page directory echo "Creating web root and error page directories..." mkdir -p "$WEB_ROOT" "$ERROR_PAGE_DIR" # Generate HTML files for each error code for code in "${!ERROR_MESSAGES[@]}"; do file="$ERROR_PAGE_DIR/$code.html" cat > "$file" < Error $code

Error $code

${ERROR_MESSAGES[$code]}

Return to Home

EOF echo "Created: $file" done echo "All error pages generated in $ERROR_PAGE_DIR" # Set permissions for error page chown -R www-data:www-data "$WEB_ROOT" chmod -R 755 "$WEB_ROOT" # Create Cloudflare credentials file (ensure you replace with your actual API token) echo "Creating Cloudflare credentials file..." mkdir -p "$(dirname "$CLOUDFLARE_CREDENTIALS")" cat > "$CLOUDFLARE_CREDENTIALS" << EOF dns_cloudflare_api_token = $CLOUDFLARE_API_TOKEN_HERE EOF chmod 600 "$CLOUDFLARE_CREDENTIALS" # Create NGINX configuration echo "Creating NGINX configuration for $DOMAIN..." mkdir -p "$NGINX_CONF_DIR/sites-available" "$NGINX_CONF_DIR/sites-enabled" cat > "$SITES_AVAILABLE" << EOF server { listen 80; server_name $DOMAIN *.$DOMAIN; root $WEB_ROOT; index index.html; location / { try_files \$uri \$uri/ /index.html; } error_page 404 $ERROR_PAGE; location = $ERROR_PAGE { root $WEB_ROOT; internal; } } EOF # Enable the site ln -sf "$SITES_AVAILABLE" "$SITES_ENABLED" # Disable default site rm -f "$NGINX_CONF_DIR/sites-enabled/default" # Test NGINX configuration echo "Testing NGINX configuration..." nginx -t # Reload NGINX to apply changes echo "Reloading NGINX..." systemctl reload nginx # Obtain Let's Encrypt wildcard SSL certificate using Cloudflare DNS echo "Obtaining Let's Encrypt wildcard SSL certificate..." source "$VENV_DIR/bin/activate" if ! certbot certonly \ --non-interactive \ --agree-tos \ --email "$EMAIL" \ --dns-cloudflare \ --dns-cloudflare-credentials "$CLOUDFLARE_CREDENTIALS" \ --domains "$DOMAIN,*.$DOMAIN"; then echo "Failed to obtain Let's Encrypt certificate. Please check Cloudflare credentials and DNS settings." >&2 deactivate exit 1 fi deactivate # Export .crt and .key files to LETSENCRYPT_EXPORT_PATH echo "Exporting SSL certificate and key to $LETSENCRYPT_EXPORT_PATH..." mkdir -p "$LETSENCRYPT_EXPORT_PATH" cp "/etc/letsencrypt/live/$DOMAIN/fullchain.pem" "$LETSENCRYPT_EXPORT_PATH/server.crt" cp "/etc/letsencrypt/live/$DOMAIN/privkey.pem" "$LETSENCRYPT_EXPORT_PATH/server.key" chown $APP_USERNAME:$APP_USERNAME "$LETSENCRYPT_EXPORT_PATH/server.crt" "$LETSENCRYPT_EXPORT_PATH/server.key" chmod 600 "$LETSENCRYPT_EXPORT_PATH/server.crt" "$LETSENCRYPT_EXPORT_PATH/server.key" # Update NGINX configuration to use SSL echo "Updating NGINX configuration for SSL..." cat > "$SITES_AVAILABLE" << EOF # Hide NGINX server signature server_tokens off; server { listen 80 default_server; server_name _; root $WEB_ROOT; index errors/404.html; #index.html; error_page 400 /errors/400.html; error_page 401 /errors/401.html; error_page 403 /errors/403.html; error_page 404 /errors/404.html; error_page 500 /errors/500.html; error_page 502 /errors/502.html; error_page 503 /errors/503.html; error_page 504 /errors/504.html; location /errors/ { root $WEB_ROOT; internal; } } server { listen 443 ssl default_server; server_name _; ssl_certificate /etc/letsencrypt/live/$DOMAIN/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/$DOMAIN/privkey.pem; # SSL security settings ssl_protocols TLSv1.2 TLSv1.3; ssl_prefer_server_ciphers on; ssl_ciphers EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH; ssl_session_cache shared:SSL:10m; ssl_session_timeout 1d; ssl_session_tickets off; root $WEB_ROOT; index errors/404.html; #index.html; error_page 400 /errors/400.html; error_page 401 /errors/401.html; error_page 403 /errors/403.html; error_page 404 /errors/404.html; error_page 500 /errors/500.html; error_page 502 /errors/502.html; error_page 503 /errors/503.html; error_page 504 /errors/504.html; location /errors/ { root $WEB_ROOT; internal; } } server { listen 80; server_name $WEBSITE_URL; # Prevent redirect loop with Cloudflare if ($http_x_forwarded_proto = "http") { return 301 https://\$host\$request_uri; } } server { listen 443 ssl; server_name $WEBSITE_URL; ssl_certificate /etc/letsencrypt/live/$DOMAIN/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/$DOMAIN/privkey.pem; # SSL security settings ssl_protocols TLSv1.2 TLSv1.3; ssl_prefer_server_ciphers on; ssl_ciphers EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH; ssl_session_cache shared:SSL:10m; ssl_session_timeout 1d; ssl_session_tickets off; # Proxy settings for Flask app location / { proxy_pass http://127.0.0.1:5000; # Updated this, where runs your web interface proxy_set_header Host \$host; proxy_set_header X-Real-IP \$remote_addr; proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto \$scheme; proxy_set_header Upgrade \$http_upgrade; proxy_set_header Connection "upgrade"; proxy_http_version 1.1; proxy_buffering off; proxy_read_timeout 3600s; proxy_send_timeout 3600s; } } EOF # Test NGINX configuration again echo "Testing updated NGINX configuration..." nginx -t # Reload NGINX to apply SSL changes echo "Reloading NGINX with SSL configuration..." systemctl reload nginx # Enable NGINX auto-start echo "Enabling NGINX to start on boot..." systemctl enable nginx # Set up automatic certificate renewal echo "Setting up Let's Encrypt renewal for wildcard certificate..." (crontab -l 2>/dev/null; echo "0 3 * * * /opt/certbot-venv/bin/certbot renew --quiet && \\ cp /etc/letsencrypt/live/\$DOMAIN/fullchain.pem \$LETSENCRYPT_EXPORT_PATH/server.crt && \\ cp /etc/letsencrypt/live/\$DOMAIN/privkey.pem \$LETSENCRYPT_EXPORT_PATH/server.key && \\ chown \$APP_USERNAME:\$APP_USERNAME "\$LETSENCRYPT_EXPORT_PATH/server.crt" "\$LETSENCRYPT_EXPORT_PATH/server.key" && \\ chmod 600 \$LETSENCRYPT_EXPORT_PATH/server.crt \$LETSENCRYPT_EXPORT_PATH/server.key") | crontab - echo "NGINX setup complete! Your site is live at https://$DOMAIN" echo "Wildcard certificate covers *.$DOMAIN" echo "Custom 404 page is set at $ERROR_PAGE" echo "SSL certificate and key exported to $LETSENCRYPT_EXPORT_PATH" echo "Please ensure your Cloudflare API token is correctly set in $CLOUDFLARE_CREDENTIALS"