From 16375b89ffcd8298d54c216330ed2c173f3c0717 Mon Sep 17 00:00:00 2001 From: Anthony Date: Sat, 5 Apr 2025 01:10:15 +0800 Subject: [PATCH] Updated install shell script --- scripts/install-wordpress.sh | 681 ++++++++++++++++++++++------------- 1 file changed, 425 insertions(+), 256 deletions(-) diff --git a/scripts/install-wordpress.sh b/scripts/install-wordpress.sh index b1c7fe7..6174be1 100644 --- a/scripts/install-wordpress.sh +++ b/scripts/install-wordpress.sh @@ -1,246 +1,377 @@ #!/bin/bash +# +# Script to automate WordPress installation. +# Includes dependency checks, WP-CLI installation, database setup, +# WordPress core installation, and configuration. +# -# Exit on error +# --- Configuration --- + +# Exit immediately if a command exits with a non-zero status. set -e +# Treat unset variables as an error when substituting. +set -u +# Pipe commands return the exit status of the last command in the pipe +set -o pipefail -# Colors for output +# Colors for output messages RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' +BLUE='\033[0;34m' NC='\033[0m' # No Color -# Default values for WordPress admin -WP_ADMIN_USER="admin" -WP_ADMIN_PASS="admin" -WP_ADMIN_EMAIL="admin@example.com" +# --- Default Values --- +# Avoid insecure defaults. Consider making these mandatory or generating random ones. +# Leaving them blank to force user input or argument passing. +WP_ADMIN_USER="" +WP_ADMIN_PASS="" +WP_ADMIN_EMAIL="" +WP_ROOT="/var/www/webroot/ROOT" # Default WordPress root directory +DOMAIN="" # Domain will be determined or required +DB_HOST="127.0.0.1" +DB_ROOT_USER="root" +DB_ROOT_PASS="" # Require user to provide this for security +SKIP_DB_ROOT_RESET="false" # By default, perform the root password reset (use --skip-db-root-reset to disable) +WEB_USER="litespeed" # Web server user (e.g., www-data, apache, nginx) +WEB_GROUP="litespeed" # Web server group -# Function to display usage -usage() { - echo "Usage: $0 [options]" - echo "" - echo "Options:" - echo " --wpusername=USERNAME WordPress admin username (default: admin)" - echo " --wppassword=PASSWORD WordPress admin password (default: admin)" - echo " --wpemail=EMAIL WordPress admin email (default: admin@example.com)" - echo " -h, --help Display this help message" - echo "" - echo "Example:" - echo " $0 --wpusername=myusername --wppassword=mypassword123 --wpemail=myemail@domain.com" +# --- Helper Functions --- + +# Print informational messages +info() { + printf "${BLUE}[INFO] %s${NC}\n" "$@" +} + +# Print success messages +success() { + printf "${GREEN}[SUCCESS] %s${NC}\n" "$@" +} + +# Print warning messages +warning() { + printf "${YELLOW}[WARNING] %s${NC}\n" "$@" +} + +# Print error messages and exit +error_exit() { + printf "${RED}[ERROR] %s${NC}\n" "$@" >&2 exit 1 } -# Parse command line arguments -while [ $# -gt 0 ]; do +# Function to display usage information +usage() { + printf "Usage: %s [OPTIONS]\n" "$0" + printf "\n" + printf "Automates the installation of WordPress.\n" + printf "\n" + printf "Required Options:\n" + printf " --wpusername=USERNAME WordPress admin username (mandatory)\n" + printf " --wppassword=PASSWORD WordPress admin password (mandatory)\n" + printf " --wpemail=EMAIL WordPress admin email (mandatory)\n" + printf " --dbrootpass=PASSWORD Current MySQL/MariaDB root password (mandatory unless resetting)\n" + printf "\n" + printf "Optional Options:\n" + printf " --wproot=PATH WordPress installation directory (default: %s)\n" "$WP_ROOT" + printf " --domain=DOMAIN Domain name for the site (default: auto-detected from hostname)\n" + printf " --webuser=USER Web server user (default: %s)\n" "$WEB_USER" + printf " --webgroup=GROUP Web server group (default: %s)\n" "$WEB_GROUP" + printf " --dbhost=HOST Database host (default: %s)\n" "$DB_HOST" + printf " --reset-db-root-pass Perform the risky root password reset (requires sudo without password)\n" + printf " -h, --help Display this help message\n" + printf "\n" + printf "Example:\n" + printf " %s --wpusername=myuser --wppassword='securePass' --wpemail=me@example.com --dbrootpass='currentRootPass'\n" "$0" + printf " %s --wpusername=myuser --wppassword='securePass' --wpemail=me@example.com --reset-db-root-pass --domain=example.com\n" "$0" + exit 1 +} + +# Function to check if a command exists +command_exists() { + command -v "$1" &> /dev/null +} + +# Function to generate a random secure password +generate_password() { + openssl rand -base64 16 # Increased length slightly +} + +# Function to clean up temporary files +cleanup() { + info "Cleaning up temporary files..." + rm -f "$WP_CLI_CONFIG_PATH" + # Add any other cleanup tasks here +} + +# --- Argument Parsing --- +# Using getopt for better argument handling +TEMP=$(getopt -o h --longoptions help,wpusername:,wppassword:,wpemail:,wproot:,domain:,dbhost:,dbrootpass:,reset-db-root-pass,webuser:,webgroup: -n "$0" -- "$@") +if [ $? != 0 ]; then + error_exit "Terminating... Invalid arguments." +fi + +# Note the quotes around "$TEMP": they are essential! +eval set -- "$TEMP" +unset TEMP + +PERFORM_DB_ROOT_RESET="false" + +while true; do case "$1" in - --wpusername=*) - WP_ADMIN_USER="${1#*=}" - ;; - --wppassword=*) - WP_ADMIN_PASS="${1#*=}" - ;; - --wpemail=*) - WP_ADMIN_EMAIL="${1#*=}" - ;; - -h|--help) - usage - ;; - *) - echo -e "${RED}Error: Invalid option $1${NC}" - usage - ;; + --wpusername) WP_ADMIN_USER="$2"; shift 2 ;; + --wppassword) WP_ADMIN_PASS="$2"; shift 2 ;; + --wpemail) WP_ADMIN_EMAIL="$2"; shift 2 ;; + --wproot) WP_ROOT="$2"; shift 2 ;; + --domain) DOMAIN="$2"; shift 2 ;; + --dbhost) DB_HOST="$2"; shift 2 ;; + --dbrootpass) DB_ROOT_PASS="$2"; shift 2 ;; + --reset-db-root-pass) PERFORM_DB_ROOT_RESET="true"; shift 1 ;; + --webuser) WEB_USER="$2"; shift 2 ;; + --webgroup) WEB_GROUP="$2"; shift 2 ;; + -h|--help) usage ;; + --) shift ; break ;; # End of options + *) error_exit "Internal error! Unexpected option: $1";; esac - shift done -# Validate parameters -if [[ -z "$WP_ADMIN_USER" ]]; then - echo -e "${RED}Error: WordPress admin username cannot be empty${NC}" - usage +# --- Validation --- +info "Validating parameters..." + +if [[ -z "$WP_ADMIN_USER" ]]; then error_exit "WordPress admin username (--wpusername) is required."; fi +if [[ -z "$WP_ADMIN_PASS" ]]; then error_exit "WordPress admin password (--wppassword) is required."; fi +if [[ -z "$WP_ADMIN_EMAIL" ]]; then error_exit "WordPress admin email (--wpemail) is required."; fi +if [[ ! "$WP_ADMIN_EMAIL" =~ ^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$ ]]; then error_exit "Invalid email format for --wpemail."; fi +if [[ "$PERFORM_DB_ROOT_RESET" == "false" && -z "$DB_ROOT_PASS" ]]; then error_exit "Database root password (--dbrootpass) is required unless --reset-db-root-pass is used."; fi +if [[ "$PERFORM_DB_ROOT_RESET" == "true" && -n "$DB_ROOT_PASS" ]]; then warning "Both --reset-db-root-pass and --dbrootpass provided. Will perform reset and ignore provided root password."; fi +if [[ ! -d "$WP_ROOT" ]]; then error_exit "WordPress root directory '$WP_ROOT' does not exist or is not a directory."; fi +if ! id "$WEB_USER" &>/dev/null; then error_exit "Web user '$WEB_USER' does not exist."; fi +if ! getent group "$WEB_GROUP" &>/dev/null; then error_exit "Web group '$WEB_GROUP' does not exist."; fi + +# --- Determine Domain --- +if [[ -z "$DOMAIN" ]]; then + if ! command_exists hostname; then error_exit "'hostname' command not found. Please specify --domain."; fi + FULL_HOSTNAME=$(hostname -f) + # Attempt to remove common node prefixes, make this more robust if needed + DOMAIN=$(echo "$FULL_HOSTNAME" | sed -E 's/^(node[0-9]*-|wp-|web-|host-)//') + if [[ -z "$DOMAIN" || "$DOMAIN" == "$FULL_HOSTNAME" ]]; then + warning "Could not reliably determine domain from hostname '$FULL_HOSTNAME'. Using it as is." + DOMAIN="$FULL_HOSTNAME" + fi + info "Auto-detected domain: $DOMAIN (Use --domain to override)" +else + info "Using specified domain: $DOMAIN" fi -if [[ -z "$WP_ADMIN_PASS" ]]; then - echo -e "${RED}Error: WordPress admin password cannot be empty${NC}" - usage +# --- Dependency Checks --- +info "Checking dependencies..." +declare -a dependencies=("php" "mysql" "curl" "openssl" "sudo" "hostname" "sed" "systemctl" "getopt") +for cmd in "${dependencies[@]}"; do + if ! command_exists "$cmd"; then + error_exit "Required command '$cmd' is not installed. Please install it first." + fi +done +# Specific check for pkill if reset is chosen +if [[ "$PERFORM_DB_ROOT_RESET" == "true" ]]; then + if ! command_exists pkill; then error_exit "'pkill' command not found, but required for --reset-db-root-pass."; fi + if ! command_exists mysqld_safe; then error_exit "'mysqld_safe' command not found, but required for --reset-db-root-pass."; fi +fi +success "All dependencies found." + +# --- WP-CLI Setup --- +WP_CLI_PATH="/usr/local/bin/wp" + +# Check if WP-CLI is installed and executable +if ! command_exists wp; then + info "WP-CLI not found. Installing WP-CLI..." + if ! curl -o wp-cli.phar https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar; then + error_exit "Failed to download WP-CLI." + fi + chmod +x wp-cli.phar + if ! sudo mv wp-cli.phar "$WP_CLI_PATH"; then + error_exit "Failed to move WP-CLI to $WP_CLI_PATH. Check sudo permissions." + fi + # Verify installation + if ! command_exists wp; then + error_exit "WP-CLI installation failed unexpectedly." + fi + success "WP-CLI installed successfully to $WP_CLI_PATH" +else + success "WP-CLI is already installed." fi -if [[ ! "$WP_ADMIN_EMAIL" =~ ^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$ ]]; then - echo -e "${RED}Error: Invalid email format${NC}" - usage -fi - -# Define WordPress root directory -WP_ROOT="/var/www/webroot/ROOT" - -# Get the domain without the node prefix -FULL_HOSTNAME=$(hostname -f) -DOMAIN=$(echo "$FULL_HOSTNAME" | sed 's/^node[0-9]*-//') - -# Set HTTP_HOST for WP-CLI +# Set up temporary WP-CLI config for HTTP_HOST if needed export WP_CLI_CONFIG_PATH="/tmp/wp-cli-config-$RANDOM.yml" cat > "$WP_CLI_CONFIG_PATH" < /dev/null; then - echo -e "${RED}PHP is not installed. Please install PHP first.${NC}" - exit 1 -fi +if [[ "$PERFORM_DB_ROOT_RESET" == "true" ]]; then + # --- Risky Root Password Reset --- + warning "Attempting to reset MariaDB/MySQL root password. This is risky!" + new_root_password=$(generate_password) + info "New root password will be: $new_root_password" -# Check if MySQL/MariaDB is installed -if ! command -v mysql &> /dev/null; then - echo -e "${RED}MySQL/MariaDB is not installed. Please install MySQL/MariaDB first.${NC}" - exit 1 -fi + info "Stopping MariaDB service..." + if ! sudo systemctl stop mariadb; then error_exit "Failed to stop MariaDB service."; fi + # Wait a moment to ensure it stopped + sleep 3 -# Check if WordPress root directory exists -if [ ! -d "$WP_ROOT" ]; then - echo -e "${RED}WordPress root directory $WP_ROOT does not exist.${NC}" - exit 1 -fi + info "Starting MariaDB in safe mode (skip-grant-tables)..." + sudo mysqld_safe --skip-grant-tables --skip-networking & + MYSQLD_SAFE_PID=$! + # Wait for MariaDB to likely start in safe mode + sleep 10 # Increased wait time for reliability -# Change to WordPress root directory -cd "$WP_ROOT" - -# Install WP-CLI if not already installed -if ! command -v wp &> /dev/null; then - echo -e "${YELLOW}Installing WP-CLI...${NC}" - curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar - chmod +x wp-cli.phar - sudo mv wp-cli.phar /usr/local/bin/wp - - # Verify WP-CLI installation - if ! command -v wp &> /dev/null; then - echo -e "${RED}Failed to install WP-CLI${NC}" - exit 1 - fi - echo -e "${GREEN}WP-CLI installed successfully${NC}" -else - echo -e "${GREEN}WP-CLI is already installed${NC}" -fi - -# Database Preparation -echo -e "${YELLOW}Preparing database...${NC}" - -# Automatically generate a new secure password for the root user -new_root_password=$(openssl rand -base64 12) - -# Generate random database name, user, and password for the new database -DB_NAME="db_$(openssl rand -hex 4)" -DB_USER="user_$(openssl rand -hex 4)" -DB_PASSWORD="$(openssl rand -base64 12)" -DB_HOST="127.0.0.1" - -echo -e "${YELLOW}New root password will be: $new_root_password${NC}" -echo -e "${YELLOW}New database credentials:${NC}" -echo -e "Database Name: $DB_NAME" -echo -e "Database User: $DB_USER" -echo -e "Database Password: $DB_PASSWORD" - -echo -e "${YELLOW}Attempting to stop the MariaDB service...${NC}" -# Stop the MariaDB service -sudo systemctl stop mariadb - -echo -e "${YELLOW}Starting MariaDB in safe mode...${NC}" -# Start MariaDB in safe mode with no networking and no grants -sudo mysqld_safe --skip-grant-tables --skip-networking & - -# Wait for MariaDB to fully start in safe mode -sleep 5 - -echo -e "${YELLOW}Resetting the root password...${NC}" -# Reset the root password in safe mode -sudo mysql -u root < /dev/null; then + error_exit "Failed to connect to database using provided root credentials. Check user, password, and host." + fi + success "Database root connection successful." fi +# --- Create WordPress Database and User --- +info "Creating WordPress database '$DB_NAME' and user '$DB_USER'..." +# Use printf for safer password injection into the command +SQL_COMMAND=$(printf "CREATE DATABASE IF NOT EXISTS %s CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER IF NOT EXISTS '%s'@'%s' IDENTIFIED BY '%s'; GRANT ALL PRIVILEGES ON %s.* TO '%s'@'%s'; FLUSH PRIVILEGES;" \ + "$DB_NAME" "$DB_USER" "$DB_HOST" "$DB_PASSWORD" "$DB_NAME" "$DB_USER" "$DB_HOST") + +if ! mysql -u "$DB_ROOT_USER" -p"$DB_ROOT_PASS" -h "$DB_HOST" -e "$SQL_COMMAND"; then + error_exit "Failed to create WordPress database or user. Check MySQL/MariaDB logs and permissions." +fi +success "Database and user created successfully." + +# --- WordPress Installation --- +info "Navigating to WordPress root: $WP_ROOT" +cd "$WP_ROOT" || error_exit "Failed to change directory to $WP_ROOT" + # Backup existing wp-config.php if it exists -if [ -f "wp-config.php" ]; then - echo -e "${YELLOW}Backing up existing wp-config.php...${NC}" - cp wp-config.php wp-config.php.bak +if [[ -f "wp-config.php" ]]; then + BACKUP_NAME="wp-config.php.bak.$(date +%Y%m%d%H%M%S)" + info "Backing up existing wp-config.php to $BACKUP_NAME" + cp wp-config.php "$BACKUP_NAME" fi -# Download WordPress core if not already present -if [ ! -f "index.php" ] && [ ! -d "wp-admin" ]; then - echo -e "${YELLOW}WordPress files not detected. Downloading WordPress core...${NC}" - wp core download --skip-content --allow-root - - # Now WordPress core installation will handle theme installation automatically - # since we removed the --skip-themes flag from the wp core install command - echo -e "${GREEN}WordPress core downloaded successfully${NC}" +# Download WordPress core files if necessary (index.php is a good indicator) +# Run wp commands as the web user if possible, falling back to --allow-root if needed +WP_RUN_ARGS=("--path=$WP_ROOT") +# Determine if sudo is needed to run as web user +SUDO_CMD="" +if [[ "$(id -u)" -ne "$(id -u "$WEB_USER")" ]]; then + SUDO_CMD="sudo -u $WEB_USER" + # Check if we can sudo without password, otherwise need --allow-root + if ! sudo -n -u "$WEB_USER" true &>/dev/null; then + warning "Cannot sudo to '$WEB_USER' without a password. Using --allow-root for WP-CLI commands." + SUDO_CMD="" # Clear sudo command + WP_RUN_ARGS+=("--allow-root") + else + info "Running WP-CLI commands as user '$WEB_USER'." + fi +fi + + +if [[ ! -f "index.php" || ! -d "wp-admin" ]]; then + info "WordPress core files not found. Downloading..." + if ! $SUDO_CMD wp core download "${WP_RUN_ARGS[@]}" --skip-content --version=latest; then + error_exit "Failed to download WordPress core files." + fi + success "WordPress core downloaded." else - echo -e "${GREEN}WordPress files already exist. Skipping download.${NC}" + info "WordPress files already exist. Skipping download." fi -# Immediate check to directly create wp-config.php regardless of previous steps -# This is a critical fix to ensure wp-config.php exists before installation continues -echo -e "${YELLOW}CRITICAL FIX: Directly creating wp-config.php to prevent errors...${NC}" -if [ ! -f "wp-config.php" ]; then - echo -e "${RED}wp-config.php is still missing. Creating it directly...${NC}" - cat > wp-config.php </dev/null || { + warning "Could not generate salts using WP-CLI, falling back to openssl (less standard format)." + echo "define( 'AUTH_KEY', '$(generate_password)' );" + echo "define( 'SECURE_AUTH_KEY', '$(generate_password)' );" + echo "define( 'LOGGED_IN_KEY', '$(generate_password)' );" + echo "define( 'NONCE_KEY', '$(generate_password)' );" + echo "define( 'AUTH_SALT', '$(generate_password)' );" + echo "define( 'SECURE_AUTH_SALT', '$(generate_password)' );" + echo "define( 'LOGGED_IN_SALT', '$(generate_password)' );" + echo "define( 'NONCE_SALT', '$(generate_password)' );" +}) +# Use cat with heredoc for wp-config.php creation +cat > wp-config.php <