Установка WordPress на Ubuntu 24.04: готовый скрипт с темой Hostfera
Скрипт устанавливает Nginx, PHP, MariaDB, WordPress и выбранную тему Journal или Community. Полный исходник, проверка SHA-256, доступ через SSH и следующие шаги.

Этот скрипт устанавливает WordPress на Ubuntu 24.04 LTS: Nginx, PHP 8.3, MariaDB, отдельную базу и одну из бесплатных тем Hostfera. Можно выбрать Journal для блога или Community для небольшого сообщества. После установки останутся домен, HTTPS и наполнение сайта.
Какой результат вы получите
Новый сайт создаётся отдельно от других проектов: со своим каталогом, системным пользователем, базой и пулом PHP-FPM. Существующие каталоги и настройки сайтов скрипт не заменяет. Повторный запуск с занятым именем останавливается.
Первоначальный адрес — http://127.0.0.1:18080. Он доступен с вашего компьютера через зашифрованный SSH-туннель. Скрипт не открывает этот порт всему интернету: так можно настроить WordPress до готовности домена и сертификата. Поисковая индексация и публичная регистрация изначально выключены.
Скрипт устанавливает нужные пакеты и запускает системные службы. Для первого самостоятельного сайта используйте отдельный VPS. Сервер с Apache, другая ОС и нестандартная настройка базы требуют отдельной инструкции. На общем виртуальном хостинге используйте установщик провайдера.
Что подготовить
- VPS с Ubuntu 24.04 LTS и доступом root либо sudo.
- Рабочую почту администратора.
- Доступ к репозиториям Ubuntu, wordpress.org, GitHub и hostfera.ru по HTTPS.
- Свободный локальный порт и не менее 2 ГБ свободного диска для установки.
Объём памяти выбирайте под проект; разумно начать оценку с 2 ГБ для небольшого сайта и затем измерять использование ресурсов. Это ориентир для старта, а не обещание определённой посещаемости. Помочь с конфигурацией может Hostfera Select.
Если вы ещё не заходили на VPS, сначала пройдите подключение по SSH. Установщик не меняет правила межсетевого экрана. Для будущего публичного сайта понадобятся TCP 80 и 443, а SSH-доступ должен сохраняться; это разобрано в инструкции по UFW.
Скачайте и проверьте установщик
Скачать install-wordpress-1.0.0.sh.
Выполните на VPS:
curl --fail --show-error --location --proto '=https' \
https://hostfera.ru/static/downloads/install-wordpress-1.0.0.sh \
-o install-wordpress-1.0.0.sh
printf '%s %s\n' '5a25e5ee52ff7e587068c1dec3e453aea9bfd5d5e896a583c7bc49185a5d9a14' \
install-wordpress-1.0.0.sh | sha256sum --check
bash -n install-wordpress-1.0.0.sh
less install-wordpress-1.0.0.sh
Ожидаемый результат проверки SHA-256 — OK. Ознакомьтесь с кодом перед запуском: он работает с правами администратора. Скачивание и выполнение здесь разделены, чтобы можно было проверить файл.
Запустите установку с выбранной темой
Замените почту и название на свои:
sudo bash install-wordpress-1.0.0.sh \
--site myblog \
--theme journal \
--port 18080 \
--email your.name@example.com \
--title 'Мой первый сайт' \
--admin siteowner
--site — техническое имя из 3–12 строчных латинских букв и цифр, первая — буква. Оно используется в путях и именах ресурсов; это не домен. --port — свободный порт от 10000 до 60000. Пароль администратора создаётся случайно.
Для Community до первого запуска замените --theme journal на --theme community. Остальные параметры относятся к самому сайту. Если уже установленную тему нужно поменять, загрузите другой ZIP из панели WordPress; запускать установщик заново для этого не нужно.
Скрипт проверяет SHA-256 архивов тем и WP-CLI. Ядро загружается официальным русским ZIP и проверяется по контрольным суммам WordPress. Установка из ZIP обходит обнаруженную при проверке проблему распаковки длинных путей через WP-CLI.
Откройте WordPress через SSH-туннель
На своём компьютере откройте отдельный терминал:
ssh -N -L 18080:127.0.0.1:18080 SSH_USER@SERVER_IP
Замените SSH_USER и SERVER_IP на пользователя SSH и адрес VPS. Оставьте терминал открытым и перейдите в браузере по http://127.0.0.1:18080/, затем по http://127.0.0.1:18080/wp-admin/.
Если локальный порт занят на вашем компьютере, освободите его либо изначально выберите другой порт установки и используйте его в обеих частях туннеля. WordPress уже хранит свой полный адрес, поэтому простая замена только левого порта может приводить к перенаправлению на прежний адрес.
Данные входа прочитайте на VPS:
sudo cat /root/hostfera-myblog.credentials
Файл доступен только root. В нём находятся локальный URL, логин, сгенерированный пароль и почта. Сохраните пароль у себя. Скрипт не отправляет уведомление об установке и не настраивает доставку почты WordPress — её нужно проверить отдельно.
Что установлено на сервере
Для примера myblog создаются:
| Ресурс | Значение |
|---|---|
| Каталог WordPress | /var/www/hostfera-myblog |
| Пользователь и база | hfwp_myblog |
| PHP-пул | /etc/php/8.3/fpm/pool.d/hostfera-myblog.conf |
| PHP-сокет | /run/php/hostfera-myblog.sock |
| Локальный виртуальный хост | /etc/nginx/sites-available/hostfera-myblog |
| Данные входа | /root/hostfera-myblog.credentials |
У темы нет демонстрационных материалов из презентации. Вы получите чистую установку с выбранным оформлением и штатным стартовым содержимым WordPress. В Community дополнительно создаются её служебные страницы.
Если установка остановилась
Прочитайте последнюю ошибку. Не запускайте тот же процесс повторно с новым именем ради обхода причины: это может создать несколько ненужных баз и каталогов.
Скрипт не удаляет созданные данные при ошибке. Это позволяет разобраться с состоянием и сохранить возможные результаты. Если сбой произошёл после создания пользователя или базы, повторный запуск с тем же именем остановится. Исправляйте конкретный шаг либо удаляйте только ресурсы этой новой тестовой установки после их проверки.
Ошибка загрузки требует проверки сети и URL. Несовпадение SHA-256 — повод остановиться и сверить версию пакета. Ошибка nginx -t или php-fpm8.3 -t требует проверки указанной конфигурации до перезагрузки службы.
Проверка установки
Установщик 1.0.0 проверен 29 октября 2026 года на Ubuntu 24.04.5 LTS с PHP 8.3 и MariaDB 10.11: отдельно установлены WordPress 7.1.4 с Journal 1.1.1 и с Community 1.0.1. Это были новые изолированные сайты на хосте с уже работающим Nginx и WordPress; первичная установка пакетов на полностью пустой ОС отдельно не проверялась.
Проверены контрольные суммы ядра, активация тем, ответы страниц и ресурсов, ограничения доступа к конфигурации и PHP в загрузках. Повторный запуск не перезаписал установленный сайт. Действовавшее демо сохранило тему, записи и конфигурацию. Такая проверка не заменяет испытание всех плагинов или будущей нагрузки вашего проекта.
Полный исходный код установщика
Ниже тот же код, что находится в скачиваемом файле версии 1.0.0:
#!/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'
Следующий шаг: домен, HTTPS и содержимое
Перейдите к инструкции подключения домена и HTTPS к этому WordPress. Она учитывает локальный адрес установки, PHP и замену адресов в базе. Общие материалы о привязке домена и бесплатном сертификате объясняют DNS и проверку продления.
Затем настройте Journal или Community и пройдите маршрут создания первого сайта. Новые бесплатные темы Hostfera будем представлять отдельными статьями после их выпуска.
Первоисточники
Сообщите адрес статьи и фрагмент через контакты редакции.



