Развертывание Symfony приложения на Ubuntu 14

В этом уроке будет рассказано, как вручную развертывать базовое приложение Symfony на сервере Ubuntu 14.04. Мы рассмотрим, как правильно конфигурировать сервер, учитывая при этом меры безопасности и эффективности, чтобы получить приложение, готовое для производства. Если вам нужен вводный урок по Symfony, вы можете почитать о том, как установить и запустить Symfony на Ubuntu 14.04.

Необходимые условия

Для этого урока нам потребуются:

• Новый Droplet на Ubuntu 14.04 работающий в средах LAMP или LEMP • Обычный (non-root) пользователь sudo, которого вы можете настроить, следуя указаниям в этом уроке: Initial Server Setup (Начальная настройка сервера)

Важно помнить, что развертывание это очень обширная тема, поскольку у каждого приложения есть свои специфические требования. Для упрощения мы будем использовать шаблонное приложение, представляющее собой список задач (to-do list application), созданное при помощи Symfony. Его исходный код вы можете найти на GitHub.

Шаг 1 — Установка зависимостей сервера

В этом шаге мы установим зависимости сервера. Начнем с обновления кэша диспетчера пакетов.

sudo apt-get update

Нам понадобится git для проверки файлов приложения, acl для задания верных разрешений каталога в процессе установки приложения, и два расширения PHP (php5-cli для исполнения PHP в командной строке и php5-curl для Symfony). Установите необходимые пакеты.

sudo apt-get install curl git php5-cli php5-curl acl nano

И наконец, нам понадобится composer для загрузки зависимостей приложения. Чтобы установить composer для всей системы, выполните:

sudo curl -sS https://getcomposer.org/installer | sudo php -- --install-dir=/usr/local/bin --filename=composer

Теперь все готово.

Шаг 2 — Конфигурация MySQL

Начнем с того, что подготовим настройку вашего MySQL для деплоя. Для следующего шага нам понадобится пароль для root-аккаунта в MySQL. Убедитесь, что вы настроили MySQL с учетом требований безопасности (как описано в шаге 2 в обучающих руководствах по LAMP и LEMP).

Если вы используете LAMP или LEMP, которые устанавливаются в один клик, вы найдете root-пароль для MySQL в ежедневном сообщении, которое распечатывается, когда вы авторизируетесь на своем сервере. Содержания ежедневных сообщений также доступны в файле /etc/motd.tail.

Задание кодировки по умолчанию

Symfony рекомендует устанавливать кодировку набора символов и сопоставление вашей базы данных на utf8. Большинство баз данных по умолчанию используют сопоставления латинским шрифтом, что приведет к неожиданным результатам (например, странные символы и нечитабельный текст) при извлечении данных, ранее сохраненных в базе данных. Конфигурация на уровне приложения невозможна, поэтому нам нужно отредактировать файл конфигурации MySQL и включить туда несколько определений.

Откройте файл /etc/mysql/my.cnf при помощи вашего любимого диспетчера командной строки.

sudo nano /etc/mysql/my.cnf

Теперь найдите блок [mysqld]. Добавьте опции collation-server и character-set-server в Basic Settings (Базовые настройки).

/etc/mysql/my.cnf
[mysqld]
#
# * Basic Settings
#
collation-server     = utf8mb4_general_ci # Replaces utf8_general_ci
character-set-server = utf8mb4            # Replaces utf8
user            = mysql
pid-file        = /var/run/mysqld/mysqld.pid
socket         = /var/run/mysqld/mysqld.sock
. . .

Сохраните и выйдите. Перезапустите MySQL, чтобы изменения вступили в силу.

sudo service mysql restart

Создание пользователя и базы данных для приложения

Теперь нам нужно создать базу данных MySQL и пользователя для нашего приложения. Сперва зайдите в клиент MySQL через root-аккаунт MySQL.

mysql -u root -p

Вам нужно будет ввести пароль. Это должен быть тот же пароль, который вы использовали, когда выполняли mysql_secure_installation. Теперь создайте базу данных приложения:

CREATE DATABASE todo;
Output
Query OK, 1 row affected (0.00 sec)

База данных создана. Следующим шагом будет создание пользователя в MySQL и предоставление этому пользователю доступа к только что созданной базе данных.

CREATE USER 'todo-user'@'localhost' IDENTIFIED BY 'todo-password';
Output
Query OK, 0 rows affected (0.00 sec)

Мы создали пользователя под именем todo-user, с паролем todo-password. Обратите внимание на то, что это просто пример и что в целях безопасности вам нужно использовать более сложный пароль для своего пользователя в MySQL.

Нам нужно предоставить этому пользователю права доступа к базе данных приложения. Это можно сделать следующим образом:

GRANT ALL PRIVILEGES ON todo.* TO 'todo-user'@'localhost';
Output
Query OK, 0 rows affected (0.00 sec)

Это предоставит пользователю todo-user все привилегии на всех таблицах внутри базы данных todo. Чтобы применить изменения, выполните:

FLUSH PRIVILEGES;
Output
Query OK, 0 rows affected (0.00 sec)

Чтобы проверить, все ли работает правильно, выйдите из клиента MySQL.

quit;

Теперь авторизируйтесь снова, но на этот раз используя новое имя пользователя MySQL и только что созданный пароль. В этом примере мы используем имя пользователя todo-user и пароль todo-password:

mysql -u todo-user -p

Вы можете проверить, к каким базам данным имеется доступ у пользователя:

SHOW DATABASES;

Результат должен выглядеть следующим образом:

Output
+--------------------+
| Database           |
+--------------------+
| information_schema |
| todo               |
+--------------------+
2 rows in set (0.00 sec)

Это означает, что новый пользователь с требуемыми привилегиями был успешно создан. Вы должны видеть только две базы данных — information_schema и todo.

Теперь вы можете выйти из клиента MySQL.

quit;

Шаг 3 — Проверка кода приложения

Развертывание приложения — это обширная тема, и объясняется это уникальностью большинства приложений, даже если рассматривать только проекты Symfony. Здесь сложно обобщать, потому что каждый отдельный случай может потребовать определенных шагов по развертыванию – например, мигрирование базы данных или выполнения дополнительных команд настройки.

Для упрощения понимания материала мы будем использовать базовое демо-приложение, созданное при помощи Symfony. Вы также можете использовать свое собственное приложение, созданное при помощи Symfony. Но имейте в виду, что вам, возможно, придется выполнить дополнтельные шаги, в зависимости от требований вашего приложения.

Наше приложение представляет собой простой список задач, который позволяет вам добавлять и удалять объекты, а также изменять статус каждого объекта. Объекты-задачи хранятся в базе данных MySQL. Исходный код вы найдете на GitHub.

Для проверки кода приложения мы будем использовать Git. Затем нужно выбрать месторасположение, которое будет служить в качестве root-каталога приложения. Затем мы соответсвующим образом конфигурируем веб-сервер. В этом уроке мы будем использовать /var/www/todo-symfony, поэтому создайте этот каталог сейчас.

sudo mkdir -p /var/www/todo-symfony

Перед тем как клонировать хранилище, давайте изменим владельца папки и группу, чтобы мы могли работать с файлами проекта, используя наш обычный пользовательский аккаунт. Замените developer на ваше обычное (non-root) имя пользователя sudo.

sudo chown developer:developer /var/www/todo-symfony

Теперь перейдте в родительский каталог и клонируйте приложение.

cd /var/www
git clone https://github.com/php-demos/todo-symfony.git todo-symfony
Output
Cloning into 'todo-symfony'...
remote: Counting objects: 83, done.
remote: Total 83 (delta 0), reused 0 (delta 0), pack-reused 83
Unpacking objects: 100% (83/83), done.
Checking connectivity... done.

Шаг 4 — Настройка прав доступа к папкам

Файлы приложения сейчас расположены по адресу /var/www/todo-symfony, в каталоге, владельцем которого является наш пользователь системы (в этом уроке мы используем developer в качестве примера). Но пользователю веб-сервера (обычно это www-data) также нужен доступ к этим файлам. В противном случае, веб-север не сможет обслуживать приложение. Более того, имеются два каталога, которые требуют специальных разрешений: app/cache и app/logs. Эти каталоги должны быть перезаписываемыми как пользователем системы, так и пользователем веб-сервера.

Для конфигурации этих специальных прав доступа мы будем использовать ACL (Списки управления доступом). Эти Списки предоставляют больше узкоспециализированных прав доступа к файлам и каталогам. Именно это нам и нужно для настройки необходимых прав, избегая при этом предоставления слишком широкого доступа.

Для начала нам нужно предоставить пользователю www-data доступ к файлам внутри папки приложения. Предоставьте этому пользователю право читать + выполнять (read + execute) (rX) во всем каталоге.

sudo setfacl -R -m u:www-data:rX todo-symfony

Затем нам нужно настроить специальные права к папкам cache и logs. Предоставьте пользователю www-data права читать + писать + выполнять (read + write + execute) (rwX), чтобы веб-свервер мог писать только в этих каталогах.

sudo setfacl -R -m u:www-data:rwX todo-symfony/app/cache todo-symfony/app/logs

И наконец, мы зададим, чтобы все новые файлы, созданные внутри папок app/cache и app/logs, следовали одной и той же, только что заданной нами схеме прав доступа, с правами читать, писать и исполнять для пользователя веб-сервера. Это достигается посредством повтора команды setfacl, которую мы только что выполнили, но на этот раз с добавлением опции -d.

sudo setfacl -dR -m u:www-data:rwX todo-symfony/app/cache todo-symfony/app/logs

Если вы хотите проверить, какие права действуют на данный момент в данном каталоге, вы можете использовать getfacl .

getfacl todo-symfony/app/cache
Результат должен выглядеть примерно так:
Output
# file: todo-symfony/app/cache
# owner: developer
# group: developer
user::rwx
user:www-data:rwx
group::rwx
mask::rwx
other::r-x
default:user::rwx
default:user:www-data:rwx
default:group::rwx
default:mask::rwx
default:other::r-x

Из этого результата видно, что хотя владельцем каталога app/cache является пользователь developer, в нем имеется дополнительный набор прав для пользователяwww-data. Директивы по умолчанию показывают, какие права будут иметь файлы, созданные внутри этого каталога.

Шаг 5 — Настройка приложения

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

Symfony хорошо функционирует в разных средах. По умолчанию, Symfony использует настройки среды разработки, и это влияет на то, как она обрабатывает кэш и ошибки. Среда разработки имеет более обширные и детализированные журналы, менее кэшированный контент, а для упрощения отладки ошибки показываются очень заметно. Это помогает при разработке приложения, но для продуктовых сред это не очень хорошо.

Чтобы настроить приложение для продакшена, нам нужно определить переменную среды, которая сообщит Symfony, что мы выполняем приложение в продуктовой среде.

export SYMFONY_ENV=prod

Затем нам нужно установить зависимости проекта. Зайдите в папку приложения и выполните composer install:

cd todo-symfony
composer install --no-dev --optimize-autoloader

В конце процесса установки вас попросят предоставить информацию, которая заполнит файл parameters.yml. Этот файл содержит важную информацию для приложения, например – настройки связи с базой данных. Вы можете нажать ENTER , чтобы принять значения по умолчанию для всех параметров, кроме имени базы данных, имени пользователя и пароль. Для них используйте значения, которые вы задали в шаге 2.

Creating the "app/config/parameters.yml" file
Some parameters are missing. Please provide them.
database_host (127.0.0.1):
database_port (null):
database_name (symfony): todo
database_user (root): todo-user
database_password (null): todo-password
. . .

После окончания установки мы можем проверить связь с базой данных при помощи консольной команды doctrine:schema:validate.

php app/console doctrine:schema:validate
Output
[Mapping]  OK - The mapping files are correct.
[Database] FAIL - The database schema is not in sync with the current mapping file.

Строка OK говорит нам о том, что связь с базой данных работает. Неудивительно, что появилась строка FAIL , поскольку мы еще не создали схему базы данных. Давайте сделаем это:

php app/console doctrine:schema:create
ATTENTION: This operation should not be executed in a production environment.
Creating database schema...
Database schema created successfully!

Будут созданы все таблицы приложения в конфигурируемой базе данных, в соответствии с информацией о метаданных, полученной из объектов приложения.

При мигрировании существующего приложения не следует использовать команды doctrine:schema:createи doctrine:schema:update напрямую. Вместо этого осуществите миграцию базы данных. В нашем случае миграция необязательна, потому что приложение устанавливается с пустой базой данных.

Теперь нужно очистить кэш.

php app/console cache:clear --env=prod --no-debug
Output
Clearing the cache for the prod environment with debug false

И наконец, сгенерировать ресурсы приложения.

php app/console assetic:dump --env=prod --no-debug
Output
Dumping all prod assets.
Debug mode is off.
14:02:39 [file+] /var/www/todo-symfony/app/../web/css/app.css
14:02:39 [dir+] /var/www/todo-symfony/app/../web/js
14:02:39 [file+] /var/www/todo-symfony/app/../web/js/app.js

Шаг 6 — Настройка веб-сервера

Осталось только настроить веб-север. Мы сделаем это в 2 шага: зададим директиву date.timezone в php.ini, и обновим файл конфигурации вебсайта по умолчанию (в Apache или в Nginx) для обслуживания нашего приложения.

Мы увидим, как выполнить эти шаги в средах LEMP и LAMP.

Конфигурация для Nginx + PHP-FPM

Начнем с редактирования файла php.ini по умолчанию, чтобы задать часовой пояс сервера. Это обязательно для выполнения приложений Symfony, и обычно закомментируется на новых установках сервера.

Откройте файл /etc/php5/fpm/php.ini.

sudo nano /etc/php5/fpm/php.ini 

Найдите строку, содержащую date.timezone. Раскомментируйте директиву, убрав знак; в начале строки, и добавьте соответствующий часовой пояс своего приложения. В этом примере мы используем Europe/Minsk, но вы можете выбрать любой поддерживаемый часовой пояс.

[Date]
; Defines the default timezone used by the date functions
; http://php.net/date.timezone
date.timezone = Europe/Minsk

Сохраните файл и выйдите. Перезапустите PHP, чтобы изменения вступили в силу.

