Сегодняшняя статья будет посвящена подготовке рабочего места разработчика. А именно — установке и настройке LNMP-окружения на виртуальной машине в windows-среде. Всех заинтересовавшихся приглашаю под кат!
Сразу же возникает пара вопросов:
- Почему не взять готовый Denwer, XAMPP, Open Server?
- Зачем всё делать руками? Есть же Vagrant
Прежде, чем начать описание процесса, отвечу на эти вопросы по порядку.
1. В сети есть много готовых сборок веб-серверов, предназначенных для локальной разработки в windows-средах. Для начинающих разработчиков полезно использовать такие сборки, чтобы овладеть языком программирования и не заморачиваться с системным администрированием. Но очень скоро начинаются первые трудности:
- Большинство хостингов сейчас предлагают linux-среды для размещения сайтов. Соответственно, тут же начинаются проблемы с кодировкой, адресацией и прочим при переносе своего проекта из среды разработки на продакшн.
- Если первые проблемы устранены, то со временем возникает необходимость установки модулей PHP/Apache/NGINX для решения прикладных задач. При портировании с windows на *nix могут возникнуть проблемы с настройкой и поведением приложения.
- PHP 5.5 и выше не умеет работать с Windows XP и ниже
2. Автоматическая сборка сервера — это здорово, удобно, круто и даёт профит при указании в резюме 😉 Разумеется, гораздо легче собрать сервер при помощи того же Vagrant. Но проблема в том, что любая автоматизация без понимания всех стадий технического процесса очень быстро разваливается. Поэтому я расскажу о пошаговой сборке сервера руками, чтобы потом уже можно было говорить об автоматизации.
Итак, начнём.
Шаг №0. Скачиваем дистрибутивы.
- VirtualBox для Windows [ скачать ] — выбирайте соответствующую разрядность для вашей операционной системы. Если Вы используете х64 систему и хотите установить x64 виртуальную машину, то необходимо проверить, что Ваш процессор имеет аппаратную поддержку виртуализации. Если это так, то в BIOS необходимо перейти к секции Processor и включить Intel Virtualization Technology (в некоторых системах может называться Virtualization Extensions) или AMD-V. После этого VirtualBox сможет работать с 64-разрядными виртуалками
- Дистрибутив Linux [ скачать ] — начнём с наиболее простого для изучения дистрибутива : Ubuntu Server 18.04 LTS. Вообще, я предпочитаю CentOS для работы, но его преимущества безопасности и строгости становятся его же минусами для изучения с нуля.
- Клиент для подключения через SSH — PuTTY
Шаг №1. Создаём виртуальную машину и устанавливаем ОС
После запуска программа VirtualBox встретит нас примерно таким окном:

В нём Вам нужно выбрать кнопку «Создать», по нажатию которой система выдаст диалоговое окно мастера создания виртуальных машин

Здесь нужно указать:
- Имя виртуалки (какое больше нравится)
- Выбрать тип ОС (нам нужна Linux)
- Выбрать тип серверного linux-дистрибутива (у наc Ubuntu Server)
- Указать объём доступной оперативной памяти. Тут нужно отталкиваться от требований проектов. Для скриптов при обучении с лихвой хватит 2 ГБ. Если на стадии обучения скрипты будут вылезать за лимит памяти, то что-то точно идёт не так. Можно указать и меньше, но для нашего проекта будет использоваться база данных MySQL, а она довольно прожорливая в плане RAM.
- Дать инструкцию на создание виртуального жёсткого диска. Нам вполне хватит 20 гигабайт для стартовых проектов.
По нажатию на кнопку «Создать», система выдаст ещё одно диалоговое окно — создания виртуального жёсткого диска
Указываем расположение, размер, тип (VDI) по умолчанию. Формату хранения я бы уделил больше внимания.
- Динамический жёсткий диск изначально занимает мало места на физическом носителе, но растёт по мере добавления файлов на виртуальную машину. Растёт он ровно до указанного при создании лимита.
- Фиксированный жёсткий диск на физическом носителе сразу занимает примерно тот же объём памяти, который выделяется ему при установке.
В чём же разница? В целях обеспечения стабильности работы системы лучше использовать виртуальные жёсткие диски фиксированного размера, т.к.
- Быстродействие ввода-вывода будет максимальным для виртуальных жестких дисков фиксированного размера, поскольку для файла не используется динамическое расширение.
- При расширении динамического жёсткого диска на физическом носителе может закончится пространство для хранения данных, что приведёт к сбою записи.
- Данные в файле не будут повреждены вследствие нехватки пространства на диске или прекращения подачи питания.
Итак, мы создали наш жёсткий диск и вернулись в первое диалоговое окно. Наша виртуальная машина готова к запуску. Но не торопитесь стартовать! Нужно внести ещё несколько настроек. Выбираем нашу виртуальную машину и переходим в меню её настроек.

Нам нужно настроить подключение виртуалки к сети, а также указать ей доступ к скачанному образу операционной системы.
- Переходим в меню «Сеть» и выбираем тип подключения «Сетевой мост». При необходимости нужно указать сетевую карту, если у Вас их несколько. В данном варианте соединения адаптер выступает в роли моста между виртуальной и физической сетями. Со стороны внешней сети имеется возможность напрямую соединяться с гостевой операционной системой — это очень удобная опция.
- Переходим в меню «Носители -> Атрибуты -> Оптический привод» и кликаем на иконку компакт диска, чтобы выбрать наш скачанный образ на 0-вом шаге.
Вот теперь можно нажимать «ОК» и запускать виртуальную машину. При первом запуске начнётся установка ОС Ubuntu. Выбираем язык English, а на следующем шаге — Install Ubuntu Server.
На заметку: для того, чтобы вывести курсор из консоли виртуальной машины используйте комбинацию клавиш "Ctrl" + "Alt" справа.
Далее Вам будет предложено
- Выбрать язык ОС и временную зону.

Россия находится в Other -> Europe -> Russian Federation.
На шаге configure locales выбираем United States — en_US.UTF-8.
Раскладку клавиатуры (Keyboard layout) можно определить автоматически. - Указать сетевое имя (Hostname) — поставим UbuntuDev.
- Создать вторичного (после root — администратора) пользователя. Создадим пользователя developer с удобным паролем.
- Зашифровать пользовательский раздел — мы пока этого делать не будем
- Подтвердить временную зону сервера
- Разбить диск на разделы. О том, как Linux работает с диском можно прочитать здесь. А мы подробнее рассмотрим процесс разбиения на диски.
Сначала нам нужно выбрать ручное разбиение дисков — Manual

На скриншоте ниже система предлагает выбрать диск, на котором будет создана таблица разделов. Выбираем SCSI3 и на следующем шаге подтверждаем создание новой таблицы разделов.
В следующем диалоге выбираем пункт FREE SPACE
![]()
и создаём загрузочный раздел:
- Выбираем Create a new partition
- Указываем new partition size (например, 512 MB)
- Задаём type Primary
- Задаём location Beginning
- Выбираем опцию Mount point и нажимаем Enter -> Указываем mount point /boot

- Устанавливаем bootable flag в on
- Выбираем Done setting up the partition
Теперь создадим логические разделы для данных и файл подкачки (swap). Я рекомендую создать следующие логические разделы:
- /data — здесь у нас будут лежать скрипты и база данных. В больших системах стоит разделять эти вещи.
- /tmp — здесь будут накапливаться временные файлы
- /var/log — для больших систем стоит отделить раздел логов, чтобы он не мешал основной системе, но для нас это некритично.
Выбираем снова FREE SPACE -> Create a new partition. Укажем для раздела данных размер в 8 GB
Тип указываем Logical, location — beginning, Mount point -> Enter manually -> /data . В остальном всё по умолчанию. Заканчиваем создание, выбрав Done setting up the partition.
Точно также создаём раздел /tmp на 512 MB, указав в конце mount point /tmp.
Ещё 10 гигабайт выделим под корневой раздел ( «/» ) — там у нас будут храниться файлы БД.
У нас осталось около немного места. Выделим его под раздел подкачки. Для того, чтобы сделать это, на последнем шаге в пункте Use as выбираем значение swap area

В итоге должна получиться примерно следующая картинка

Разметка завершена, выбираем Finish partitioning and write changes to disk
Далее установщик предложит Вам указать настройки прокси-соединения. Если Вы не используете прокси, то просто пропустите этот шаг (Continue). Если же прокси есть, то заполните поля согласно настройкам Вашего прокси-соединения.
На следующем шаге Вам предложат выбрать автоматическую установку обновлений безопасности. Рекомендую оставить этот пункт в значении «No automatic updates», если Вы не уверены, что обновления не будут мешать Вам жить. Ведь каждое обновление потенциально приносит несовместимость с текущей системой.

Теперь установщик попросит указать пакеты, которые потребуется установить. Выбираем только OpenSSH Server (с помощью пробела). Остальное установим сами в нужных версиях.
Перед завершением установки Ubuntu попросит добавить системный загрузчик GRUB в главную загрузочную запись. Выбираем Yes и продолжаем.
На этом установка закончена. Система предупредит о том, что нужно вынуть (для нас — размонтировать) установочный диск. Это можно сделать из меню VitrualBox -> Настройки -> Носители -> Атрибуты -> Оптический привод.
Нажимаем Continue.
После перезагрузки в том самом окне GRUB выбираем Ubuntu для загрузки.

Система запросит логин и пароль. Входим под пользователем developer, которого мы создали в процессе установки. Мы внутри! 🙂

Шаг №2. Оптимизируем взаимодействие с ОС и устанавливаем пакеты.
Посмотрим, какой IP нам был присвоен с помощью команды
ifconfig
Запустим ssh (если он не запускался) и добавим его к автозапуску
service ssh start
update-rc.d ssh defaults
Теперь можно запустить скачанную на шаге №0 утилиту PuTTy и использовать её для соединения с сервером. Её интерфейс гораздо удобнее работы через VirtualBox.
PuTTy выглядит следующим образом:

