#!/bin/bash # # wordpress-tools # https://git.stack-source.com/msb/wordpress-tools # MIT License Copyright (c) 2021 Matthew Saunders Brown # require root if [ "${EUID}" -ne 0 ]; then echo "This script must be run as root" exit fi virtualhost_basedir="/srv/www" virtualhost_htdocsdir="html" declare -a input_keys_index input_keys_index=(v r t e u p m d n w x s) declare -A input_keys_array input_keys_array[v]="VirtualHost" input_keys_array[r]="URL" input_keys_array[t]="Site Title" input_keys_array[e]="Admin Email" input_keys_array[u]="Admin Username" input_keys_array[p]="Admin Password" input_keys_array[m]="MySQL Hostname" input_keys_array[d]="MySQL Database" input_keys_array[n]="MySQL Username" input_keys_array[w]="MySQL Password" input_keys_array[x]="MySQL DB Prefix" input_keys_array[s]="Shell Username" declare -A input_values_array help() { thisfilename=$(basename -- "$0") echo "$thisfilename - Install WordPress to a specific VirtualHost." echo "" echo "Usage: $thisfilename [-v VirtualHost] [-r URL] [-t Site Title] [-e Admin Email] [-u Admin Username] [-p Admin Password] [-h MySQL Hostname] [-d MySQL Database] [-n MySQL Username] [-w MySQL Password] [-x MySQL DB Prefix] [-s Shell Username]" echo "" echo " -v VirtualHost VirtualHost that WordPress install is for, only option that is required - all others have automatic defaults." echo " -r URL Site URL for WordPress install, defaults to VirtualHost." echo " -t Site Title Site Title for WordPress install, defaults to VirtualHost." echo " -e Admin Email Email address for WordPress admin user, defaults to 'Admin username'@'VirtualHost'" echo " -u Admin Username Username for WordPress admin user, defaults to Shell Username" echo " -p Admin Password Password for WordPress admin user, random password is generated if not set." echo " -m MySQL Hostname MySQL Hostname, defaults to 127.0.0.1" echo " -d MySQL Database MySQL Database, defaults to 'VirtualHost' with dots & dashes changed from symbols to words if not specified." echo " -n MySQL Username MySQL Username, defaults to 'Shell Username'@'VirtualHost' if not specified." echo " -w MySQL Password MySQL Hostname, random password is generated if not set." echo " -x MySQL DB Prefix WordPress db table prefix, defaults to wp_" echo " -s Shell Username System user that owns website files for this VirtualHost, autodetected and reset if not specified correctly." echo " -f Force install - skips install confirmation step, for automated installs." echo " -h Print this help." echo "" echo " You will be prompted to any options that were not" echo " specified on the command line and given a chance" echo " to confirm before performing the install unless the" echo " -f option is specified." exit } # force (-f) defaults to false force=false # set any options that were passed while getopts "v:r:t:e:u:p:m:d:n:w:x:s:fh" opt; do case "${opt}" in h ) help exit;; v ) input_values_array[v]=${OPTARG} ;; r ) input_values_array[r]=${OPTARG} ;; t ) input_values_array[t]=${OPTARG} ;; e ) input_values_array[e]=${OPTARG} ;; u ) input_values_array[u]=${OPTARG} ;; p ) input_values_array[p]=${OPTARG} ;; m ) input_values_array[m]=${OPTARG} ;; d ) input_values_array[d]=${OPTARG} ;; n ) input_values_array[n]=${OPTARG} ;; w ) input_values_array[w]=${OPTARG} ;; x ) input_values_array[x]=${OPTARG} ;; s ) input_values_array[s]=${OPTARG} ;; f ) force=true ;; \? ) echo "Invalid option: $OPTARG" 1>&2 exit 1;; : ) echo "Invalid option: $OPTARG requires an argument" 1>&2 exit 1;; esac done # v - virtualhost function validate_v() { if [ -d "$virtualhost_basedir/${input_values_array[v]}" ]; then if [ -d "$virtualhost_basedir/${input_values_array[v]}/$virtualhost_htdocsdir" ]; then # make sure DocumentRoot is empty (except for possible index.html file) htdocsdir_file_count=`/usr/bin/ls $virtualhost_basedir/${input_values_array[v]}/$virtualhost_htdocsdir|grep -v index.html|wc -l` if [ $htdocsdir_file_count -gt 0 ]; then echo "$virtualhost_basedir/${input_values_array[v]}/$virtualhost_htdocsdir appears to contain an existing website." echo "Manually remove all files before attempting to install WordPress" exit fi else echo "${input_values_array[v]} is installed, but DocumentRoot for ${input_values_array[v]} does not exist." echo "$virtualhost_basedir/${input_values_array[v]}/$virtualhost_htdocsdir" exit fi else echo "VirtualHost ${input_values_array[v]} is not installed on this server." echo "$virtualhost_basedir/${input_values_array[v]}/$virtualhost_htdocsdir" unset input_values_array[v] fi } if [ -n "${input_values_array[v]}" ] ; then validate_v fi if [ -z "${input_values_array[v]}" ] ; then while [ -z "${input_values_array[v]}" ]; do read -p "Enter the VirtualHost for WordPress install: " virtualhost if [ -n "$virtualhost" ] ; then input_values_array[v]=$virtualhost validate_v fi done fi # s - Shell Username function validate_s() { # force shell user value, user can't override shell_username=$(stat -c '%U' $virtualhost_basedir/${input_values_array[v]}) if [[ ${input_values_array[s]} != $shell_username ]]; then echo "ERROR: Incorrect Shell Username, forcing value reset." input_values_array[s]=$shell_username fi } if [ -z "${input_values_array[s]}" ] ; then input_values_array[s]=$(stat -c '%U' $virtualhost_basedir/${input_values_array[v]}) fi if [ -n "${input_values_array[e]}" ] ; then validate_s fi # u - URL function validate_u() { if [[ ${input_values_array[r]} != *"${input_values_array[v]}"* ]] ; then echo "URL (${input_values_array[r]}) does not appear to be based on VirtualHost (${input_values_array[v]})" unset input_values_array[r] fi } if [ -z "${input_values_array[r]}" ] ; then input_values_array[r]="www.${input_values_array[v]}" fi if [ -n "${input_values_array[r]}" ] ; then validate_u fi # t - Site Title if [ -z "${input_values_array[t]}" ] ; then input_values_array[t]="${input_values_array[v]}" fi # e - Admin Email function validate_e() { regex="^[a-z0-9!#\$%&'*+/=?^_\`{|}~-]+(\.[a-z0-9!#$%&'*+/=?^_\`{|}~-]+)*@([a-z0-9]([a-z0-9-]*[a-z0-9])?\.)+[a-z0-9]([a-z0-9-]*[a-z0-9])?\$" if ! [[ ${input_values_array[e]} =~ $regex ]] ; then read -p "ERROR: Invalid email address, please re-enter: " admin_email if [ -n "$admin_email" ] ; then input_values_array[e]=$admin_email validate_e fi fi } if [ -z "${input_values_array[e]}" ] ; then input_values_array[e]="${input_values_array[s]}@${input_values_array[v]}" fi if [ -n "${input_values_array[e]}" ] ; then validate_e fi # u - Admin Username if [ -z "${input_values_array[u]}" ] ; then input_values_array[u]=${input_values_array[s]} fi # p - Admin Password if [ -z "${input_values_array[p]}" ] ; then input_values_array[p]=`pwgen -1 8` fi # m - MySQL Hostname if [ -z "${input_values_array[m]}" ] ; then if [ -f "$virtualhost_basedir/${input_values_array[v]}/.my.cnf" ]; then input_values_array[m]=`grep host /srv/www/${input_values_array[v]}/.my.cnf |cut -d = -f 2` else input_values_array[m]="127.0.0.1" fi fi # d - MySQL Database if [ -z "${input_values_array[d]}" ] ; then if [ -f "$virtualhost_basedir/${input_values_array[v]}/.my.cnf" ]; then input_values_array[d]=`grep database /srv/www/${input_values_array[v]}/.my.cnf |cut -d = -f 2` else mysql_database=${input_values_array[v]} mysql_database=${mysql_database//./dot} mysql_database=${mysql_database//-/dash} input_values_array[d]=$mysql_database fi fi # n - MySQL Username if [ -z "${input_values_array[n]}" ] ; then if [ -f "$virtualhost_basedir/${input_values_array[v]}/.my.cnf" ]; then input_values_array[n]=`grep user /srv/www/${input_values_array[v]}/.my.cnf |cut -d = -f 2` else input_values_array[n]="${input_values_array[s]}@${input_values_array[v]}" fi fi # w - MySQL Password if [ -z "${input_values_array[w]}" ] ; then if [ -f "$virtualhost_basedir/${input_values_array[v]}/.my.cnf" ]; then input_values_array[w]=`grep password /srv/www/${input_values_array[v]}/.my.cnf |cut -d = -f 2` else input_values_array[w]=`pwgen -1 16` fi fi # w - MySQL Password function validate_w() { mysql_username_count=`mysql -s -N -e "SELECT COUNT(*) FROM mysql.user WHERE User='${input_values_array[n]}'"` if [[ "$mysql_username_count" -gt 0 ]]; then mysql_password_verification=`mysql -s -A -N -e "SELECT COUNT(1) Password_is_OK FROM mysql.user WHERE user='${input_values_array[n]}' AND password=PASSWORD('${input_values_array[w]}')"` if [[ "$mysql_password_verification" -ne 1 ]]; then read -p "ERROR: Invalid MySQL Password for existing MySQL User ${input_values_array[n]}, please enter current password: " mysql_password if [ -n "$mysql_password" ] ; then input_values_array[w]=$mysql_password restart_script fi fi fi } # x - MySQL DB Prefix function validate_x() { if mysql -e "USE ${input_values_array[d]}" 2> /dev/null; then mysql_db_prefix=`echo ${input_values_array[x]} |sed 's|_|\\\_|g'` mysql_db_prefix_count=`mysql -s -N -e "SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '${input_values_array[d]}' AND TABLE_NAME LIKE '$mysql_db_prefix%'"` if [[ "$mysql_db_prefix_count" -gt 0 ]]; then read -p "One or more MySQL tables with DB Prefix '${input_values_array[x]}' already exist, please enter new prefix: " mysql_db_prefix if [ -n "$mysql_db_prefix" ] ; then input_values_array[x]=$mysql_db_prefix restart_script fi fi fi } if [ -z "${input_values_array[x]}" ] ; then input_values_array[x]="wp_" fi # if [ -n "${input_values_array[x]}" ] ; then # validate_x # fi # display confirmation function display_confirmation() { echo for key in "${!input_keys_index[@]}" ; do value=${input_keys_index[$key]} echo "$value - ${input_keys_array[$value]}: ${input_values_array[$value]}" done echo echo "i - install now with these settings" echo "q - quit without installing" echo read -p "Select option to edit or install/quit: " option echo } function restart_script() { # set command line args cli_args= for key in "${!input_values_array[@]}" ; do value=${input_values_array[$key]} cli_args="$cli_args -$key '$value'" done # echo "${0} $cli_args" echo eval ${0} $cli_args exit } if [[ "$force" == "false" ]]; then display_confirmation else option="i" fi if [[ "$option" == "i" ]]; then # validate MySQL DB Prefix validate_x # validate MySQL User Password validate_w echo echo "Installing WP for VirtualHost ${input_values_array[v]} now..." # create database if it doesn't already exist if ! mysql -e "USE ${input_values_array[d]}" 2> /dev/null; then mysqladmin create ${input_values_array[d]} fi # create mysql user if they don't already exist if [[ "$mysql_username_count" -eq 0 ]]; then mysql -e "CREATE USER '${input_values_array[n]}'@'${input_values_array[m]}' IDENTIFIED BY '${input_values_array[w]}'" fi # add db privileges for mysql user if no already enabled if ! mysql --host=${input_values_array[m]} --user=${input_values_array[n]} --password=${input_values_array[w]} -e "USE ${input_values_array[d]}" 2> /dev/null; then mysql -e "GRANT ALL PRIVILEGES ON ${input_values_array[d]}.* TO '${input_values_array[n]}'@'${input_values_array[m]}'" mysqladmin flush-privileges fi # switch to Shell User and install WordPress sudo -u ${input_values_array[s]} --shell /bin/bash << EOF cd $virtualhost_basedir/${input_values_array[v]}/$virtualhost_htdocsdir wp core download wp config create --dbhost="${input_values_array[m]}" --dbname=${input_values_array[d]} --dbuser="${input_values_array[n]}" --dbpass="${input_values_array[w]}" --dbprefix="${input_values_array[x]}" wp config set DISALLOW_FILE_EDIT true wp config set DISABLE_WP_CRON true wp core install --url="${input_values_array[u]}" --title="${input_values_array[v]}" --admin_user=${input_values_array[u]} --admin_password="${input_values_array[p]}" --admin_email=${input_values_array[e]} echo "apache_modules:" > wp-cli.local.yml echo " - mod_rewrite" >> wp-cli.local.yml wp rewrite flush --hard rm wp-cli.local.yml EOF if [ -f "$virtualhost_basedir/${input_values_array[v]}/$virtualhost_htdocsdir/index.html" ]; then /usr/bin/rm $virtualhost_basedir/${input_values_array[v]}/$virtualhost_htdocsdir/index.html fi elif [[ "$option" == "q" ]]; then echo "Quiting without installing." elif [[ " ${input_keys_index[@]} " =~ " $option " ]]; then read -p "Enter new value for ${input_keys_array[$option]} (${input_values_array[$option]}): " new_value if [ -n "$new_value" ] ; then input_values_array[$option]=$new_value fi restart_script else echo "ERROR: Invalid entry, try again." fi