#!/usr/bin/env bash
# Hostfera WordPress installer 1.0.0. Ubuntu 24.04 LTS, Nginx, PHP 8.3, MariaDB.
# Installs a NEW isolated site on a loopback port; never replaces an existing site.
set -Eeuo pipefail
umask 077
export LC_ALL=C.UTF-8 DEBIAN_FRONTEND=noninteractive
die() { printf '%s\n' "Ошибка: $*" >&2; exit 1; }
trap 'printf "Установка остановлена на строке %s. Не запускайте повторно с тем же именем: сначала проверьте созданные ресурсы.\n" "$LINENO" >&2' ERR
[[ $EUID -eq 0 ]] || die 'Запустите через sudo bash.'
set +x
[[ -r /etc/os-release ]] || die 'Не определена ОС.'
. /etc/os-release
[[ $ID == ubuntu && $VERSION_ID == 24.04 ]] || die 'Поддерживается Ubuntu 24.04 LTS.'

SITE='' THEME='' PORT='' EMAIL='' TITLE='Мой сайт' ADMIN='siteowner'
while (($#)); do
  [[ $# -ge 2 ]] || die 'Ожидаются пары --параметр значение.'
  case "$1" in
    --site) SITE=$2;; --theme) THEME=$2;; --port) PORT=$2;;
    --email) EMAIL=$2;; --title) TITLE=$2;; --admin) ADMIN=$2;;
    *) die "Неизвестный параметр: $1";;
  esac
  shift 2
done
[[ $SITE =~ ^[a-z][a-z0-9]{2,11}$ ]] || die '--site: от 3 до 12 строчных латинских букв и цифр; первая буква.'
[[ $PORT =~ ^[0-9]{5}$ && $PORT -ge 10000 && $PORT -le 60000 ]] || die '--port: число от 10000 до 60000.'
[[ $EMAIL =~ ^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$ ]] || die '--email: укажите свою рабочую почту.'
[[ $ADMIN =~ ^[a-zA-Z][a-zA-Z0-9_-]{2,30}$ ]] || die '--admin: логин от 3 до 31 символа.'
[[ -n $TITLE && ${#TITLE} -le 120 ]] || die '--title: от 1 до 120 символов.'
if systemctl is-active --quiet apache2; then die 'На сервере работает Apache. Используйте отдельный VPS с Nginx.'; fi
case "$THEME" in
  journal)
    THEME_SLUG=hostfera-journal
    ARCHIVE=hostfera-journal-1.1.1.zip
    THEME_SHA=25e2c743ced48d89a544cf759ea71f1f7ace612e42779f8545693b1459ae406f;;
  community)
    THEME_SLUG=hostfera-community
    ARCHIVE=hostfera-community-1.0.1.zip
    THEME_SHA=335a8182d6699fcabb21a2cf9f6b1f7c7766301057596fd2f56ae69539600bab;;
  *) die '--theme: journal или community.';;
esac
ACCOUNT=hfwp_$SITE
WEBROOT=/var/www/hostfera-$SITE
DB=$ACCOUNT
POOL=/etc/php/8.3/fpm/pool.d/hostfera-$SITE.conf
VHOST=/etc/nginx/sites-available/hostfera-$SITE
ENABLED=/etc/nginx/sites-enabled/hostfera-$SITE
SOCKET=/run/php/hostfera-$SITE.sock
CREDENTIALS=/root/hostfera-$SITE.credentials
WPCLI=/usr/local/lib/hostfera/wp-cli-2.12.0.phar
WPCLI_SHA=ce34ddd838f7351d6759068d09793f26755463b4a4610a5a5c0a97b68220d85c
URL=http://127.0.0.1:$PORT

for target in "$WEBROOT" "$POOL" "$VHOST" "$ENABLED" "$CREDENTIALS"; do
  [[ ! -e $target && ! -L $target ]] || die "Уже существует: $target"