Вводим полученный IP в поле Host Name (or IP address). Используем порт 22 — это порт для соединений SSH по умолчанию. Нажимаем Open.
Логинимся под пользователем developer. Теперь можно заниматься установкой нужных нам пакетов.
Нам потребуются:
- NGINX — веб-сервер для обработки пользовательских запросов
- PHP-FPM. Для установленной мной версии Ubuntu 18.04 LTS актуальной версией PHP является 7.2.3
- Percona DB — форк движка MySQL. Более стабильный и производительный
На заметку: более "классической" является сборка Apache + NGINX + PHP, где все запросы принимаются с помощью NGINX как реверс-прокси (он либо отдаёт статические файлы, либо направляет запрос к Apache, который взаимодействует с PHP). Связка более ресурсоёмкая, но и менее уязвима за счёт добавления слоя Apache. NGINX менее требователен к ресурсам.
Устанавливаем NGINX
В Ubuntu 18.04 LTS по умолчанию доступен NGINX версии 1.14 (на момент написания статьи), что вполне себе нормально по функционалу, поэтому можно ставить сразу из репозитория.
apt-get install nginx
После установки можем проверить версию
nginx -v
Должно получиться что-то вроде
nginx version: nginx/1.14.0
Устанавливаем Percona DB
Мы будем устанавливать Percona версии 5.7, где InnoDB, как известно, уже умеет делать FullText индексы, а MyISAM уже и не нужен.
Скачиваем пакет репозиториев Percona
wget https://repo.percona.com/apt/percona-release_0.1-6.$(lsb_release -sc)_all.deb
И устанавливаем его
dpkg -i percona-release_0.1-6.$(lsb_release -sc)_all.deb
Обновляем список репозиториев. Не забываем, что находимся под root-ом!
apt-get update
Теперь можно поставить пакет БД
apt-get install percona-server-server-5.7
В процессе установки система запросит пароль root-пользователя для БД
Устанавливаем PHP-FPM
Тут всё достаточно просто
apt-get install php-fpm php-cli php-mysqli php-gd
Проверяем установку
php -v
Должно получиться
PHP 7.2.3-1ubuntu4.18 (cli) (built: Oct 28 2015 01:34:46)
Copyright (c) 1997-2018 The PHP Group
Заодно добавим PHP-FPM в автозагрузку командой
update-rc.d php-fpm defaults
Обратите внимание на то, что в новых пакетах php-fpm может называться, например, php7.2-fpm.
Шаг №3. Настраиваем пакеты и их взаимодействие
Теперь мы можем приступить непосредственно к настройке установленных пакетов для того, чтобы начать работу.
Настраиваем NGINX
Веб-сервер NGINX многопоточен. Согласно документации NGINX количество дочерних процессов веб-сервера должно быть равно количеству ядер процессора в системе.
Давайте узнаем, сколько ядер процессоров есть у нас
cat /proc/cpuinfo | grep processor | wc -l
На моей виртуальной машине доступно 1 ядро. Я отредактирую файл nginx.conf
nano nginx.conf
И выставлю значение
worker_processes 1;
В конец файла добавим ссылку на подключение директории виртуальных хостов
include /etc/nginx/sites-enabled/*;
Сохраняем файл через Ctrl + O.
Если проект должен быть доступен через браузер, то нужно создать виртуальный хост, который будет обслуживать наш проект.
Создадим директорию проекта в разделе /data
mkdir /data/myproject.com
mkdir /data/myproject.com/docs
mkdir /data/myproject.com/logs
chown -R nginx:nginx /data/myproject.com
chmod -R 0775 /data/myproject.com
Обратите внимание на то, какой пользователь выполняет процесс nginx. Это может быть и www-data (посмотреть можно в nginx.conf). Поэтому в командах выше можно заменить nginx на актуального пользователя.
Теперь создаём настройку для нашего виртуального хоста
nano /etc/nginx/sites-available/myproject.com
Ниже я привожу код конфигурации виртуального хоста.
server {
# слушаем стандартный порт HTTP
listen 80;
# здесь нужно указать наш домен
server_name myproject.com www.myproject.com;
# кодировка по умолчанию
charset utf-8;
# для разработки потребуются логи
access_log /data/myproject.com/logs/access.log combined;
error_log /data/myproject.com/logs/error.log;
# корневая директория логики
root /data/myproject.com/docs;
# установим сжатие данных
gzip on;
gzip_disable "msie6";
gzip_comp_level 6;
gzip_min_length 1100;
gzip_buffers 16 8k;
gzip_proxied any;
gzip_types text/plain application/xml
application/javascript
text/css
text/js
text/xml
application/x-javascript
text/javascript
application/json
application/xml+rss;
# настройки размеров и таймаутов
client_max_body_size 100m;
client_body_buffer_size 128k;
client_header_timeout 3m;
client_body_timeout 3m;
send_timeout 3m;
client_header_buffer_size 1k;
large_client_header_buffers 4 16k;
# правила обработки запросов к домену
location / {
# корневая директория
root /data/myproject.com/docs;
# стартовый скрипт
index index.php;
# правило автозагрузки в порядке следования: файл, папка, скрипт
try_files $uri $uri/ @fallback;
}
# правило для того, чтобы отдавать статические файлы
location ~* \.(jpeg|ico|jpg|gif|png|css|js|pdf|txt|tar|gz|wof|csv|zip|xml|yml) {
access_log off;
try_files $uri @statics;
expires 14d;
add_header Access-Control-Allow-Origin *;
add_header Cache-Control public;
root /data/myproject.com/docs;
}
location @statics {
rewrite ^/(\w+)/(.*)$ /$2 break;
access_log off;
rewrite_log off;
expires 14d;
add_header Cache-Control public;
add_header Access-Control-Allow-Origin *;
root /data/myproject.com/docs;
}
# правила обработки PHP-скриптов
location ~ \.php$ {
root /data/myproject.com/docs;
proxy_read_timeout 120;
fastcgi_read_timeout 120;
try_files $uri $uri/ =404;
# внимательно смотрите на то, какое имя задано у сокета
# это можно узнать в настройках php-fpm
fastcgi_pass unix:/var/run/php-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
Активируем виртуальный хост
ln -s ../sites-available/myproject.com
Если пользователь nginx существует, добавим пользователя nginx в группу www-data, чтобы NGINX мог получить доступ к сокету PHP
usermod -a -G www-data nginx
Перезапустим NGINX
service nginx restart
Настраиваем Percona
Любой MySQL движок использует файл /etc/my.cnf , но у Percona его по умолчанию нет.
Создадим его
touch /etc/my.cnf
Внесём настройки
[client]
# порт и сокет для клиента
port = 3306
socket = /var/run/mysqld/mysqld.sock
[mysqld]
user = mysql
pid-file = /var/run/mysqld/mysqld.pid
socket = /var/run/mysqld/mysqld.sock
port = 3306
datadir = /var/lib/mysql
# Отдадим под innodb четверть памяти. Настройка эта зависит от объёма данных в формате innodb
# Но в идеале нужно всегда устанавливать значение больше, чем полный объём данных в innodb
innodb_buffer_pool_size = 512M
# У нас один процессор, поэтому будет только 1 поток кэша
innodb_buffer_pool_instances = 1
# Чтобы innodb работал быстрее, отключаем запись резервных данных на жёсткий диск
innodb_flush_log_at_trx_commit = 2
innodb_flush_method = 'O_DIRECT'
Сохраним файл. Для того, чтобы применить более тонкие настройки, можно воспользоваться утилитой mysqltuner.
Зайдём на сервер MySQL. Пароль рута был задан при установке.
mysql -uroot -p
Посмотрим, что за пользователи созданы по умолчанию
use mysql;
select * from user;
Как видим, полно всего ненужного.

Удаляем пользователей, оставляя только root@localhost
drop user 'root'@'ubuntudev';
drop user 'root'@'127.0.0.1';
drop user 'root'@'::1';
drop user ''@'localhost';
drop user ''@'ubuntudev';
flush privileges;
Теперь создадим базу данных и пользователя для нашего PHP-приложения. Разумеется, пароль задаём свой.
create database application_db;
create user 'connect'@'localhost' identified by 'password';
grant SELECT, INSERT, UPDATE, DELETE on application_db.* to 'connect'@'localhost';
flush privileges;
Пользователь создан, права обновлены. Теперь можно будет спокойно соединяться с базой и работать с данными.
Настраиваем PHP
Зачастую нужно использовать PHP не только для генерации страниц, но и для выполнения команд из консоли.
При этом используются разные модули PHP и, как следствие, разные конфигурационные файлы. Для удобства сделаем один файл конфигурации и ссылки на него из модулей. Выполним поочерёдно команды
mv /etc/php/fpm/php.ini ../
rm /etc/php/fpm/php.ini
rm /etc/php/cgi/php.ini
cd /etc/php/fpm
ln -s /etc/php/php.ini
cd /etc/php/cgi
ln -s /etc/php/php.ini
В файле /etc/php/fpm/php.ini находим параметры и вносим изменения
short_open_tag = On
cgi.fix_pathinfo = 0
date.timezone = Europe/Moscow
Перезагружаем PHP-FPM
service php-fpm restart
Шаг №4. Взлетит?
Теперь попробуем написать что-нибудь на PHP и проверить работоспособность результата нашей долгой работы.
Перейдём в директорию проекта
cd /data/myproject.com/docs
Создадим там простенький файл index.php с содержимым
Теперь пропишем привязку хоста к доменному имени. Если Вы работаете под Windows, то с правами администратора откройте файл
C:\Windows\System32\drivers\etc\hosts
и добавьте туда строчку
172.20.4.14 myproject.com
Разумеется, нужно заменить 172.20.4.14 на IP, выданный Вам сетью.
Сохраняем файл, открываем браузер и набираем myproject.com.
Если всё сделано правильно, то результатом будет вот такая картинка

Шаг №5. Работа с файлами
А какой прок от виртуалки, если нет возможности удобно работать с файлами на ней?
Можно подключить общий диск или смонтировать USB устройство. Но гораздо удобнее использовать Samba для коннекта между win и *nix.
Установим пакет
apt-get install samba
Теперь нужно произвести настройки в файле /etc/samba/smb.conf . Добавляем в конец файла строки
[my-projects]
comment = My projects
path = /data/
valid users = developer
create mask = 0775
force create mode = 0775
directory mask = 0775
writable = yes
force group = www-data
Теперь нужно создать пользователя samba командой
smbpasswd -a developer
указав при этом отдельный пароль для него.
Перезагружаем процессы samba
service smbd restart
service nmbd restart
Теперь уже в windows в адресной строке проводника можно вбить наш IP

В результате мы увидим вот такую сетевую директорию

Кликнув по ней правой клавишей, мы сможем подключить её как сетевой диск и работать напрямую через любимый редактор файлов или IDE.
За сим всё!
С радостью отвечу на возникшие вопросы в комментариях!


