Created
June 26, 2025 12:30
-
-
Save mrEckendonk/59e7172b2dba1362aac7455a5829c44c to your computer and use it in GitHub Desktop.
Local Development Create Apache Site - WordPress - Remove - Fedora tested. (tailscale not yet completed)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # Configuration | |
| RECORD_FILE="/root/.site_manager_records" | |
| DB_ROOT_USER="root" | |
| DB_ROOT_PASS="" # Leave empty if no password | |
| TAILSCALE_TAILNET="banded-arctic.ts.net" | |
| SERVE_RECORD="/root/.tailscale_serve_status" | |
| # Check for root privileges | |
| if [ "$(id -u)" != "0" ]; then | |
| echo "This script must be run as root. Use sudo." >&2 | |
| exit 1 | |
| fi | |
| # Install dependencies if missing | |
| install_dependencies() { | |
| if ! command -v httpd &> /dev/null || ! command -v openssl &> /dev/null; then | |
| echo "Installing required packages..." | |
| dnf install -y httpd mod_ssl openssl policycoreutils-python-utils firewalld tailscale jq mod_proxy_html | |
| systemctl enable --now httpd firewalld | |
| firewall-cmd --permanent --add-service={http,https} | |
| firewall-cmd --reload | |
| # Enable Apache proxy modules | |
| cat > /etc/httpd/conf.modules.d/00-proxy.conf <<EOF | |
| LoadModule proxy_module modules/mod_proxy.so | |
| LoadModule proxy_http_module modules/mod_proxy_http.so | |
| LoadModule proxy_html_module modules/mod_proxy_html.so | |
| LoadModule headers_module modules/mod_headers.so | |
| LoadModule ssl_module modules/mod_ssl.so | |
| EOF | |
| fi | |
| } | |
| # Initialize dependencies | |
| install_dependencies | |
| # Domain validation functions | |
| domain_exists() { | |
| local domain="$1" | |
| [[ -f "/etc/httpd/conf.d/${domain}.conf" ]] && return 0 | |
| return 1 | |
| } | |
| ssl_exists() { | |
| local domain="$1" | |
| [[ -f "/etc/pki/tls/certs/${domain}/${domain}.crt" && \ | |
| -f "/etc/pki/tls/private/${domain}/${domain}.key" ]] && return 0 | |
| return 1 | |
| } | |
| wp_site_exists() { | |
| local domain="$1" | |
| grep -q "^${domain}:" "$RECORD_FILE" 2>/dev/null | |
| return $? | |
| } | |
| print_divider() { | |
| echo "============================================================" | |
| } | |
| # Database functions | |
| create_db_user() { | |
| local domain="$1" | |
| local db_name="wp_${domain//./_}" | |
| local db_user="${db_name}_user" | |
| local db_pass=$(openssl rand -base64 16 | tr -dc 'a-zA-Z0-9' | head -c 16) | |
| # Create database and user | |
| mysql -u"$DB_ROOT_USER" ${DB_ROOT_PASS:+-p"$DB_ROOT_PASS"} <<EOF | |
| CREATE DATABASE IF NOT EXISTS \`${db_name}\`; | |
| CREATE USER '${db_user}'@'localhost' IDENTIFIED BY '${db_pass}'; | |
| GRANT ALL PRIVILEGES ON \`${db_name}\`.* TO '${db_user}'@'localhost'; | |
| FLUSH PRIVILEGES; | |
| EOF | |
| # Add to record file | |
| echo "${domain}:${db_name}:${db_user}:${db_pass}" >> "$RECORD_FILE" | |
| chmod 600 "$RECORD_FILE" | |
| echo "$db_name:$db_user:$db_pass" | |
| } | |
| remove_db_user() { | |
| local domain="$1" | |
| if wp_site_exists "$domain"; then | |
| local record=$(grep "^${domain}:" "$RECORD_FILE") | |
| IFS=':' read -ra parts <<< "$record" | |
| local db_name="${parts[1]}" | |
| local db_user="${parts[2]}" | |
| mysql -u"$DB_ROOT_USER" ${DB_ROOT_PASS:+-p"$DB_ROOT_PASS"} <<EOF | |
| DROP DATABASE IF EXISTS \`${db_name}\`; | |
| DROP USER IF EXISTS '${db_user}'@'localhost'; | |
| FLUSH PRIVILEGES; | |
| EOF | |
| # Remove from record file | |
| sed -i "/^${domain}:/d" "$RECORD_FILE" | |
| fi | |
| } | |
| # Site management functions | |
| create_basic_site() { | |
| local domain="$1" | |
| # Setup directories | |
| DOC_ROOT="/var/www/${domain}/public_html" | |
| SSL_CERT_DIR="/etc/pki/tls/certs/${domain}" | |
| SSL_KEY_DIR="/etc/pki/tls/private/${domain}" | |
| mkdir -p "$DOC_ROOT" "$SSL_CERT_DIR" "$SSL_KEY_DIR" | |
| chown -R apache:apache "/var/www/${domain}" | |
| chmod -R 755 "/var/www/${domain}" | |
| # Generate SSL certificate | |
| openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ | |
| -keyout "${SSL_KEY_DIR}/${domain}.key" \ | |
| -out "${SSL_CERT_DIR}/${domain}.crt" \ | |
| -subj "/CN=${domain}" \ | |
| -addext "subjectAltName=DNS:${domain},DNS:www.${domain}" 2>/dev/null | |
| # Set permissions | |
| chmod 400 "${SSL_KEY_DIR}/${domain}.key" | |
| chmod 444 "${SSL_CERT_DIR}/${domain}.crt" | |
| chown root:apache "${SSL_KEY_DIR}/${domain}.key" | |
| # Configure SELinux | |
| semanage fcontext -a -t httpd_sys_content_t "/var/www/${domain}(/.*)?" 2>/dev/null | |
| semanage fcontext -a -t cert_t "/etc/pki/tls/certs/${domain}(/.*)?" 2>/dev/null | |
| semanage fcontext -a -t cert_t "/etc/pki/tls/private/${domain}(/.*)?" 2>/dev/null | |
| restorecon -Rv "/var/www/${domain}" /etc/pki/tls 2>/dev/null | |
| # Create Apache config | |
| CONF_FILE="/etc/httpd/conf.d/${domain}.conf" | |
| cat > "$CONF_FILE" << EOF | |
| <VirtualHost *:80> | |
| ServerName ${domain} | |
| ServerAlias www.${domain} | |
| Redirect permanent / https://${domain}/ | |
| </VirtualHost> | |
| <VirtualHost *:443> | |
| ServerName ${domain} | |
| ServerAlias www.${domain} | |
| SSLEngine on | |
| SSLCertificateFile ${SSL_CERT_DIR}/${domain}.crt | |
| SSLCertificateKeyFile ${SSL_KEY_DIR}/${domain}.key | |
| DocumentRoot ${DOC_ROOT} | |
| ErrorLog /var/log/httpd/${domain}_error.log | |
| CustomLog /var/log/httpd/${domain}_access.log combined | |
| <Directory ${DOC_ROOT}> | |
| Options -Indexes +FollowSymLinks | |
| AllowOverride All | |
| Require all granted | |
| </Directory> | |
| Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" | |
| Header always set X-Content-Type-Options nosniff | |
| Header always set X-Frame-Options DENY | |
| # Proxy settings for Tailscale | |
| ProxyPreserveHost On | |
| RequestHeader set X-Forwarded-Proto "https" | |
| RequestHeader set X-Forwarded-Port "443" | |
| </VirtualHost> | |
| EOF | |
| # Update /etc/hosts | |
| if ! grep -q "$domain" /etc/hosts; then | |
| echo -e "127.0.0.1\t${domain} www.${domain}" >> /etc/hosts | |
| fi | |
| } | |
| create_test_page() { | |
| local domain="$1" | |
| local doc_root="/var/www/${domain}/public_html" | |
| cat > "${doc_root}/index.html" << EOF | |
| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <title>${domain} Works!</title> | |
| <style> | |
| body { | |
| font-family: Arial, sans-serif; | |
| text-align: center; | |
| padding-top: 50px; | |
| background-color: #f0f8ff; | |
| } | |
| .success { | |
| color: #2ecc71; | |
| font-size: 3em; | |
| } | |
| .info { | |
| color: #3498db; | |
| font-size: 1.2em; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="success">✔</div> | |
| <h1>${domain} is working!</h1> | |
| <p class="info">SSL/TLS is properly configured on this server.</p> | |
| <p class="info">🚀 Automagic HTTPS Setup Complete!</p> | |
| </body> | |
| </html> | |
| EOF | |
| } | |
| add_site() { | |
| while true; do | |
| read -p "Enter domain name (e.g., example.local): " DOMAIN | |
| if [ -z "$DOMAIN" ]; then | |
| echo "Domain name cannot be empty!" >&2 | |
| continue | |
| fi | |
| if domain_exists "$DOMAIN"; then | |
| echo -e "\033[1;31mERROR: Domain '$DOMAIN' already exists!\033[0m" >&2 | |
| return 1 | |
| fi | |
| print_divider | |
| echo "You are about to create:" | |
| echo " • Domain: $DOMAIN" | |
| echo " • Document root: /var/www/${DOMAIN}/public_html" | |
| echo " • SSL certificate: /etc/pki/tls/certs/${DOMAIN}" | |
| echo " • Apache config: /etc/httpd/conf.d/${DOMAIN}.conf" | |
| print_divider | |
| read -p "Continue? (Y/n) " confirm | |
| confirm=${confirm:-Y} | |
| if [[ "$confirm" =~ ^[Yy]$ ]]; then | |
| break | |
| else | |
| echo "Operation cancelled." | |
| return | |
| fi | |
| done | |
| create_basic_site "$DOMAIN" | |
| create_test_page "$DOMAIN" | |
| # Validate and restart Apache | |
| if httpd -t; then | |
| systemctl restart httpd | |
| print_divider | |
| echo -e "\033[1;32mSUCCESS: Site ${DOMAIN} added!\033[0m" | |
| echo " • Access: https://${DOMAIN}" | |
| echo " • Document root: /var/www/${DOMAIN}/public_html" | |
| echo " • SSL Cert: /etc/pki/tls/certs/${DOMAIN}/${DOMAIN}.crt" | |
| print_divider | |
| else | |
| echo -e "\033[1;31mERROR: Apache configuration test failed. Site not activated.\033[0m" >&2 | |
| fi | |
| } | |
| add_wordpress_site() { | |
| while true; do | |
| read -p "Enter domain name for WordPress site (e.g., blog.local): " DOMAIN | |
| if [ -z "$DOMAIN" ]; then | |
| echo "Domain name cannot be empty!" >&2 | |
| continue | |
| fi | |
| if domain_exists "$DOMAIN"; then | |
| echo -e "\033[1;31mERROR: Domain '$DOMAIN' already exists!\033[0m" >&2 | |
| return 1 | |
| fi | |
| if wp_site_exists "$DOMAIN"; then | |
| echo -e "\033[1;31mERROR: WordPress site '$DOMAIN' already exists!\033[0m" >&2 | |
| return 1 | |
| fi | |
| print_divider | |
| echo "You are about to create a WordPress site:" | |
| echo " • Domain: $DOMAIN" | |
| echo " • Document root: /var/www/${DOMAIN}/public_html" | |
| echo " • SSL certificate: /etc/pki/tls/certs/${DOMAIN}" | |
| echo " • Apache config: /etc/httpd/conf.d/${DOMAIN}.conf" | |
| echo " • New database and MySQL user will be created" | |
| print_divider | |
| read -p "Continue? (Y/n) " confirm | |
| confirm=${confirm:-Y} | |
| if [[ "$confirm" =~ ^[Yy]$ ]]; then | |
| break | |
| else | |
| echo "Operation cancelled." | |
| return | |
| fi | |
| done | |
| # Create basic site structure | |
| create_basic_site "$DOMAIN" | |
| # Download and install WordPress | |
| DOC_ROOT="/var/www/${DOMAIN}/public_html" | |
| WP_URL="https://wordpress.org/latest.tar.gz" | |
| echo "Downloading WordPress..." | |
| wget -q -O /tmp/wordpress.tar.gz "$WP_URL" | |
| echo "Extracting WordPress..." | |
| tar -xzf /tmp/wordpress.tar.gz -C /tmp | |
| cp -a /tmp/wordpress/* "$DOC_ROOT" | |
| chown -R apache:apache "$DOC_ROOT" | |
| rm -rf /tmp/wordpress /tmp/wordpress.tar.gz | |
| # Create database and user | |
| echo "Creating database and user..." | |
| db_creds=$(create_db_user "$DOMAIN") | |
| IFS=':' read -ra CREDS <<< "$db_creds" | |
| local db_name="${CREDS[0]}" | |
| local db_user="${CREDS[1]}" | |
| local db_pass="${CREDS[2]}" | |
| # Create wp-config.php | |
| cp "$DOC_ROOT/wp-config-sample.php" "$DOC_ROOT/wp-config.php" | |
| sed -i "s/database_name_here/$db_name/" "$DOC_ROOT/wp-config.php" | |
| sed -i "s/username_here/$db_user/" "$DOC_ROOT/wp-config.php" | |
| sed -i "s/password_here/$db_pass/" "$DOC_ROOT/wp-config.php" | |
| # Add security keys | |
| SECRET_KEYS=$(wget -q -O - https://api.wordpress.org/secret-key/1.1/salt/) | |
| sed -i "/AUTH_KEY/s/put your unique phrase here/$SECRET_KEYS/" "$DOC_ROOT/wp-config.php" | |
| # Add proxy settings to wp-config.php | |
| echo "Adding proxy configuration to WordPress..." | |
| cat >> "$DOC_ROOT/wp-config.php" << EOF | |
| /* Added by Site Manager for Tailscale */ | |
| if (isset(\$_SERVER['HTTP_X_FORWARDED_PROTO']) && \$_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') { | |
| \$_SERVER['HTTPS'] = 'on'; | |
| } | |
| EOF | |
| # Validate and restart Apache | |
| if httpd -t; then | |
| systemctl restart httpd | |
| print_divider | |
| echo -e "\033[1;32mSUCCESS: WordPress site ${DOMAIN} created!\033[0m" | |
| echo " • Access: https://${DOMAIN}" | |
| echo " • WordPress Admin: https://${DOMAIN}/wp-admin" | |
| echo " • Database: $db_name" | |
| echo " • Database User: $db_user" | |
| echo -e " • Database Password: \033[1;34m$db_pass\033[0m" | |
| echo " • Document root: $DOC_ROOT" | |
| print_divider | |
| echo "Note: Save these database credentials for future reference" | |
| print_divider | |
| else | |
| echo -e "\033[1;31mERROR: Apache configuration test failed. Site not activated.\033[0m" >&2 | |
| fi | |
| } | |
| renew_ssl() { | |
| while true; do | |
| read -p "Enter domain name to renew SSL: " DOMAIN | |
| if [ -z "$DOMAIN" ]; then | |
| echo "Domain name cannot be empty!" >&2 | |
| continue | |
| fi | |
| if ! domain_exists "$DOMAIN"; then | |
| echo -e "\033[1;31mERROR: Domain '$DOMAIN' does not exist!\033[0m" >&2 | |
| return 1 | |
| fi | |
| if ! ssl_exists "$DOMAIN"; then | |
| echo -e "\033[1;31mERROR: SSL certificate for '$DOMAIN' not found!\033[0m" >&2 | |
| return 1 | |
| fi | |
| print_divider | |
| echo "You are about to RENEW SSL for:" | |
| echo " • Domain: $DOMAIN" | |
| echo " • New expiration: $(date -d "+365 days" +"%Y-%m-%d")" | |
| echo " • Old certificate will be backed up" | |
| print_divider | |
| read -p "Continue? (Y/n) " confirm | |
| confirm=${confirm:-Y} | |
| if [[ "$confirm" =~ ^[Yy]$ ]]; then | |
| break | |
| else | |
| echo "Operation cancelled." | |
| return | |
| fi | |
| done | |
| SSL_CERT_DIR="/etc/pki/tls/certs/${DOMAIN}" | |
| SSL_KEY_DIR="/etc/pki/tls/private/${DOMAIN}" | |
| # Backup old certs | |
| TIMESTAMP=$(date +%Y%m%d%H%M%S) | |
| BACKUP_DIR="/etc/pki/tls/backups/${DOMAIN}" | |
| mkdir -p "$BACKUP_DIR" | |
| cp -v "${SSL_CERT_DIR}/${DOMAIN}.crt" "${BACKUP_DIR}/${DOMAIN}.crt.bak-${TIMESTAMP}" | |
| cp -v "${SSL_KEY_DIR}/${DOMAIN}.key" "${BACKUP_DIR}/${DOMAIN}.key.bak-${TIMESTAMP}" | |
| echo "Created backups:" | |
| echo " • ${BACKUP_DIR}/${DOMAIN}.crt.bak-${TIMESTAMP}" | |
| echo " • ${BACKUP_DIR}/${DOMAIN}.key.bak-${TIMESTAMP}" | |
| # Generate new certificate | |
| openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ | |
| -keyout "${SSL_KEY_DIR}/${DOMAIN}.key" \ | |
| -out "${SSL_CERT_DIR}/${DOMAIN}.crt" \ | |
| -subj "/CN=${DOMAIN}" \ | |
| -addext "subjectAltName=DNS:${DOMAIN},DNS:www.${DOMAIN}" 2>/dev/null | |
| # Set permissions | |
| chmod 400 "${SSL_KEY_DIR}/${DOMAIN}.key" | |
| chmod 444 "${SSL_CERT_DIR}/${DOMAIN}.crt" | |
| chown root:apache "${SSL_KEY_DIR}/${DOMAIN}.key" | |
| # Restart Apache | |
| if httpd -t; then | |
| systemctl restart httpd | |
| print_divider | |
| echo -e "\033[1;32mSUCCESS: SSL certificate renewed for ${DOMAIN}!\033[0m" | |
| echo " • New expiration: $(openssl x509 -in ${SSL_CERT_DIR}/${DOMAIN}.crt -noout -enddate | cut -d= -f2)" | |
| echo " • Backup location: ${BACKUP_DIR}" | |
| print_divider | |
| else | |
| echo -e "\033[1;31mERROR: Apache configuration test failed. Reverting changes.\033[0m" >&2 | |
| cp -v "${BACKUP_DIR}/${DOMAIN}.crt.bak-${TIMESTAMP}" "${SSL_CERT_DIR}/${DOMAIN}.crt" | |
| cp -v "${BACKUP_DIR}/${DOMAIN}.key.bak-${TIMESTAMP}" "${SSL_KEY_DIR}/${DOMAIN}.key" | |
| systemctl restart httpd | |
| fi | |
| } | |
| start_tailscale_serve() { | |
| # Check Tailscale status | |
| if ! tailscale status &> /dev/null; then | |
| echo -e "\033[1;31mERROR: Tailscale not running. Start with 'tailscale up' first.\033[0m" >&2 | |
| return 1 | |
| fi | |
| # Check for existing serve | |
| if [ -f "$SERVE_RECORD" ]; then | |
| echo -e "\033[1;33mWARNING: An active Tailscale Serve session already exists!\033[0m" | |
| IFS=':' read -r ACTIVE_DOMAIN ACTIVE_PORT < "$SERVE_RECORD" | |
| echo " • Currently serving: $ACTIVE_DOMAIN on port $ACTIVE_PORT" | |
| read -p "Stop current session and start new one? (y/N) " confirm | |
| confirm=${confirm:-N} | |
| if [[ ! "$confirm" =~ ^[Yy]$ ]]; then | |
| echo "Operation cancelled." | |
| return | |
| fi | |
| # Stop existing serve | |
| tailscale serve --https=443 off | |
| rm -f "$SERVE_RECORD" | |
| fi | |
| # Get site domain | |
| read -p "Enter domain name to expose via Tailscale Serve: " DOMAIN | |
| if [ -z "$DOMAIN" ]; then | |
| echo "Domain name cannot be empty!" >&2 | |
| return 1 | |
| fi | |
| if ! domain_exists "$DOMAIN"; then | |
| echo -e "\033[1;31mERROR: Domain '$DOMAIN' does not exist!\033[0m" >&2 | |
| return 1 | |
| fi | |
| # Get FQDN | |
| NODE_NAME=$(tailscale status --json | jq -r '.Self.HostName') | |
| if [ -z "$NODE_NAME" ]; then | |
| echo -e "\033[1;31mERROR: Could not get Tailscale node name\033[0m" >&2 | |
| return 1 | |
| fi | |
| FQDN="${NODE_NAME}.${TAILSCALE_TAILNET}" | |
| print_divider | |
| echo "You are about to expose:" | |
| echo " • Local Site: https://${DOMAIN}" | |
| echo " • Public URL: https://${FQDN} (via Tailscale Serve)" | |
| echo " • This will make your site accessible to your tailnet" | |
| print_divider | |
| read -p "Continue? (y/N) " confirm | |
| confirm=${confirm:-N} | |
| if [[ ! "$confirm" =~ ^[Yy]$ ]]; then | |
| echo "Operation cancelled." | |
| return | |
| fi | |
| # Start Tailscale Serve with HTTPS | |
| echo "Starting Tailscale Serve with HTTPS..." | |
| tailscale serve --bg --https=443 "https://${DOMAIN}" | |
| # Record status | |
| echo "${DOMAIN}:443" > "$SERVE_RECORD" | |
| chmod 600 "$SERVE_RECORD" | |
| print_divider | |
| echo -e "\033[1;32mSUCCESS: Tailscale Serve started!\033[0m" | |
| echo " • Local Site: https://${DOMAIN}" | |
| echo " • Public URL: \033[1;34mhttps://${FQDN}\033[0m" | |
| echo " • Tailscale Status: $(tailscale serve status)" | |
| print_divider | |
| echo "Note: All links will work correctly with HTTPS" | |
| echo " Certificate is automatically managed by Tailscale" | |
| print_divider | |
| } | |
| stop_tailscale_serve() { | |
| if [ ! -f "$SERVE_RECORD" ]; then | |
| echo -e "\033[1;31mERROR: No active Tailscale Serve session found!\033[0m" >&2 | |
| return 1 | |
| fi | |
| # Get current serve info | |
| IFS=':' read -r DOMAIN PORT < "$SERVE_RECORD" | |
| NODE_NAME=$(tailscale status --json | jq -r '.Self.HostName') | |
| FQDN="${NODE_NAME}.${TAILSCALE_TAILNET}" | |
| print_divider | |
| echo "Active Tailscale Serve:" | |
| echo " • Domain: $DOMAIN" | |
| echo " • Port: $PORT" | |
| echo " • Public URL: https://${FQDN}" | |
| print_divider | |
| read -p "Stop this Tailscale Serve session? (y/N) " confirm | |
| confirm=${confirm:-N} | |
| if [[ ! "$confirm" =~ ^[Yy]$ ]]; then | |
| echo "Operation cancelled." | |
| return | |
| fi | |
| # Stop Tailscale Serve | |
| tailscale serve --https=443 off | |
| rm -f "$SERVE_RECORD" | |
| print_divider | |
| echo -e "\033[1;32mSUCCESS: Tailscale Serve stopped!\033[0m" | |
| echo " • Domain: $DOMAIN is no longer exposed" | |
| print_divider | |
| } | |
| remove_site() { | |
| while true; do | |
| read -p "Enter domain name to remove: " DOMAIN | |
| if [ -z "$DOMAIN" ]; then | |
| echo "Domain name cannot be empty!" >&2 | |
| continue | |
| fi | |
| if ! domain_exists "$DOMAIN"; then | |
| echo -e "\033[1;31mERROR: Domain '$DOMAIN' does not exist!\033[0m" >&2 | |
| return 1 | |
| fi | |
| is_wordpress=false | |
| if wp_site_exists "$DOMAIN"; then | |
| is_wordpress=true | |
| wp_info=$(grep "^${DOMAIN}:" "$RECORD_FILE") | |
| IFS=':' read -ra parts <<< "$wp_info" | |
| db_name="${parts[1]}" | |
| db_user="${parts[2]}" | |
| fi | |
| print_divider | |
| echo "WARNING: You are about to PERMANENTLY remove:" | |
| echo " • Domain: $DOMAIN" | |
| echo " • Document root: /var/www/${DOMAIN}" | |
| echo " • SSL certificates" | |
| echo " • Apache configuration" | |
| echo " • Log files" | |
| if $is_wordpress; then | |
| echo " • WordPress database: $db_name" | |
| echo " • Database user: $db_user" | |
| fi | |
| print_divider | |
| read -p "ARE YOU SURE? This cannot be undone! (y/N) " confirm | |
| confirm=${confirm:-N} | |
| if [[ "$confirm" =~ ^[Yy]$ ]]; then | |
| break | |
| else | |
| echo "Operation cancelled." | |
| return | |
| fi | |
| done | |
| # Remove WordPress database if exists | |
| if wp_site_exists "$DOMAIN"; then | |
| echo "Removing WordPress database..." | |
| remove_db_user "$DOMAIN" | |
| fi | |
| # Remove Apache configs | |
| rm -vf "/etc/httpd/conf.d/${DOMAIN}.conf" | |
| # Remove document root | |
| DOC_ROOT="/var/www/${DOMAIN}" | |
| rm -rvf "$DOC_ROOT" | |
| # Remove SSL certs | |
| SSL_CERT_DIR="/etc/pki/tls/certs/${DOMAIN}" | |
| SSL_KEY_DIR="/etc/pki/tls/private/${DOMAIN}" | |
| rm -rvf "$SSL_CERT_DIR" "$SSL_KEY_DIR" | |
| # Remove log files | |
| rm -vf "/var/log/httpd/${DOMAIN}_access.log" "/var/log/httpd/${DOMAIN}_error.log" | |
| # Remove hosts entry | |
| sed -i "/${DOMAIN}/d" /etc/hosts | |
| # Restart Apache | |
| if httpd -t; then | |
| systemctl restart httpd | |
| print_divider | |
| echo -e "\033[1;32mSUCCESS: Site ${DOMAIN} has been completely removed.\033[0m" | |
| echo " • All related files and configurations deleted" | |
| if $is_wordpress; then | |
| echo " • Database '$db_name' and user '$db_user' removed" | |
| fi | |
| print_divider | |
| # Disable Tailscale Serve if it was active | |
| if [ -f "$SERVE_RECORD" ]; then | |
| IFS=':' read -r SERVE_DOMAIN _ < "$SERVE_RECORD" | |
| if [ "$SERVE_DOMAIN" == "$DOMAIN" ]; then | |
| echo "Disabling Tailscale Serve for ${DOMAIN}..." | |
| tailscale serve off | |
| rm -f "$SERVE_RECORD" | |
| echo "Tailscale Serve disabled" | |
| print_divider | |
| fi | |
| fi | |
| else | |
| echo -e "\033[1;31mERROR: Apache configuration test failed. Manual cleanup needed.\033[0m" >&2 | |
| fi | |
| } | |
| # Main menu | |
| while true; do | |
| echo -e "\n\033[1;34mApache Site Management\033[0m" | |
| print_divider | |
| echo "1. Add a new site" | |
| echo "2. Renew SSL certificate" | |
| echo "3. Remove a site" | |
| echo "4. Add a WordPress site" | |
| echo "5. Start Tailscale Serve" | |
| echo "6. Stop Tailscale Serve" | |
| echo "7. Quit" | |
| print_divider | |
| # Show Tailscale status | |
| if tailscale status &> /dev/null; then | |
| TS_STATUS=$(tailscale status --json | jq -r '.BackendState') | |
| TS_FQDN=$(tailscale status --json | jq -r '.Self.HostName + "." + .MagicDNSSuffix') | |
| echo -e "Tailscale: \033[1;32m$TS_STATUS\033[0m | FQDN: \033[1;34m$TS_FQDN\033[0m" | |
| # Show active serve status | |
| if [ -f "$SERVE_RECORD" ]; then | |
| IFS=':' read -r SERVE_DOMAIN SERVE_PORT < "$SERVE_RECORD" | |
| echo -e "Active Serve: \033[1;33m$SERVE_DOMAIN\033[0m at \033[1;33mhttps://$TS_FQDN\033[0m" | |
| else | |
| echo -e "Active Serve: \033[1;31mNone\033[0m" | |
| fi | |
| print_divider | |
| fi | |
| read -p "Choose an option (1-7): " choice | |
| case $choice in | |
| 1) add_site;; | |
| 2) renew_ssl;; | |
| 3) remove_site;; | |
| 4) add_wordpress_site;; | |
| 5) start_tailscale_serve;; | |
| 6) stop_tailscale_serve;; | |
| 7) echo "Exiting..."; exit 0;; | |
| *) echo -e "\033[1;31mInvalid option. Please choose 1-7.\033[0m";; | |
| esac | |
| read -n 1 -s -r -p "Press any key to continue..." | |
| clear | |
| done |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment