В «жизни» практически любого веб-проекта – будь то небольшой интернет-магазин или сайт набирающего популярность бара – рано или поздно случается момент, когда не хватает ни возможностей и ресурсов shared-хостинга, ни средств для тотальной реорганизации архитектуры приложения. Несколько лет назад, когда я ещё работал в небольшой веб-студии, мне частенько приходилось наблюдать такую картину. Практически во всех подобных случаях принималось одно и то же решение – аренда выделенного сервера и перенос на него проекта в том виде, в котором он есть. В то время в сети было доступно немало статей по настройке серверов с Linux на борту. Причём практически все они были не самого лучшего качества и зачастую содержали настолько вредные советы, что господин Остер мог бы стоя аплодировать авторам тех материалов.
«Всё это дела давно минувших дней» – так я думал ещё совсем недавно, пока ко мне не обратился мой давний приятель за помощью в решении аналогичной проблемы. Как оказалось, ситуация с тех пор сильно не изменилась: нужный раздел документации практически не обновился, сами разработчики в основном советуют воспользоваться shared-хостингом от своих партнёров, а толкового материала, учитывающего нюансы миграции на
Прежде всего оговорюсь. В этой статье я не буду рассматривать вопросы выбора
Первые шаги
Итак, у нас есть
useradd user_name -s /bin/bash -U -m -G sudo
passwd user_name
Дальнейшую работу будем проводить уже от имени только что созданного пользователя.
Установка необходимого ПО
nginx
В качестве HTTP-сервера будет использоваться nginx. Думаю, что в представлении он не нуждается. Устанавливать его будем из репозитория, любезно развёрнутого командой разработчиков. Для этого необходимо получить ключ, которым подписаны установочные пакеты:
# иногда происходит неведомая фигня с добавлением ключей непосредственно из STDOUT
# поэтому сначала ключ сохраняем в файл и только потом добавляем
wget http://nginx.org/keys/nginx_signing.key
sudo apt-key add nginx_signing.key
rm nginx_signing.key
И обновить список источников пакетов, добавив в файл /etc/apt/sources.list строки:
# 12.04 = precise
# 14.04 = trusty
deb http://nginx.org/packages/ubuntu/ trusty nginx
deb-src http://nginx.org/packages/ubuntu/ trusty nginx
После этого обновляемся и устанавливаем nginx:
sudo aptitude update && sudo aptitude upgrade -y
sudo aptitude install nginx
Чтобы задать лимиты на количество открываемых пользователем http-сервера файлов, нужно добавить в /etc/security/limits.conf строки:
nginx hard nofile 32768
nginx soft nofile 32768
Точные цифры следует подбирать, исходя из конфигурации вашего сервера. Активируется модуль лимитов добавлением следующей строки в /etc/pam.d/common-session:
session required pam_limits.so
Проверить, что лимиты установились можно следующей командой:
sudo su nginx --shell /bin/bash --command "ulimit -a"
PHP
HostCMS требует, чтобы были включены следующие модули php: curl, gd, xslt и, естественно, mysql. Кроме того, обратите внимание, что теперь пакет php5-json не является виртуальным и его нужно устанавливать отдельно. Помимо прочего подключим модуль кеширования опкода xcache. В качестве SAPI (режим запуска интерпретатора) будем использовать PHP-FPM, однако, чтобы иметь возможность выполлять некоторые скрипты по расписанию будет установлен еще и PHP-CLI.
sudo aptitude install php5-common php5-fpm php5-cli php5-curl php5-gd php5-mysql php5-xsl php5-json php5-xcache
MySQL
Установка MySQL довольная проста. Несколько раз установщик запросит у вас пароль для root'а сервера баз данных, можете смело оставлять его пустым — мы сменим его позже, с помощью утилиты mysql_secure_installation. При ее запуске ответьте, что хотите сменить пароль root'a, удалить тестовую БД и тестовых пользователей и обновить права на таблицы службной БД.
sudo aptitude install mysql-server
sudo mysql_secure_installation
Подробно почитать о настройке mysql-сервера можно здесь. Статья отлично написана, поэтому не вижу смысла дублировать сюда информацию.
Настройка загрузки файлов
В качестве протокола передачи файлов я предлагаю использовать SSH FTP (SFTP). Во-первых, он безопаснее обычного ftp, так как данные будут передаваться в зашифрованном виде. Во-вторых, не придется устанавливать дополнительное ПО: все что нужно — ssh-сервер — у нас уже есть. А минусов практически никаких — все современные IDE и клиенты загрузки данных умеют работать с этим протоколом.
Чтобы определить, кому можно подключаться по sftp, создадим дополнительную группу пользователей, например, sftp:
sudo groupadd sftp
И активируем передачу данных, добавив в конец файла /etc/ssh/sshd_config строки:
Match Group sftp
ChrootDirectory %h
ForceCommand internal-sftp
AllowTcpForwarding no
Подготовка файловой системы
Традиционно, файлы, относящиеся к веб-сайтам, размещаются в каталоге /var/www/. И мы не будем отступать от этого негласного правила. Создадим папку для виртуальных хостов и будущую точку монтирования быстрого кэша:
sudo mkdir -p -m 755 /var/www/data
sudo mkdir -m 777 /var/www/tmp
Затем укажем, что при следующей загрузке, в эту папку будет смонтирована tmpfs. Добавим в /etc/fstab:
tmpfs /var/www/tmp/ tmpfs defaults,noatime,nosuid,nodev,noexec,mode=1777,size=128M 0 0
Стоит заметить, что некоторые редакции HostCMS имеют встроенный алгоритм кеширования ответов в файлы. Если вы используете одну из таких редакций имеет смысл примонтировать tmpfs к директории кеша самой CMS.
Настройка виртуальных хостов
Если вы планируете развернуть на своем сервере несколько сайтов под управлением HostCMS, то описанную ниже процедуру придется повторить несколько раз. В этом случае имеет смысл попытаться автоматизировать процесс заведения нового хоста. Советую для этих целей обратить внимание на небольшой набор скриптов, описанных в этой статье, и «допилить» их под себя.
Заведение пользователя хоста
По соображениям безопасности все файлы, связанные с нашим сайтом будут принадлежать специально заведенному в системе пользователю. Подключение по sftp и выполнение PHP-скриптов будет происходить от его же имени. Чтобы было проще, его можно назвать по имени своего сайта:
sudo useradd -b /var/www/data -s /usr/lib/sftp-server -m -U -G sftp example.com
sudo passwd example.com
sudo su example.com --shell /bin/bash --command "mkdir -m 0755 ~/data ~/log && mkdir -m 0777 ~/tmp"
Для корректной работы chroot'а нужно сделать root'a владельцем домашнего каталога этого пользователя:
cd /var/www/data
sudo chown root:root example.com
Заведение пула PHP-FPM
Пул php-fpm будет запускаться от имени пользователя, которого мы создали на предыдущем шаге. Для взаимодействия с фронтн-энд сервером будет использоваться юникс-сокет. Кроме того, можно настроить количество запускаемых процессов для обработки запросов, тип логирования и некоторые другие специфичные для вашего сайта параметры php.
[example.com]
user = example.com
group = example.com
listen = /var/run/php5_example.com.sock
listen.backlog = 4096
listen.owner = nginx
listen.group = nginx
listen.mode = 0660
process.priority = 0
chdir = /
pm = dynamic
pm.max_children = 64
pm.start_servers = 8
pm.min_spare_servers = 4
pm.max_spare_servers = 16
pm.process_idle_timeout = 60s;
pm.max_requests = 256
access.log = /var/www/data/example.com/log/php.access.log
access.format = "%R # %{HTTP_HOST}e # %{HTTP_USER_AGENT}e # %t # %m # %r # %Q%q # %s # %f # %{mili}d # %{kilo}M # %{user}C+%{system}C"
slowlog = /var/www/data/example.com/log/php.slow.log
request_slowlog_timeout = 2s
request_terminate_timeout = 300s
php_admin_flag[display_errors] = off
php_admin_flag[log_errors] = on
php_admin_value[error_log] = /var/www/data/example.com/log/php.error.log
php_admin_value[memory_limit] = 32M
php_admin_value[open_basedir] = /var/www/data/example.com/:.
php_admin_value[upload_tmp_dir] = /var/www/data/example.com/tmp
php_admin_value[session.save_path] = /var/www/data/example.com/tmp
Создание конфига виртуального хоста
В файле настройки хоста nginx вам нужно будет указать доменное имя сайта, путь для записи логов доступа и адрес юникс-сокета, который слушает php-fpm. Для обработки запросов к несуществующим файлам будем использовать именованный location — таким образом мы будем эмулировать работу mod_rewrite для Apache2. Перед тем, как отдавать на обработку скрипт нашему бэкэнду, проверяем его существование. Это позволить избежать проблемы, описанной здесь. Для того, чтобы снизить нагрузку на сайт от незарегистрированных пользователей, будем использовать кеширование на стороне nginx. Для этого создадим конфигурационный файл /etc/nginx/conf.d/cache со следующим содержимым:
fastcgi_cache_path /var/www/tmp/cache levels=1:2 keys_zone=cache:32m max_size=128m;
fastcgi_temp_path /var/www/tmp/proxy 1 2;
fastcgi_ignore_headers Expires Cache-Control;
fastcgi_cache_lock on;
fastcgi_cache_lock_timeout 60s;
fastcgi_cache_use_stale error timeout updating invalid_header;
fastcgi_cache_bypass $cookie_PHPSESSID;
fastcgi_no_cache $cookie_PHPSESSID;
fastcgi_cache_key $scheme$host$request_uri;
А затем подключим его в конфиге виртуального хоста.
server {
listen 80;
server_name example.com www.example.com;
access_log /var/www/data/example.com/log/nginx.access.log main;
error_log /var/www/data/example.com/log/nginx.error.log;
root /var/www/data/example.com/data;
error_page 404 /404/;
location / {
index index.html index.php;
try_files $uri $uri/ @hostcms;
}
# php скрипты отдаем в php-fpm, предварительно проверяя их существование
location ~ .php$ {
try_files $uri =404;
fastcgi_pass unix:/var/run/php5_example.com.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
include /etc/nginx/conf.d/cache;
}
# все запросы, для которых не нашлось файлов, переадресуются на index.php
location @hostcms {
fastcgi_pass unix:/var/run/php5_example.com.sock;
fastcgi_param SCRIPT_FILENAME $document_root/index.php;
include fastcgi_params;
include /etc/nginx/conf.d/cache;
}
Создание базы данных сайта
Сейчас почти всё готово, осталось только развернуть базу данных и создать пользователя, от имени которого будет осуществляться к ней подключение. Для этого нужно в консоли mysql выполнить несколько простых команд:
CREATE USER 'example_com'@'localhost' IDENTIFIED BY 'ВашСуперСтойкийПароль';
GRANT USAGE ON * . * TO 'example_com'@'localhost' WITH MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0 MAX_USER_CONNECTIONS 0;
CREATE DATABASE IF NOT EXISTS example_com_db DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;
GRANT ALL PRIVILEGES ON example_com_db . * TO 'example_com'@'%';
Обратите внимание, что подключение к базе от имени этого пользователя разрешается с любого адреса.
Если у вас имеется дамп использовавшейся ранее базы, то развернуть его можно следующим набором команд все в той же консоли mysql:
use example_com_db;
source ПутьДоДампаБазыДанных;
Настройка резервного копирования и ротации логов
Если вы всё сделали правильно, то у вас уже должно быть полностью настроенное окружение для запуска вашего проекта. Остаются два последних по списку, но не по значимости, шага — настройка резервного копирования и ротации логов. В качестве инструмента для создания бэкапов я рекомендую использовать backup-manager. На хабре есть отличная статья про него, поэтому подробно останавливаться на нём не будем.
Для осуществления ротации логов нам нужно всего лишь создать правильный конфиг для утилиты logrotate.
/var/www/data/example.com/log/nginx*.log {
weekly
missingok
rotate 52
compress
delaycompress
notifempty
create 640 root root
sharedscripts
postrotate
[ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid`
endscript
}
/var/www/data/example.com/log/php*.log {
weekly
missingok
rotate 52
compress
delaycompress
notifempty
create 640 root root
postrotate
invoke-rc.d php5-fpm reopen-logs > /dev/null
endscript
}
Вместо заключения
Пожалуй, это всё, что я хотел сказать.
Возможно, кто-то сочтёт статью не слишком актуальной ввиду засилия панелей управления
Другие посчитают её немного сумбурной. Не исключено, что это и так: в статье я только попытался отразить свой путанный опыт в области серверного администрирования.
В любом случае, буду рад, если этот материал поможет кому-то. Замечания и дополнения приветствуются.
Автор: vinogradov_m