Установка на Ubuntu VDS
Эта инструкция описывает чистую установку KaevCMS на отдельный VDS с Ubuntu Server 24.04 LTS, nginx, PHP 8.3-FPM и MySQL.
Ubuntu 24.04 выбрана как базовая система KaevCMS, потому что её штатные репозитории содержат PHP 8.3 — ту же минимальную и фиксированную платформу, которая указана в composer.json. Ubuntu 26.04 LTS поставляется с PHP 8.5; её можно проверять отдельно, но до прохождения полного quality-gate она не считается основной проверенной платформой.
Итоговая структура
/var/www/kaevcms/
├── app/
├── bootstrap/
├── config/
├── public/ ← единственный Document Root nginx
├── storage/
├── vendor/
├── .env
└── artisanНельзя направлять nginx на /var/www/kaevcms. Публичным должен быть только /var/www/kaevcms/public.
Перед началом
Подготовьте:
- чистый VDS с Ubuntu Server 24.04 LTS;
- домен с A-записью на IPv4-адрес VDS — необязательно для локальной или тестовой установки;
- SSH-доступ с
sudo; - полный ZIP-релиз KaevCMS;
- отдельные пароли для MySQL и владельца KaevCMS.
В примерах замените:
example.com на свой домен, если он уже есть
192.168.50.111 на фактический IP сервера
admin@example.com на свой email для Let's Encrypt
KaevCmsDbPasswordHere на длинный уникальный пароль MySQLДля первичной проверки KaevCMS достаточно IP-адреса. Домен и сертификат можно настроить позже.
1. Обновите систему
sudo apt update
sudo apt full-upgrade -y
sudo rebootПосле перезагрузки снова подключитесь по SSH.
2. Настройте firewall
Если SSH работает на стандартном порту 22:
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable
sudo ufw status verboseЕсли SSH перенесён на другой порт, сначала разрешите этот порт и только затем включайте UFW.
Не открывайте порт MySQL 3306 в интернет для локальной базы KaevCMS.
3. Установите nginx, MySQL, PHP и утилиты
sudo apt install -y \
nginx \
mysql-server \
unzip \
curl \
ca-certificates \
composer \
php8.3-cli \
php8.3-fpm \
php8.3-mysql \
php8.3-mbstring \
php8.3-xml \
php8.3-curl \
php8.3-zip \
php8.3-intl \
php8.3-gdПроверьте версии и службы:
php -v
composer --version
sudo systemctl status nginx --no-pager
sudo systemctl status php8.3-fpm --no-pager
sudo systemctl status mysql --no-pagerKaevCMS требует PHP 8.3 или новее. Для этой инструкции команда php -v должна показывать ветку 8.3.x.
4. Создайте базу KaevCMS
Откройте MySQL от системного администратора:
sudo mysqlВыполните:
CREATE DATABASE kaevcms_db
CHARACTER SET utf8mb4
COLLATE utf8mb4_unicode_ci;
CREATE USER 'kaevcms_user'@'localhost'
IDENTIFIED BY 'KaevCmsDbPasswordHere';
GRANT ALL PRIVILEGES ON kaevcms_db.*
TO 'kaevcms_user'@'localhost';
FLUSH PRIVILEGES;
EXIT;Проверьте отдельного пользователя:
mysql -u kaevcms_user -p -h 127.0.0.1 kaevcms_dbПосле успешного входа выполните EXIT;.
Для Web Installer используйте:
Host: 127.0.0.1
Port: 3306
Database: kaevcms_db
Username: kaevcms_user
Password: созданный пароль5. Загрузите и распакуйте KaevCMS
Передайте полный ZIP-релиз на сервер через SFTP/SCP, например в /tmp/KaevCMS-full.zip.
sudo mkdir -p /var/www/kaevcms
sudo unzip /tmp/KaevCMS-full.zip -d /var/www/kaevcms
sudo chown -R "$USER":www-data /var/www/kaevcms
cd /var/www/kaevcmsПроверьте, что архив не создал лишний уровень каталога:
test -f /var/www/kaevcms/artisan && echo "KaevCMS root OK"Если artisan находится, например, в /var/www/kaevcms/KaevCMS-0.x.x/artisan, перенесите содержимое этой вложенной папки на один уровень выше.
Удалите загруженный архив после распаковки:
sudo rm -f /tmp/KaevCMS-full.zip6. Установите production-зависимости
Выполняйте Composer от обычного SSH-пользователя, которому принадлежит проект, а не от root:
cd /var/www/kaevcms
composer install --no-dev --optimize-autoloader --no-interaction
composer check-platform-reqs --no-devNode.js и npm на VDS не требуются: готовые frontend-assets уже входят в полный релиз.
7. Назначьте права
Сначала задайте безопасные базовые права:
sudo find /var/www/kaevcms -type d -exec chmod 755 {} \;
sudo find /var/www/kaevcms -type f -exec chmod 644 {} \;Разрешите nginx/PHP-FPM запись только в runtime-каталоги:
sudo chgrp -R www-data \
/var/www/kaevcms/storage \
/var/www/kaevcms/bootstrap/cache \
/var/www/kaevcms/public/uploads
sudo chmod -R g+rwX \
/var/www/kaevcms/storage \
/var/www/kaevcms/bootstrap/cache \
/var/www/kaevcms/public/uploads
sudo find /var/www/kaevcms/storage \
/var/www/kaevcms/bootstrap/cache \
/var/www/kaevcms/public/uploads \
-type d -exec chmod 2775 {} \;Проверьте, что пользователь PHP-FPM действительно может создавать вложенные каталоги кэша и файлы:
cd /var/www/kaevcms
sudo -u www-data php artisan kaevcms:runtime-directories --probeОбщий кэш приложения по умолчанию остаётся файловым, а счётчики ограничений входа и других запросов хранятся в основной базе CMS:
CACHE_STORE=file
CACHE_LIMITER=databaseWeb Installer должен создать .env в корне проекта. Временно разрешите группе www-data запись в корень:
sudo chmod 775 /var/www/kaevcmsНе назначайте 0777 всему проекту.
8. Настройте лимиты PHP
Откройте конфигурацию PHP-FPM:
sudo nano /etc/php/8.3/fpm/php.iniРекомендуемые стартовые значения:
memory_limit = 512M
upload_max_filesize = 64M
post_max_size = 70M
max_execution_time = 120
max_input_time = 120Примените изменения:
sudo systemctl restart php8.3-fpmНа VDS обновления применяются через CLI от владельца файлов проекта, поэтому загружать большой update ZIP через PHP не требуется.
9. Настройте nginx
Создайте сайт:
sudo nano /etc/nginx/sites-available/kaevcmsКонфигурация:
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
root /var/www/kaevcms/public;
index index.php;
charset utf-8;
client_max_body_size 512m;
access_log /var/log/nginx/kaevcms-access.log;
error_log /var/log/nginx/kaevcms-error.log;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location = /index.php {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}
location = /install/index.php {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}
location ^~ /uploads/ {
try_files $uri =404;
}
location ~ \.php$ {
return 404;
}
location ~ /\.(?!well-known).* {
deny all;
}
}Активируйте конфигурацию:
sudo ln -s /etc/nginx/sites-available/kaevcms /etc/nginx/sites-enabled/kaevcms
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl reload nginxПроверьте Document Root:
sudo nginx -T | grep -A4 -B4 '/var/www/kaevcms/public'Если домена пока нет, укажите в конфигурации nginx фактический IP сервера:
server_name 192.168.50.111;10. Настройте HTTPS при наличии домена
Если домен и его A-запись уже указывают на VDS, установите Certbot:
sudo apt install -y certbot python3-certbot-nginxПолучите сертификат:
sudo certbot --nginx \
-d example.com \
-d www.example.com \
-m admin@example.com \
--agree-tos \
--redirectПроверьте автоматическое продление:
sudo systemctl status certbot.timer --no-pager
sudo certbot renew --dry-runЕсли поддомен www не используется и для него нет DNS-записи, уберите второй -d из команды и www.example.com из server_name.
Если домена или A-записи пока нет, пропустите Certbot. Web Installer разрешает установку по HTTP и только покажет предупреждение. Это удобно для тестового VDS, локального IP или закрытой сети. Перед открытием публичного сайта пользователям настройте домен и HTTPS.
Защитные настройки nginx
Эти настройки применяются к самому VDS. Они нужны при новой установке и полезны для уже работающего сайта.
1. Скрыть версию nginx. Откройте конфигурацию:
sudo nano /etc/nginx/nginx.confВнутри секции http { ... } найдите настройку server_tokens (если она уже есть — измените её, а не дублируйте) и укажите:
server_tokens off;Это скрывает точную версию nginx в заголовке Server и стандартных страницах ошибок, но не заменяет обновления безопасности nginx.
2. Включить HSTS только после проверки HTTPS. Когда сертификат работает, HTTP перенаправляется на HTTPS и продление проверено командой sudo certbot renew --dry-run, откройте конфигурацию сайта:
sudo nano /etc/nginx/sites-available/kaevcmsДобавьте директиву внутрь каждого HTTPS-блока server { ... } сайта (обычно с listen 443 ssl), включая отдельный HTTPS-редирект с www, если он есть:
add_header Strict-Transport-Security "max-age=604800" always;604800 — срок HSTS 7 дней. Сначала проверьте работу HTTPS на всём сайте, а затем при необходимости увеличьте срок. Не добавляйте HSTS к HTTP-блоку, сайту только по IP, а также параметры includeSubDomains или preload без отдельной проверки всех поддоменов. Если внутри server есть location со своими add_header, заголовок HSTS может не унаследоваться: добавьте его и в такой location.
3. Проверить и применить:
sudo nginx -t
sudo systemctl reload nginx
curl -I https://example.com/
curl -I https://example.com/login
curl -I https://example.com/nesushchestvuetОжидается заголовок Strict-Transport-Security: max-age=604800 на HTTPS-ответах, включая ошибку 404. На страницах входа и для авторизованных пользователей актуальная CMS также возвращает Cache-Control: no-store.
Не дублируйте CSP в nginx
Content-Security-Policy (CSP) и запрет кэширования приватных ответов реализованы в приложении KaevCMS. Указывать вторую CSP в nginx не нужно: браузер применяет обе политики одновременно, что может сломать сайт, личный кабинет или переход к ЮMoney.
Эти изменения приложения вошли в коммит 7fb7bade, сделанный после релиза 0.53.1. Чтобы они работали, установленная сборка должна содержать этот коммит или более позднее исправление.
11. Пройдите Web Installer
С доменом и сертификатом откройте:
https://example.com/install/Без домена откройте IP-адрес сервера:
http://192.168.50.111/install/Замените пример на фактический IP. На шаге базы укажите созданные ранее реквизиты и используйте пустую базу kaevcms. Предупреждение об HTTP не блокирует проверку базы или завершение установки.
После завершения установки убедитесь, что Web Installer автоматически удалил публичную папку /install, затем войдите в административную панель. Если итоговая страница сообщает об ошибке удаления, удалите каталог вручную.
12. Закройте временные права после установки
После появления .env выполните:
sudo chmod 755 /var/www/kaevcms
sudo chown "$USER":www-data /var/www/kaevcms/.env
sudo chmod 640 /var/www/kaevcms/.env
sudo chown "$USER":www-data /var/www/kaevcms/storage/app/installed.lock
sudo chmod 640 /var/www/kaevcms/storage/app/installed.lockПроверьте, что закрытые файлы не отдаются через nginx:
curl -I https://example.com/.env
curl -I https://example.com/vendor/autoload.phpОжидается 404 или 403, но не содержимое файла.
13. Настройте планировщик
Создайте системный cron-файл:
sudo nano /etc/cron.d/kaevcmsСодержимое:
* * * * * www-data cd /var/www/kaevcms && /usr/bin/php8.3 artisan schedule:run >> /dev/null 2>&1Примените права и проверьте:
sudo chmod 644 /etc/cron.d/kaevcms
sudo -u www-data /usr/bin/php8.3 /var/www/kaevcms/artisan schedule:runЧерез несколько минут проверьте heartbeat планировщика в системной диагностике KaevCMS.
14. Queue worker для асинхронной почты
Этот раздел нужен только после включения асинхронной очереди в KaevCMS.
Создайте systemd-службу:
sudo nano /etc/systemd/system/kaevcms-queue.serviceСодержимое:
[Unit]
Description=KaevCMS queue worker
After=network.target mysql.service php8.3-fpm.service
[Service]
Type=simple
User=www-data
Group=www-data
WorkingDirectory=/var/www/kaevcms
ExecStart=/usr/bin/php8.3 /var/www/kaevcms/artisan queue:work database --queue=mail-probe,mail,default --sleep=1 --tries=3 --timeout=120
Restart=always
RestartSec=5
TimeoutStopSec=360
KillSignal=SIGTERM
[Install]
WantedBy=multi-user.targetЗапустите службу:
sudo systemctl daemon-reload
sudo systemctl enable --now kaevcms-queue
sudo systemctl status kaevcms-queue --no-pagerЖурнал:
sudo journalctl -u kaevcms-queue -n 100 --no-pager15. Финальная проверка
cd /var/www/kaevcms
sudo -u www-data php artisan about --only=environment
sudo -u www-data php artisan kaevcms:release-version --no-ansi
sudo -u www-data php artisan kaevcms:maintenance-status --no-ansi
sudo -u www-data php artisan kaevcms:encryption-health --no-ansi
sudo nginx -t
sudo systemctl is-active nginx php8.3-fpm mysql
sudo systemctl is-enabled nginx php8.3-fpm mysqlПроверьте в браузере:
- главную страницу;
/admin;- вход владельца;
- загрузку изображения новости;
- SMTP-тест;
- подключение LoginServer/GameServer;
- системную диагностику;
Дальнейшее обновление
Порядок установки Update Agent и обновлений через панель или SSH вынесен в отдельную инструкцию: Обновление KaevCMS.
Как изменить адрес сайта после установки
Адрес KaevCMS хранится в двух местах:
/var/www/kaevcms/.env
/etc/nginx/sites-available/kaevcmsПереход на другой IP или работа по HTTP
Откройте .env:
sudo nano /var/www/kaevcms/.envУкажите фактический адрес и отключите принудительный HTTPS:
APP_URL=http://192.168.50.112
APP_FORCE_HTTPS=false
SESSION_SECURE_COOKIE=falseAPP_FORCE_HTTPS=true заставляет KaevCMS формировать HTTPS-ссылки. SESSION_SECURE_COOKIE=true запрещает браузеру отправлять сессионную cookie по HTTP и может приводить к ошибке 419 Page Expired при входе.
Затем измените server_name в nginx:
sudo nano /etc/nginx/sites-available/kaevcmsserver_name 192.168.50.112;Примените изменения:
cd /var/www/kaevcms
php artisan optimize:clear
sudo nginx -t
sudo systemctl reload nginxПосле смены IP, домена или протокола удалите старые cookies сайта либо откройте его в приватном окне браузера.
Переход на домен и HTTPS
После настройки DNS и сертификата измените .env:
APP_URL=https://cms.example.com
APP_FORCE_HTTPS=true
SESSION_SECURE_COOKIE=trueИ nginx:
server_name cms.example.com;После этого снова выполните php artisan optimize:clear, проверку nginx и его перезагрузку.
Диагностика
502 Bad Gateway
sudo systemctl status php8.3-fpm --no-pager
ls -la /run/php/
sudo tail -n 100 /var/log/nginx/kaevcms-error.logПроверьте, что nginx использует существующий сокет:
fastcgi_pass unix:/run/php/php8.3-fpm.sock;403 Forbidden
namei -l /var/www/kaevcms/public/index.php
sudo -u www-data test -r /var/www/kaevcms/public/index.php && echo readableКаждый родительский каталог пути должен иметь право прохода x для nginx.
Ошибка записи
sudo -u www-data test -w /var/www/kaevcms/storage && echo storage-writable
sudo -u www-data test -w /var/www/kaevcms/bootstrap/cache && echo cache-writable
sudo -u www-data test -w /var/www/kaevcms/public/uploads && echo uploads-writableНе исправляйте проблему командой chmod -R 777 /var/www/kaevcms.
Если Laravel пишет storage/framework/cache/data/...: No such file or directory, восстановите runtime-каталоги и проверьте запись от пользователя PHP-FPM:
cd /var/www/kaevcms
sudo mkdir -p storage/framework/cache/data storage/framework/sessions storage/framework/views storage/logs bootstrap/cache
sudo chown -R "$USER":www-data storage bootstrap/cache
sudo chmod -R g+rwX storage bootstrap/cache
sudo find storage bootstrap/cache -type d -exec chmod 2775 {} \;
sudo -u www-data php artisan kaevcms:runtime-directories --probe
php artisan optimize:clear
sudo -u www-data php artisan kaevcms:runtime-directories --probeoptimize:clear не заменяет правильные права и владельца. Updater проверяет runtime-каталоги до очистки кэша и повторно создаёт и проверяет их после неё.
419 Page Expired после входа по HTTP
Проверьте /var/www/kaevcms/.env:
APP_URL=http://192.168.50.111
APP_FORCE_HTTPS=false
SESSION_SECURE_COOKIE=false
SESSION_DOMAIN=Затем:
cd /var/www/kaevcms
php artisan optimize:clearУдалите cookies для старого адреса или откройте сайт в приватном окне. Адрес в APP_URL должен совпадать с адресом, который открыт в браузере.
Каталоги загрузок отмечены как недоступные для записи
KaevCMS использует:
public/uploads/news
public/uploads/pages
public/uploads/settings
public/uploads/account-avatars
public/uploads/game-assetsВ актуальном релизе установщик и системная диагностика создают отсутствующие каталоги автоматически. Для ручного восстановления прав выполните:
sudo mkdir -p \
/var/www/kaevcms/public/uploads/news \
/var/www/kaevcms/public/uploads/pages \
/var/www/kaevcms/public/uploads/settings \
/var/www/kaevcms/public/uploads/account-avatars \
/var/www/kaevcms/public/uploads/game-assets
sudo chgrp -R www-data /var/www/kaevcms/public/uploads
sudo chmod -R g+rwX /var/www/kaevcms/public/uploads
sudo find /var/www/kaevcms/public/uploads -type d -exec chmod 2775 {} \;Проверка:
sudo -u www-data test -w /var/www/kaevcms/public/uploads/news && echo news-writable
sudo -u www-data test -w /var/www/kaevcms/public/uploads/pages && echo pages-writable
sudo -u www-data test -w /var/www/kaevcms/public/uploads/settings && echo settings-writableНе используйте chmod -R 777.
Новость создана, но не отображается на сайте
Проверьте в админ-панели, что новость не является черновиком, переключатель публикации включён, а дата публикации не установлена в будущем. Изображение новости не влияет на сам факт публикации.
Логи
sudo tail -n 100 /var/log/nginx/kaevcms-error.log
sudo tail -n 100 /var/www/kaevcms/storage/logs/laravel.log
sudo journalctl -u php8.3-fpm -n 100 --no-pager
sudo journalctl -u kaevcms-queue -n 100 --no-pagerОфициальные справочные материалы
- Примечания к Ubuntu 24.04 LTS — базовая PHP 8.3.
- Сводка Ubuntu 26.04 LTS — базовая PHP 8.5.
- Установка nginx в Ubuntu Server.
- Установка PHP в Ubuntu Server.
- Установка и настройка MySQL.
- Документация Ubuntu по firewall.
- Получение TLS-сертификатов в Ubuntu.
- Развёртывание Laravel — наружу должен смотреть только
public/index.php. - Команда Composer install.
- Инструкция Certbot для nginx.