sudo service php5-fpm restart

Затем нам нужно заменить файл конфигурации вебсайта по умолчанию на файл, специально предназначенный для обслуживания приложения Symfony. Сначала создайте резервную копию текущей конфигураци вебсайта по умолчанию.

cd /etc/nginx/sites-available
sudo mv default default-bkp

Создайте новый файл, чтобы заменить им старый.

sudo nano /etc/nginx/sites-available/default

Вставьте следующий контент в файл. Не забудьте заменить значения server_name для отображения доменного имени или IP адреса вашего сервера.

server {
     server_name example.com www.example.com your_server_ip;
     root /var/www/todo-symfony/web;
     location / {
         # try to serve file directly, fallback to app.php
         try_files $uri /app.php$is_args$args;
     }
     location ~ ^/app\.php(/|$) {
         fastcgi_pass unix:/var/run/php5-fpm.sock;
         fastcgi_split_path_info ^(.+\.php)(/.*)$;
         include fastcgi_params;
         fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
         # Prevents URIs that include the front controller. This will 404:
         # http://domain.tld/app.php/some-path
         # Remove the internal directive to allow URIs like this
         internal;
     }
     error_log /var/log/nginx/symfony_error.log;
     access_log /var/log/nginx/symfony_access.log;
}

Сохраните файл и выйдите. Перезапустите Nginx, чтобы изменения вступили в силу.

sudo service nginx restart 

Конфигурация для веб-сервера Apache + PHP5

Начнем с редактирования файла по умолчанию php.ini, чтобы задать часовой пояс сервера. Это обязательно для выполнения приложений Symfony, и обычно закомментируется на новых установках сервера.

Откройте файл /etc/php5/apache2/php.ini:

sudo nano /etc/php5/apache2/php.ini

Найдите строку, содержащую date.timezone. Раскомментируйте директиву, убрав знак ; в начале строки, и добавьте соответствующий часовой пояс вашего приложения. В этом примере мы используем пояс Europe/Minsk, но вы можете выбрать любой поддерживаемый часовой пояс.

[Date]
; Defines the default timezone used by the date functions
; http://php.net/date.timezone
date.timezone = Europe/Minsk

Сохраните файл и выйдите. Теперь нам нужно заменить файл конфигурации вебсайта по умолчанию на файл, специально предназначенный для обслуживания приложения Symfony. Создайте резервную копию текущей конфигурации вебсайта по умолчанию.

cd /etc/apache2/sites-available
sudo mv 000-default.conf default-bkp.conf

Создайте новый файл, чтобы заменить им старый.

sudo nano /etc/apache2/sites-available/000-default.conf

Вставьте в файл следующий контент в /etc/apache2/sites-available/000-default.conf:

<VirtualHost *:80>
    DocumentRoot /var/www/todo-symfony/web
    <Directory /var/www/todo-symfony/web>
        AllowOverride None
        Order Allow,Deny
        Allow from All
        <IfModule mod_rewrite.c>
            Options -MultiViews
            RewriteEngine On
            RewriteCond %{REQUEST_FILENAME} !-f
            RewriteRule ^(.*)$ app.php [QSA,L]
        </IfModule>
    </Directory>
    # uncomment the following lines if you install assets as symlinks
    # or run into problems when compiling LESS/Sass/CoffeScript assets
    # <Directory /var/www/project>
    #     Options FollowSymlinks
    # </Directory>
    ErrorLog /var/log/apache2/symfony_error.log
    CustomLog /var/log/apache2/symfony_access.log combined
</VirtualHost>

Если для доступа на сервер вы используете доменное имя, а не просто IР-адрес, вы можете (по желанию) задать значения ServerName и ServerAlias, как показано ниже. Или же вы можете опустить их.

/etc/apache2/sites-available/000-default.conf

<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot /var/www/todo-symfony/web
. . .

Сохраните файл и выйдите. Нам также нужно настроить mod_rewrite для Apache.

sudo a2enmod rewrite

Перезапустиет Apache, чтобы изменения вступили в силу.

sudo service apache2 restart

Шаг 7 — Доступ к приложению

Ваш сервер должен быть готов обслуживать демо-версию приложения Symfony. Зайдите наhttp://your_server_ip в своем браузере, и вы увидите следующую страницу:

Вы можете использовать эту форму для создания новых задач и тестирования функциональности приложения.

Заключение

Продуктовое развертывание приложения требует особого внимания к деталям, например – создания выделенного пользователя базы данных с ограниченным доступом и настройки прав доступа к каталогам в папке приложения. Эти шаги необходимы для повышения безопасности сервера и приложения в производственных средах. В этом уроке мы рассмотрели конкретные шаги, которые необходимо предпринять, чтобы вручную осуществить продуктовое развертывание базового приложения Symfony на сервере Ubuntu 14.04.