You've already forked wordpress-ubuntu
308 lines
8.7 KiB
Bash
Executable File
308 lines
8.7 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
# Author : Allan Christensen
|
|
# First Created : 22-05-2021 (DD-MM-YYYY)
|
|
# Description : Installs WordPress on Ubuntu 24.04 (MariaDB or MySQL)
|
|
# License : MIT License
|
|
|
|
#
|
|
# Are we root
|
|
#
|
|
if [[ $(id -u) -ne 0 ]]; then echo "" && echo "Must be root or use sudo" && echo "" ; exit ; fi
|
|
|
|
#
|
|
# Detect PHP-FPM version
|
|
#
|
|
phpfpm=$(systemctl list-unit-files --type=service | awk '/php[0-9]+\.[0-9]+-fpm\.service/ {sub(".service","",$1); print $1; exit}')
|
|
if [[ -z "$phpfpm" ]]; then printf "\nUnable to detect PHP-FPM version. Is PHP-FPM installed?\n\n" ; exit 1 ; fi
|
|
|
|
#
|
|
# Detect database engine (MariaDB or MySQL)
|
|
#
|
|
if systemctl list-unit-files | grep -q '^mariadb\.service'; then
|
|
db_engine="mariadb"
|
|
db_service="mariadb"
|
|
elif systemctl list-unit-files | grep -q '^mysql\.service'; then
|
|
db_engine="mysql"
|
|
db_service="mysql"
|
|
else
|
|
printf "\nNo supported database server found.\n\n"
|
|
printf "You must have MariaDB or MySQL installed and enabled.\n\n"
|
|
exit 1
|
|
fi
|
|
|
|
#
|
|
# Check if required services are running
|
|
#
|
|
for svc in nginx "$db_service" "$phpfpm"; do
|
|
systemctl is-active --quiet "$svc" || {
|
|
printf "\n%s is not running, cannot continue...\n\n" "${svc^}"
|
|
exit 1
|
|
}
|
|
done
|
|
|
|
#
|
|
# Check DB authentication method
|
|
# (local root access via socket / auth_socket / passwordless)
|
|
#
|
|
if mysql -u root -e ";" 2>/dev/null; then
|
|
socketauth="yes"
|
|
else
|
|
socketauth="no"
|
|
fi
|
|
|
|
#
|
|
# Usage
|
|
#
|
|
usage() {
|
|
printf -- "\nwordpressinstall (Ubuntu 24.04)\n\n"
|
|
printf -- "Database engine detected: %s\n\n" "$db_engine"
|
|
|
|
if [[ "$socketauth" == "yes" ]]; then
|
|
printf -- "LOCAL ROOT ACCESS DETECTED — no need for -a or -m\n\n"
|
|
printf -- "Usage:\n"
|
|
printf -- " sudo ./wordpressinstall -n <domain> -d <wpdbname> -u <wpdbuser> -p <wpdbpass>\n\n"
|
|
printf -- "Example:\n"
|
|
printf -- " sudo ./wordpressinstall -n wp.example.com -d wpdb -u wpuser -p wpPass123\n\n"
|
|
else
|
|
printf -- "NO LOCAL ROOT ACCESS — you must use -a and -m\n\n"
|
|
printf -- "Usage:\n"
|
|
printf -- " sudo ./wordpressinstall -n <domain> -d <wpdbname> -u <wpdbuser> -p <wpdbpass> -a <db-admin-user> -m <db-admin-password>\n\n"
|
|
printf -- "Examples:\n"
|
|
printf -- " sudo ./wordpressinstall -n wp.example.com -d wpdb -u wpuser -p wpPass123 -a root -m RootDBPassword\n"
|
|
printf -- " sudo ./wordpressinstall -n wp.example.com -d wpdb -u wpuser -p wpPass123 -a admin -m AdminDBPassword\n\n"
|
|
fi
|
|
|
|
printf -- "Options:\n"
|
|
printf -- " -h | -help | --help Show this help screen\n\n"
|
|
}
|
|
|
|
#
|
|
# Let's go
|
|
#
|
|
clear
|
|
|
|
#
|
|
# Trap: show usage if user requests help. Recognizes -help and --help as early exits before getopts
|
|
#
|
|
if [[ "$1" == "-help" || "$1" == "--help" ]]; then usage ; exit 0 ; fi
|
|
|
|
#
|
|
# Trap: malformed or missing input. Catches empty argument or argument not starting with '-'
|
|
#
|
|
if [[ $# -eq 0 || ! $1 =~ ^- ]]; then usage ; exit 1 ; fi
|
|
|
|
#
|
|
# Configure command line options
|
|
#
|
|
while getopts ":n:d:u:p:a:m:h" option; do
|
|
case "$option" in
|
|
n) hostname=$(echo "$OPTARG" | tr '[:upper:]' '[:lower:]');;
|
|
d) dbname="$OPTARG";;
|
|
u) dbuser="$OPTARG";;
|
|
p) dbpass="$OPTARG";;
|
|
a) db_admin_user="$OPTARG";;
|
|
m) db_admin_pwd="$OPTARG";;
|
|
h) usage; exit 0;;
|
|
:) usage; echo "" ; echo "Error! Option -$OPTARG requires an argument." ; echo "" ; exit 1;;
|
|
\?) usage; echo "" ; echo "Error! Invalid option: -$OPTARG" ; echo "" ; exit 1;;
|
|
esac
|
|
done
|
|
|
|
#
|
|
# Parse and validate input
|
|
#
|
|
if [[ -z "$hostname" || -z "$dbname" || -z "$dbuser" || -z "$dbpass" ]]; then
|
|
usage
|
|
printf "\nERROR: Missing required arguments.\n"
|
|
printf "Hostname (-n), Database name (-d), User (-u), and Password (-p) are required.\n\n"
|
|
exit 1
|
|
fi
|
|
|
|
#
|
|
# Normalise DB admin defaults
|
|
#
|
|
db_admin_user="${db_admin_user:-root}"
|
|
|
|
#
|
|
# Validate domain format (RFC-ish, same family as your other installers)
|
|
#
|
|
if [[ "$hostname" =~ ^- ]]; then
|
|
printf "\nERROR: Domain cannot start with a hyphen.\n"
|
|
printf "Example of valid input: wp.example.com\n\n"
|
|
exit 1
|
|
fi
|
|
|
|
if [[ "$hostname" =~ [[:space:]/_] ]]; then
|
|
printf "\nERROR: Domain cannot contain spaces, slashes, or underscores.\n\n"
|
|
exit 1
|
|
fi
|
|
|
|
if [[ ! "$hostname" =~ ^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$ ]]; then
|
|
printf "\nERROR: Invalid domain format.\n"
|
|
printf "Example of valid input: wp.example.com\n\n"
|
|
exit 1
|
|
fi
|
|
|
|
#
|
|
# Validate DB identifiers (keep it simple and safe)
|
|
#
|
|
if [[ "$dbname" =~ [^a-zA-Z0-9_] ]]; then
|
|
printf "\nERROR: Database name must only contain letters, numbers, and underscores.\n\n"
|
|
exit 1
|
|
fi
|
|
|
|
if [[ "$dbuser" =~ [^a-zA-Z0-9_] ]]; then
|
|
printf "\nERROR: Database user must only contain letters, numbers, and underscores.\n\n"
|
|
exit 1
|
|
fi
|
|
|
|
if [[ "$dbname" =~ [[:space:]] || "$dbuser" =~ [[:space:]] || "$dbpass" =~ [[:space:]] ]]; then
|
|
printf "\nERROR: Database name, user, and password cannot contain whitespace.\n\n"
|
|
exit 1
|
|
fi
|
|
|
|
#
|
|
# If no socket auth, require admin credentials
|
|
#
|
|
if [[ "$socketauth" == "no" ]]; then
|
|
if [[ -z "${db_admin_pwd:-}" ]]; then
|
|
usage
|
|
printf "\nERROR: No local root access detected — you must provide -a and -m.\n\n"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
#
|
|
# Ensure curl and git are installed
|
|
#
|
|
for tool in curl git; do dpkg -s "$tool" &>/dev/null || apt install -y -qq "$tool" ; done
|
|
|
|
#
|
|
# Download, install, and configure the latest WordPress version
|
|
#
|
|
printf "\nDownloading latest WordPress package...\n"
|
|
mkdir -p /var/www/html
|
|
curl -sL https://wordpress.org/latest.tar.gz | tar -xzf - --transform "s,^wordpress,$hostname," -C "/var/www/html" || { echo "WordPress download or extraction failed"; exit 1; }
|
|
|
|
wptarget="/var/www/html/$hostname"
|
|
cp "$wptarget/wp-config-sample.php" "$wptarget/wp-config.php"
|
|
|
|
sed -i "s/database_name_here/$dbname/" "$wptarget/wp-config.php"
|
|
sed -i "s/username_here/$dbuser/" "$wptarget/wp-config.php"
|
|
sed -i "s/password_here/$dbpass/" "$wptarget/wp-config.php"
|
|
|
|
#
|
|
# Adjust WordPress DB_HOST depending on DB auth type
|
|
# - socket/auth_socket prefers localhost (socket)
|
|
# - password/admin prefers 127.0.0.1 (TCP)
|
|
#
|
|
if [[ "$socketauth" == "no" ]]; then
|
|
sed -i "s/^define( 'DB_HOST'.*/define( 'DB_HOST', '127.0.0.1' );/" "$wptarget/wp-config.php"
|
|
fi
|
|
|
|
#
|
|
# Set permissions on WordPress directory
|
|
#
|
|
chown -R www-data: "$wptarget"
|
|
|
|
#
|
|
# Clone nginx-snippets; if nginx-snippets exists then just pull latest changes
|
|
#
|
|
nginxsnippets="/etc/nginx/nginx-snippets"
|
|
repo="https://git.x-files.dk/webserver/nginx-snippets.git"
|
|
if [[ -d "$nginxsnippets/.git" ]]; then git -C "$nginxsnippets" pull --quiet; else git clone --quiet "$repo" "$nginxsnippets"; fi
|
|
|
|
#
|
|
# Create WordPress Nginx configuration
|
|
#
|
|
cp "$nginxsnippets/hostfiles/wordpress.80.conf" /etc/nginx/conf.d/"$hostname".conf
|
|
sed -i -- "s/DOMAIN/$hostname/g" /etc/nginx/conf.d/"$hostname".conf
|
|
sed -i "s/PHPVERSION/$phpfpm/" /etc/nginx/conf.d/"$hostname".conf
|
|
|
|
#
|
|
# WordPress hardening
|
|
#
|
|
mkdir -p /etc/nginx/includes
|
|
cp "$nginxsnippets/wp-hardening.conf" /etc/nginx/includes/wp-hardening.conf
|
|
sed -i "s/PHPVERSION/$phpfpm/" /etc/nginx/includes/wp-hardening.conf
|
|
cp --no-clobber "$nginxsnippets/wp-rate-limit.conf" /etc/nginx/conf.d/wp-rate-limit.conf 2>/dev/null
|
|
|
|
#
|
|
# Determine DB login method (uses earlier socketauth variable)
|
|
#
|
|
printf "\nChecking database access method...\n"
|
|
|
|
if [[ "$socketauth" == "yes" ]]; then
|
|
dbmethod="socket"
|
|
printf "Socket authentication detected (root)\n"
|
|
else
|
|
dbmethod="admin"
|
|
printf "Using admin user authentication (%s)\n" "$db_admin_user"
|
|
fi
|
|
|
|
#
|
|
# Create WordPress database
|
|
#
|
|
case "$dbmethod" in
|
|
socket)
|
|
mysql -u root <<EOF
|
|
CREATE DATABASE IF NOT EXISTS $dbname;
|
|
CREATE USER IF NOT EXISTS '$dbuser'@'localhost' IDENTIFIED BY '${dbpass//\'/\'\\\'\'}';
|
|
GRANT ALL PRIVILEGES ON $dbname.* TO '$dbuser'@'localhost';
|
|
FLUSH PRIVILEGES;
|
|
EOF
|
|
;;
|
|
admin)
|
|
mysql -u "${db_admin_user}" -p"${db_admin_pwd}" <<EOF
|
|
CREATE DATABASE IF NOT EXISTS $dbname;
|
|
CREATE USER IF NOT EXISTS '$dbuser'@'localhost' IDENTIFIED BY '${dbpass//\'/\'\\\'\'}';
|
|
GRANT ALL PRIVILEGES ON $dbname.* TO '$dbuser'@'localhost';
|
|
FLUSH PRIVILEGES;
|
|
EOF
|
|
;;
|
|
esac
|
|
|
|
#
|
|
# Restarting Nginx and PHP-FPM for changes to take effect
|
|
#
|
|
printf "\nRestarting services...\n"
|
|
systemctl restart "$phpfpm"
|
|
systemctl restart nginx
|
|
|
|
#
|
|
# WordPress notice
|
|
#
|
|
wpdbhost="localhost"
|
|
[[ "$socketauth" == "no" ]] && wpdbhost="127.0.0.1"
|
|
|
|
wpnotice=$(cat <<EOF
|
|
-----------------------------------------------------------------------------------
|
|
NEXT STEP:
|
|
|
|
Go to http://$hostname/wp-admin/install.php and complete the WordPress setup
|
|
|
|
Database summary (wp-config.php):
|
|
|
|
Database Host : $wpdbhost
|
|
Database Name : $dbname
|
|
Database User : $dbuser
|
|
Database Pass : $dbpass
|
|
-----------------------------------------------------------------------------------
|
|
EOF
|
|
)
|
|
|
|
#
|
|
# Print notice
|
|
#
|
|
printf '%s\n' "$wpnotice"
|
|
|
|
#
|
|
# All done
|
|
#
|
|
printf "\nAll Done...\n"
|
|
|
|
#
|
|
# End of script
|
|
#
|