Акция Панель управления ispmanager для VDS — первый месяц бесплатно
до 31.07.2026 Подробнее
Выберите продукт

PHP‑приложение на VDS: пошаговое развертывание и базовая оптимизация

Развертывание PHP‑приложения на VDS часто пугает тех, кто привык к shared‑хостингу: нужно самому настраивать Linux, веб‑сервер, PHP‑FPM, MySQL и DNS. В этой инструкции разберём, как с нуля поднять рабочий стек, безопасно подготовить сервер, настроить виртуальный хост и базу данных, выполнить первый деплой и базовую оптимизацию.
PHP‑приложение на VDS: пошаговое развертывание и базовая оптимизация

В этой статье разберём практический сценарий: у нас есть PHP‑приложение (фреймворк или «самопис», не принципиально), и нужно развернуть его на новом VDS. Никаких панелей — только SSH и базовый набор инструментов. Цель: получить предсказуемый, управляемый стек с PHP, Nginx и MySQL, корректно работающий DNS и понятный процесс деплоя.

1. Исходные данные и базовая модель

Предположим, у нас есть:

  • VDS с Debian/Ubuntu (пример будем показывать на Debian/Ubuntu‑подобных системах);
  • домен example.com, которым вы управляете через панель регистратора;
  • PHP‑приложение в репозитории Git (или хотя бы в виде архива);
  • нужна связка: Nginx → PHP‑FPM → PHP‑код + база MySQL/MariaDB.

Наша минимальная задача:

  • подготовить VDS: SSH, обновления, базовая безопасность;
  • настроить DNS: A‑запись на сервер;
  • установить Nginx, PHP‑FPM, MySQL/MariaDB;
  • подготовить виртуальный хост, директорию проекта и пользователя деплоя;
  • выполнить деплой и проверить работу;
  • разобрать элементарную оптимизацию под типичные PHP‑нагрузки.

2. Первичное подключение к VDS и подготовка системы

2.1. Подключение по SSH

После получения VDS вы получаете IP‑адрес и пароль root или пользователя с правами sudo. Подключаемся:

ssh root@YOUR_VDS_IP

Для начала стоит поменять пароль (или сразу настроить авторизацию по ключам, что намного безопаснее):

passwd

2.2. Обновление системы и базовый набор пакетов

Перед любыми установками обновляем репозитории и ставим базовый набор утилит:

apt update
apt upgrade -y
apt install -y sudo vim htop curl git unzip

Создадим отдельного пользователя для управления приложением, чтобы не работать под root:

adduser deploy
usermod -aG sudo deploy

Дальше логинимся под пользователем deploy и стараемся root использовать только при необходимости.

2.3. Часовой пояс, hostname, базовые настройки

Приводим часовой пояс к вашему региону — важно для логов и кронов:

sudo timedatectl set-timezone Europe/Moscow

Проверяем hostname и при необходимости задаём осмысленный:

hostnamectl
sudo hostnamectl set-hostname app-vds-1

Настройка DNS A‑записей домена на IP VDS

3. DNS: связываем домен и VDS

Чтобы сайт открывался по домену, а не по IP, нужно настроить DNS. Минимум — A‑записи вида:

example.com.        300   IN   A   203.0.113.10
www.example.com.    300   IN   A   203.0.113.10

Где 203.0.113.10 — IP вашего VDS. TTL 300 (5 минут) удобен на этапе настройки и миграций.

После изменения DNS ждём применения (обычно 5–15 минут) и проверяем:

dig +short example.com
ping -c 4 example.com

Если ответы приходят с IP вашего VDS, DNS‑часть базово готова. Если используете отдельный почтовый сервис, не забудьте корректно настроить MX‑записи и SPF/DMARC — детально про это можно почитать в статье о DNS‑записях для авторизации почты.

4. Установка PHP, Nginx и MySQL/MariaDB

4.1. Выбор версий PHP и MySQL

Для нового проекта имеет смысл сразу использовать актуальную ветку PHP (например, PHP 8.2+). Для MySQL можно взять либо MySQL 8, либо MariaDB 10.6+ (зависит от требований приложения и привычки). Старайтесь не ставить устаревшие версии: вы потеряете по безопасности и производительности.