done
! getent passwd "$ACCOUNT" >/dev/null || die 'Системный пользователь уже существует.'
! getent group "$ACCOUNT" >/dev/null || die 'Системная группа уже существует.'
! ss -H -ltn "sport = :$PORT" | grep -q . || die 'Порт уже занят.'
[[ $(df -Pm /var | awk 'NR==2 {print $4}') -ge 2048 ]] || die 'Нужно не менее 2 ГБ свободного места.'
command -v flock >/dev/null || die 'Требуется flock из util-linux.'
exec 9>/run/lock/hostfera-wordpress-installer.lock
flock -n 9 || die 'Другой установщик уже работает.'

printf 'Установка пакетов. Существующие сайты и виртуальные хосты сохраняются.\n'
apt-get update -qq
apt-get install -y --no-upgrade nginx mariadb-server php8.3-fpm php8.3-cli \
  php8.3-mysql php8.3-xml php8.3-mbstring php8.3-curl php8.3-zip php8.3-gd \
  php8.3-intl curl ca-certificates unzip openssl
systemctl enable --now mariadb php8.3-fpm nginx
[[ $(mariadb --batch --skip-column-names -e "SELECT COUNT(*) FROM information_schema.SCHEMATA WHERE SCHEMA_NAME='$DB'") == 0 ]] || die 'База уже существует.'
[[ $(mariadb --batch --skip-column-names -e "SELECT COUNT(*) FROM mysql.user WHERE User='$DB'") == 0 ]] || die 'Пользователь базы уже существует.'

TEMP=$(mktemp -d /tmp/hostfera-wp.XXXXXXXX)
trap 'rm -rf -- "$TEMP"' EXIT
fetch() { curl --fail --silent --show-error --location --proto '=https' --proto-redir '=https' --tlsv1.2 --connect-timeout 20 --max-time 300 "$1" -o "$2"; }
fetch "https://hostfera.ru/static/downloads/$ARCHIVE" "$TEMP/theme.zip"
printf '%s  %s\n' "$THEME_SHA" "$TEMP/theme.zip" | sha256sum --check --status || die 'Не совпала SHA-256 темы.'
fetch 'https://ru.wordpress.org/latest-ru_RU.zip' "$TEMP/wordpress.zip"
unzip -tq "$TEMP/wordpress.zip" >/dev/null
unzip -q "$TEMP/wordpress.zip" -d "$TEMP/core"
[[ -f $TEMP/core/wordpress/wp-includes/version.php ]] || die 'Не найдено ядро в официальном ZIP.'
if [[ ! -f $WPCLI ]]; then
  fetch 'https://github.com/wp-cli/wp-cli/releases/download/v2.12.0/wp-cli-2.12.0.phar' "$TEMP/wp.phar"
  printf '%s  %s\n' "$WPCLI_SHA" "$TEMP/wp.phar" | sha256sum --check --status || die 'Не совпала SHA-256 WP-CLI.'
  install -D -m 0755 "$TEMP/wp.phar" "$WPCLI"
fi
printf '%s  %s\n' "$WPCLI_SHA" "$WPCLI" | sha256sum --check --status || die 'Установленная WP-CLI отличается от проверенной версии.'
chmod 0755 /usr/local/lib/hostfera

useradd --system --user-group --home-dir "$WEBROOT" --shell /usr/sbin/nologin "$ACCOUNT"
install -d -m 0755 -o "$ACCOUNT" -g "$ACCOUNT" "$WEBROOT"
cp -a "$TEMP/core/wordpress/." "$WEBROOT/"
chown -R "$ACCOUNT:$ACCOUNT" "$WEBROOT"
install -m 0644 "$TEMP/theme.zip" "$WEBROOT/.hostfera-theme.zip"
DB_PASSWORD=$(openssl rand -hex 24)
ADMIN_PASSWORD=$(openssl rand -hex 20)
printf 'URL=%s\nLOGIN=%s\nPASSWORD=%s\nEMAIL=%s\nTHEME=%s\n' \
  "$URL" "$ADMIN" "$ADMIN_PASSWORD" "$EMAIL" "$THEME_SLUG" > "$CREDENTIALS"
