Files
wordpress-ubuntu/wordpressinstall
2025-12-19 15:40:50 +01:00

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
#