4.2. Установка Nginx и PHP‑FPM

Устанавливаем веб‑сервер и PHP‑FPM с популярными расширениями:

sudo apt install -y nginx
sudo apt install -y php-fpm php-mysql php-cli php-xml php-mbstring php-curl php-zip

Проверяем версии и статусы сервисов:

php -v
nginx -v
systemctl status php*-fpm
systemctl status nginx

Важно, чтобы PHP работал через FPM, а не как модуль Apache: на VDS связка Nginx + PHP‑FPM обычно даёт лучшую управляемость и предсказуемую производительность.

4.3. Установка и первичная настройка MySQL/MariaDB

Устанавливаем сервер баз данных:

sudo apt install -y mariadb-server

После установки запускаем скрипт базовой безопасности:

sudo mysql_secure_installation

Скрипт предложит:

  • задать пароль root в MySQL (если он ещё не установлен);
  • удалить анонимные аккаунты;
  • запретить root‑логин не с localhost;
  • удалить тестовую базу;
  • перезагрузить таблицы привилегий.

На все вопросы, кроме, возможно, пароля, обычно отвечаем «Yes».

4.4. Создание базы и пользователя для PHP‑приложения

Заходим в MySQL под root:

sudo mysql

Создаём базу и отдельного пользователя с минимальными правами:

CREATE DATABASE appdb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'appuser'@'localhost' IDENTIFIED BY 'S3cureP4ss!';
GRANT ALL PRIVILEGES ON appdb.* TO 'appuser'@'localhost';
FLUSH PRIVILEGES;
EXIT;

Используйте свой пароль, не из примера. Его мы позже пропишем в конфиге PHP‑приложения.

FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

5. Структура проекта и пользователь деплоя

5.1. Где хранить код и статику

На VDS удобно разделять:

  • /var/www/example.com/current — текущий релиз (symlink на папку релиза);
  • /var/www/example.com/releases — каталоги с релизами;
  • /var/www/example.com/shared — общие файлы (конфиги, логи, storage и т.п.).

Для начала можно обойтись упрощённой схемой: просто /var/www/example.com, но лучше с самого начала закладывать структуру под дальнейший автоматизированный деплой.

5.2. Права и владелец файлов

Предположим, владелец кода — пользователь deploy, а PHP‑FPM работает от пользователя www-data. Нужна аккуратная настройка прав, чтобы и деплой, и PHP могли читать/писать, где нужно.

Создадим директорию под проект:

sudo mkdir -p /var/www/example.com
sudo chown -R deploy:www-data /var/www/example.com
sudo chmod 2755 /var/www/example.com

Бит 2 (setgid) на директории помогает сохранять группу для создаваемых файлов и директорий.

6. Настройка PHP‑FPM под приложение

По умолчанию PHP‑FPM поднимает пул www. Для изоляции приложений на одном VDS лучше делать отдельные пулы, но в базовом сценарии можно использовать дефолтный пул, аккуратно настроив основные параметры.

6.1. Основные параметры пула PHP‑FPM

Открываем конфигурацию пула (имя файла и путь могут отличаться в зависимости от дистрибутива и версии PHP):

sudo vim /etc/php/8.2/fpm/pool.d/www.conf

Нас интересует:

  • user и group — от кого работает PHP‑код;
  • listen — сокет или порт;
  • режим управления процессами: pm, pm.max_children, pm.max_requests.

Типичная базовая настройка (фрагмент, показываем только суть):

user = www-data
group = www-data

listen = /run/php/php8.2-fpm.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

pm = dynamic
pm.max_children = 10
pm.start_servers = 2
pm.min_spare_servers = 2
pm.max_spare_servers = 4
pm.max_requests = 500

После правок:

sudo systemctl reload php8.2-fpm

Конкретные числа зависят от ресурсов VDS: для 1–2 ГБ RAM не стоит ставить слишком много процессов, иначе под нагрузкой сервер уйдёт в своп.