chmod 0600 "$CREDENTIALS"
mariadb <<SQL
CREATE DATABASE \`$DB\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER '$DB'@'localhost' IDENTIFIED BY '$DB_PASSWORD';
GRANT ALL PRIVILEGES ON \`$DB\`.* TO '$DB'@'localhost';
SQL
wp_site() { (cd "$WEBROOT" && runuser -u "$ACCOUNT" -- env WP_CLI_CACHE_DIR="$WEBROOT/.wp-cli/cache" php "$WPCLI" --path="$WEBROOT" "$@"); }
wp_site core verify-checksums --locale=ru_RU
printf '%s\n' "$DB_PASSWORD" | wp_site config create --dbname="$DB" --dbuser="$DB" --dbhost=localhost --prompt=dbpass --quiet
chmod 0600 "$WEBROOT/wp-config.php"
unset DB_PASSWORD
wp_site config set DISALLOW_FILE_EDIT true --raw
wp_site config set WP_ENVIRONMENT_TYPE staging
printf '%s\n' "$ADMIN_PASSWORD" | wp_site core install --url="$URL" --title="$TITLE" \
  --admin_user="$ADMIN" --admin_email="$EMAIL" --prompt=admin_password --skip-email
unset ADMIN_PASSWORD
wp_site option update blog_public 0
wp_site option update users_can_register 0
wp_site option update default_role subscriber
wp_site option update timezone_string Europe/Moscow
wp_site option update comment_moderation 1
wp_site option update show_on_front posts
wp_site rewrite structure '/%postname%/'
wp_site theme install "$WEBROOT/.hostfera-theme.zip" --activate
if [[ $THEME == community ]]; then
  wp_site eval 'hfc_install_data(); hfc_setup_pages();'
fi
rm -- "$WEBROOT/.hostfera-theme.zip"
find "$WEBROOT" -type d -exec chmod 0755 {} +
find "$WEBROOT" -type f ! -name wp-config.php -exec chmod 0644 {} +
chmod 0600 "$WEBROOT/wp-config.php"

cat > "$POOL" <<CONF
[$ACCOUNT]
user = $ACCOUNT
group = $ACCOUNT
listen = $SOCKET
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
pm = ondemand
pm.max_children = 3
pm.process_idle_timeout = 10s
pm.max_requests = 300
php_admin_value[memory_limit] = 192M
php_admin_value[upload_max_filesize] = 32M
php_admin_value[post_max_size] = 40M
php_admin_flag[display_errors] = off
security.limit_extensions = .php
CONF
chmod 0644 "$POOL"
cat > "$VHOST" <<NGINX
server {
    listen 127.0.0.1:$PORT;
    server_name _;
    root $WEBROOT;
    index index.php;
    client_max_body_size 40m;
    add_header X-Content-Type-Options nosniff always;
    add_header X-Robots-Tag "noindex, nofollow" always;
    location / { try_files \$uri \$uri/ /index.php?\$args; }
    location = /xmlrpc.php { deny all; }
    location = /wp-config.php { deny all; }
    location ~ /\. { deny all; }
    location ~* ^/wp-content/uploads/.*\.(?:php[0-9]?|phtml|phar)(?:/|$) { deny all; }
    location ~* \.(?:sql|log|bak|ini|conf)$ { deny all; }
    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:$SOCKET;
        fastcgi_hide_header X-Powered-By;
    }
}
NGINX
chmod 0644 "$VHOST"
ln -s "$VHOST" "$ENABLED"
php-fpm8.3 -t
nginx -t
systemctl reload php8.3-fpm
systemctl reload nginx
wp_site core is-installed
[[ $(wp_site option get stylesheet) == "$THEME_SLUG" ]] || die 'Тема не активна.'
curl --fail --silent --show-error --max-time 30 "$URL/" -o /dev/null
printf '\nWordPress установлен: %s\nТема: %s\nДанные входа: %s (доступ только root)\n' "$URL" "$THEME_SLUG" "$CREDENTIALS"
printf 'Откройте SSH-туннель с вашего компьютера: ssh -N -L %s:127.0.0.1:%s SSH_USER@SERVER_IP\n' "$PORT" "$PORT"
printf 'Затем откройте %s/wp-admin/ . До подключения домена и HTTPS сайт доступен только через туннель.\n' "$URL"
printf 'Инструкция: https://hostfera.ru/blog/domen-i-https-dlya-wordpress-na-vps/\n'