6.2. Общие PHP‑настройки (php.ini)

Из базового полезно проверить:

  • memory_limit — сколько памяти можно съесть одному PHP‑процессу;
  • upload_max_filesize и post_max_size — если приложение принимает большие файлы;
  • max_execution_time — верхний предел для долгих операций;
  • date.timezone — чтобы не было проблем с датами.

Правится обычно файл вида /etc/php/8.2/fpm/php.ini:

sudo vim /etc/php/8.2/fpm/php.ini

И не забываем перезапустить PHP‑FPM после изменений.

Конфигурация Nginx и PHP‑FPM в редакторе на сервере Linux

7. Настройка Nginx: виртуальный хост для PHP

7.1. Базовый server{} для сайта

Создадим файл конфигурации виртуального хоста, например:

sudo vim /etc/nginx/sites-available/example.com.conf

Минимальный вариант для PHP‑приложения (без HTTPS, только чтобы подняться и проверить связку):

server {
    listen 80;
    server_name example.com www.example.com;

    root /var/www/example.com/public;
    index index.php index.html;

    access_log /var/log/nginx/example.com.access.log;
    error_log /var/log/nginx/example.com.error.log warn;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_pass unix:/run/php/php8.2-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_index index.php;
    }

    location ~* \.(jpg|jpeg|png|gif|ico|css|js|webp|svg)$ {
        expires 7d;
        access_log off;
    }
}

Дальше активируем конфиг и проверяем:

sudo ln -s /etc/nginx/sites-available/example.com.conf /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Если проверка (nginx -t) успешна, виртуальный хост поднялся.

7.2. Проверочный info.php

Чтобы убедиться, что связка Nginx → PHP‑FPM работает, создадим простой файл:

mkdir -p /var/www/example.com/public
echo '<?php phpinfo();' > /var/www/example.com/public/info.php
sudo chown -R deploy:www-data /var/www/example.com

Теперь открываем в браузере адрес вида http://example.com/info.php. Если видите страницу с информацией о PHP — стек работает. Не забудьте удалить этот файл после проверки, чтобы не светить конфиг PHP в проде.

FastFox SSL
Надежные SSL-сертификаты
Мы предлагаем широкий спектр SSL-сертификатов от GlobalSign по самым низким ценам. Поможем с покупкой и установкой SSL бесплатно!

8. Подготовка окружения приложения: конфиг, зависимости, права

8.1. Конфигурация подключения к MySQL

Большинство PHP‑фреймворков и CMS имеют свой файл конфигурации БД: .env, config.php, database.php и т.д. Вам нужно в нём прописать:

  • host: 127.0.0.1 (или localhost);
  • database: appdb;
  • user: appuser;
  • password: ваш надёжный пароль;
  • charset: utf8mb4.

Следите, чтобы конфиг не был доступен напрямую через веб‑сервер (обычно они лежат за пределами public или закрыты правилами маршрутизации).

8.2. Composer‑зависимости

Если приложение использует Composer, ставим его и подтягиваем зависимости на сервере:

cd /var/www/example.com
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
php composer-setup.php --install-dir=/usr/local/bin --filename=composer
rm composer-setup.php

composer install --no-dev --optimize-autoloader

В продакшн‑окружении почти всегда включаем --no-dev и --optimize-autoloader. Если интернет на сервере ограничен, можно собирать vendor‑папку локально и загружать её вместе с кодом.

8.3. Права на каталоги cache/logs/uploads

Чтобы приложение корректно писало кэш, логи и загружаемые файлы, даём права пользователю, от которого работает PHP‑FPM, обычно www-data:

sudo chown -R deploy:www-data /var/www/example.com
sudo find /var/www/example.com -type f -exec chmod 640 {} \;
sudo find /var/www/example.com -type d -exec chmod 750 {} \;

Отдельно можно чуть ослабить права для каталогов, куда идёт запись из веб‑приложения (например, storage, var, uploads):

sudo chmod -R 770 /var/www/example.com/storage

Конкретные пути зависят от вашей CMS/фреймворка.

9. Деплой: как удобно накидывать релизы на VDS

9.1. Ручной деплой через Git

Самый простой вариант — клонировать репозиторий напрямую на VDS:

cd /var/www/example.com
sudo -u deploy git clone git@github.com:you/yourapp.git .

Дальше при обновлении:

cd /var/www/example.com
sudo -u deploy git pull
composer install --no-dev --optimize-autoloader
php artisan migrate

Название команд зависят от фреймворка (вместо artisan может быть bin/console, свои скрипты и т.д.).

9.2. Архив или rsync

Если Git на сервере использовать не хотите, можно деплоить через rsync или архив:

# на локальной машине
rsync -avz ./project/ deploy@example.com:/var/www/example.com/

После выкладки — тот же набор шагов: установка зависимостей, миграции БД, очистка кэшей, прогрев конфигурации.

9.3. Минимум безопасности для деплоя

Не храните пароль от MySQL и прочие секреты в репозитории в открытом виде. Используйте:

  • отдельные .env‑файлы на сервере, исключённые из Git;
  • разные учётные данные для prod/stage/dev;
  • SSH‑ключи с ограниченным доступом под пользователя deploy.

10. Проверка работоспособности PHP, MySQL и DNS

10.1. Локальная проверка сервисов

Проверяем, что все нужные сервисы запущены и слушают нужные порты/сокеты:

systemctl status nginx
systemctl status php8.2-fpm
systemctl status mariadb

ss -tulpn | grep -E '80|3306'

Если MySQL слушает только 127.0.0.1:3306 — это нормально и даже хорошо: доступ к БД только локальный, из PHP‑приложения.

10.2. Тест подключения PHP → MySQL

Можно сделать маленький тестовый скрипт, который подключается к БД:

echo '<?php
$mysqli = new mysqli("127.0.0.1", "appuser", "S3cureP4ss!", "appdb");
if ($mysqli->connect_errno) {
    echo "Failed to connect to MySQL: " . $mysqli->connect_error;
} else {
    echo "OK";
}
' > /var/www/example.com/public/dbtest.php

Откройте в браузере адрес вида http://example.com/dbtest.php. Если видите «OK» — связка PHP + MySQL настроена корректно. Не забудьте удалить этот файл после проверки.

10.3. Проверка DNS и host‑заголовков

Иногда сайт по IP открывается, а по домену — нет. В таком случае проверяем, какой сервер отвечает и какой host уходит в запросе:

curl -v http://example.com/

Смотрите на блоки Connected to и > Host: example.com. Если всё указывает на ваш VDS, а в логах Nginx появляются обращения — проблема либо в приложении, либо в конфиге виртуального хоста. При смене регистратора или перенастройке домена может пригодиться материал о том, как аккуратно переносить домены и DNS, например статья о переносе домена и корректной работе DNS.

11. Базовая оптимизация: где обычно «болит»

После того как сайт заработал, важно не останавливаться на «как‑то работает». Несколько типичных мест, которые имеет смысл проверить и подкрутить ещё на старте.

11.1. Лимиты Nginx и размеры запросов

Если приложение принимает загрузку файлов, убедитесь, что размер запроса не режется на уровне Nginx или PHP. В конфиге server или глобально в nginx.conf проверьте:

client_max_body_size 20m;

В php.ini — параметры upload_max_filesize и post_max_size должны быть не меньше, чем максимально ожидаемый размер файла.

11.2. Кэширование статики

Чтобы не забивать PHP‑процессы отдачей картинок и CSS, правильно выставляем заголовки кэширования для статических файлов (выше мы уже задействовали expires 7d). Можно добавить:

location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|webp)$ {
    expires 7d;
    add_header Cache-Control "public";
}

Это уменьшит нагрузку на VDS при повторных посещениях сайта.

11.3. PHP‑опкэш

Убедитесь, что включён opcache — без него PHP‑приложение будет каждый запрос компилировать скрипты заново, что особенно критично на нагруженных проектах.

В php.ini или отдельном файле конфигурации opcache проверьте ключевые параметры:

  • opcache.enable=1;
  • opcache.memory_consumption — достаточно ли памяти под кеш кода;
  • opcache.max_accelerated_files — достаточно ли слотов под кэшируемые файлы.

11.4. Базовая настройка MySQL/MariaDB под VDS

Конфигурация MySQL по умолчанию часто не оптимальна под небольшой VDS. Даже пара настроек даёт заметную прибавку:

  • innodb_buffer_pool_size — 30–50% от RAM для небольшого сервера, если БД важна;
  • max_connections — не завышайте без необходимости, иначе при пике легко «съесть» всю память;
  • query_cache_type и query_cache_size для MySQL 5.7 и ниже лучше выключить (на новых версиях он и так удалён).

Эти параметры задаются в my.cnf, после чего требуется перезапуск службы MySQL.

12. Логи и диагностика: куда смотреть при проблемах

Чтобы не тратить часы на «оно не работает», полезно с самого начала знать, где живут логи:

  • логи Nginx: /var/log/nginx/access.log и /var/log/nginx/error.log (или разнесённые по виртуальным хостам);
  • логи PHP‑FPM: /var/log/php8.2-fpm.log и, при включённом php_admin_value[error_log], логи конкретного пула;
  • ошибки PHP в приложении: в зависимости от фреймворка — обычно в storage/logs или аналогичных каталогах;
  • логи MySQL/MariaDB: /var/log/mysql/error.log или системный журнал через journalctl.

При первых проблемах можно ориентироваться на типичные симптомы:

  • «502 Bad Gateway» — смотрим error‑лог Nginx и логи PHP‑FPM;
  • «500 Internal Server Error» — чаще всего ошибка в приложении/конфиге, проверяем логи PHP и приложения;
  • «Connection refused» к БД — MySQL не запущен или неверные креды/хост;
  • «404 Not Found» при «красивых» URL — проверьте try_files и маршрутизацию в Nginx.

13. Что ещё имеет смысл сделать после первого запуска

Когда базовый стек работает, а приложение отвечает по домену, можно переходить к следующему уровню зрелости:

  • включить HTTPS с нормальным сертификатом и настроить редиректы HTTP → HTTPS (для продакшена стоит сразу использовать боевые SSL-сертификаты);
  • поднять бэкапы БД и файлов (хотя бы ежедневные);
  • подключить мониторинг ресурсов VDS (нагрузка CPU, RAM, диск, доступность сайта);
  • вынести деплой в скрипты или CI/CD, чтобы не нажимать каждый раз руками.

Но всё это уже строится поверх базового каркаса, который мы разобрали: рабочий PHP‑стек (Nginx + PHP‑FPM + MySQL), аккуратно настроенный VDS и предсказуемый процесс развертывания приложения.

Если вы раньше работали только с общим виртуальным хостингом, первый переход на VDS может показаться сложным. Однако все шаги логичны и воспроизводимы: подготовить сервер, настроить PHP и веб‑сервер, привязать базу и домен, наладить деплой и минимальную оптимизацию. Дальше останется только углубляться в тонкую настройку под ваш конкретный проект и нагрузку.

Поделиться статьей

Вам будет интересно

Debian/Ubuntu: mount: wrong fs type, bad option, bad superblock — как быстро найти и исправить причину OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: mount: wrong fs type, bad option, bad superblock — как быстро найти и исправить причину

Ошибка mount: wrong fs type, bad option, bad superblock в Debian/Ubuntu может означать и простую опечатку в имени раздела, и пробл ...
Debian/Ubuntu: XFS metadata corruption и emergency read-only — пошаговое восстановление OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: XFS metadata corruption и emergency read-only — пошаговое восстановление

Если XFS-раздел внезапно стал доступен только для чтения, а сервер ушёл в emergency mode, главное — не спешить. Разберём безопасны ...
Debian/Ubuntu: как исправить Failed to fetch при apt update OpenAI Статья написана AI (GPT 5)

Debian/Ubuntu: как исправить Failed to fetch при apt update

Ошибка Failed to fetch при apt update в Debian и Ubuntu обычно связана не с самим APT, а с DNS, сетью, зеркалом, прокси, временем ...