Локальный веб-сервер — VirtualBox, Debian, Nginx+php-fpm, MySQL

Дмитрий Корнев
24 августа 2016

Создавая недавно новый сайт на Yii2 я прилично помучился из-за различий рабочего окружения, которые обеспечивают локальный Open-Server на Windows и реальный сервер с Debian. Это вынудило меня настроить правильный локальный сервер, используя VirtualBox. В статье я расскажу, как это сделать.

Задача

Есть компьютер с Windows 10, где установлен VirtualBox. Создадим виртуальную машину в VirtualBox, установим на неё Debian. Затем настроим на этой машине веб-сервер и установим некоторый софт, необходимый для веб-разработки. Дополнительно настроим общую папку, чтобы удобно работать в ней с кодом сайтов в любимом редакторе под Windows. Открываться сайты тоже будут под Windows.

Виртуалка и Debian

Скачиваем новейший образ для установки Debian. Даю ссылку на страницу с образами, предназначенными для сетевой установки. Они маленькие, не имеют ничего лишнего, хорошо подходят для веб-сервера. Я использую 64-битный образ. На момент написания статьи актуален Debian версии 8.5.

Создаём виртуальную машину:

Объём памяти и диска по своему усмотрению.

Диск особо расходоваться не будет, т.к. мы будем работать с сайтами в общей папке, которая будет подключается к Debian как дополнительный носитель. Тип основного диска по умолчанию, динамический.

Машина подготовлена. Пока не включаем. Заходим в свойства машины, подключаем скаченный установочный образ на CD/DVD:

Пройдёмся по другим настройкам.

Число ядер процессора выбирайте сами, в зависимости от возможностей и потребностей. Обязательно установите отметку «Включить PAE/NX».

Можно выключить разные ненужные вещи, типа удаленного доступа по RDP, звуковой карты, порта USB стандарта 2.0 и т.д.

В сетевых адаптерах выбираем тип подключения «NAT», ниже тут же кликаем «Дополнительно» и заходим в «Проброс портов».

Здесь для SSH указываем порты 3022 и 22, для веба 80 и 80. Остальное заполнять не надо. Этого достаточно.

Почему именно «NAT»? Виртуальную машину сможете использовать только вы, она не будет видна в вашей локальной сети и никак на неё не повлияет. Для меня это важно.

Если вы хотите, чтобы ваша виртуальная машина полноценно добавлялась в вашу локальную сеть, то выбирайте тип подключения «Сетевой мост». Другие компьютеры в вашей локальной сети тоже смогут обращаться к вашей виртуальной машине.

В завершении добавляем общую папку:

Выходим из настроек.

Запускаем машину, устанавливаем Debian.

Процедура установки Debian ничем особо непримечательна. Выбираем вначале обычную установку, я предпочитаю с графическим интерфейсом. По ходу выбираем всякие параметры. Запасаемся терпением.

Ближе к концу установки надо будет выбрать компоненты, которые требуется установить. Рабочий стол и прочий мусор нам на веб-сервере не нужен, снимаем везде отметки. Оставляем только SSH-сервер и стандартные системные утилиты.

Предлагаемый в списке «web server»  я тоже предпочитаю не ставить, т.к. там будет Apache, который в современном мире нафиг не нужен. Лучше установить потом самому именно те программы, какие нужны.

В общем, установка завершается, машина перезапускается.

Входим под root-ом:

Всё ок? Небольшая рекомендация. Делайте «снимки» машины на разных этапах настройки и использования. Это полезно! Если в процессе каких-то настроек или других действий что-то пойдёт не так, то вы сможете откатиться к предыдущему состоянию.

Вот сейчас машина успешно стартовала. Выключите её, сделайте снимок. Это займет от силы минуту.

Чтобы выключить машину можно написать poweroff, чтобы перезапустить — reboot.

Настройки

Пока продолжаем работать с созданной машиной через окно VirtualBox. К подключению по SSH вернёмся чуть позже.

В процессе установки Debian, кроме root, обязательно создаётся дополнительный пользователь. Если он совсем вам не нужен, то его можно удалить:

userdel -r имя_пользователя

Дополнительный пользователь иногда полезен. Например, когда вы будете работать с Composer. Этот менеджер пакетов считает, что работа под root небезопасна и выдаёт предупреждение, хотя и продолжает исправно работать.

По умолчанию Debian не позволяет подключиться по SSH, используя пользователя root. Выглядит это так:

login as: root
root@127.0.0.1's password:
Access denied

Дополнительным пользователем подключаться можно сразу.

Чтобы по SSH можно было зайти root-ом редактируем файл /etc/ssh/sshd_config.

Ищем:

PermitRootLogin without-password

Меняем на:

PermitRootLogin yes

Чтобы изменения вступили в силу перезагружаем машину.

Для подключений по SSH в Windows удобно использовать PuTTY. Адрес машины 127.0.0.1, порт 3022:

Теперь уже можно большую часть времени работать с виртуальной машиной через SSH. Оно удобнее, чем через окно VirtualBox. Окно PuTTY можно свободно растягивать и его содержимое будет под это подстраиваться. В вашем распоряжении буфер обмена и даже мышь.

Чтобы работала общая папка требуется установить дополнения гостевой ОС.

Для начала подключаем образ:

Теперь монтируем его:

mount /dev/cdrom /media/cdrom

Предварительно устанавливаем требуемые пакеты:

apt-get install build-essential module-assistant

Ещё выполняем:

m-a prepare

Теперь сама установка дополнений:

sh /media/cdrom/VBoxLinuxAdditions.run

Результат успешной установки:

root@webdev:~# sh /media/cdrom/VBoxLinuxAdditions.run
Verifying archive integrity... All good.
Uncompressing VirtualBox 5.1.2 Guest Additions for Linux...........
VirtualBox Guest Additions installer
Copying additional installer modules ...
Installing additional modules ...
vboxadd.sh: Building Guest Additions kernel modules.
update-initramfs: Generating /boot/initrd.img-3.16.0-4-amd64
vboxadd.sh: Starting the VirtualBox Guest Additions.

Could not find the X.Org or XFree86 Window System, skipping.
root@webdev:~#

Перезапускаем машину и радуемся. Теперь у нас заработала общая папка. В виртуальной машине в моём случае это: /media/sf_Webdev. На основной машине она соответствует: c:\VirtualDub\Folders\Webdev.

Работа с общей папкой в виртуальной машине осуществляется из под пользовательской группы vboxsf. Это означает, что если пользователь (под которым вы работаете) не входит в эту пользовательскую группу, то он не сможет записывать в общую папку. Для него в папке по умолчанию режим «readonly».

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

usermod -aG vboxsf имя_пользователя
usermod -aG vboxsf root
usermod -aG vboxsf www-data

Пользователь www-data по умолчанию используется Nginx.

Веб-сервер

Переходим к настройке веб-сервера:

apt-get install nginx
apt-get install php5-fpm php5-cgi

В общей папке создадим папку первого сайта: /media/sf_Webdev/site.loc.

Соответственно она появится и на основной машине. В эту папку поместим тестовый файл index.php с кодом:

<?php phpinfo(); ?>

Не имеет значения, как именно вы создаёте папки и файлы в общей папке. Можете всё это делать уже из вашей основной системы.

Создадим символическую ссылку для каталога сайта:

ln -s /media/sf_Webdev/site.loc /var/www

Создадим для сайта файл настроек Nginx /etc/nginx/sites-available/site.loc.

Его содержимое:

server {
  listen 80;
  server_name site.loc;
  root /var/www/site.loc;
  index index.php;

  location / {
    try_files $uri $uri/ =404;
  }

  location ~ \.php$ {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/var/run/php5-fpm.sock;
  }

  access_log /var/log/nginx/site.loc_access.log;
  error_log /var/log/nginx/site.loc_error.log;
}

Подключим файл настроек:

ln -s /etc/nginx/sites-available/site.loc /etc/nginx/sites-enabled/site.loc

Перезапустим Nginx:

/etc/init.d/nginx restart

Теперь в основной системе отредактируем hosts-файл c:\Windows\System32\drivers\etc\hosts.

В него надо добавить строчку:

127.0.0.1 site.loc

Всё! Настало время в веб-браузере основной системы попробовать открыть сайт http://site.loc. Если всё в порядке, то вы увидите информацию по PHP виртуальной машины.

Если сайт не открылся, вы получили белую страницу, то скорее всего у вас в основной системе уже используется каким-то приложением порт 80. Соответственно проброс этого порта из виртуальной системы в основную не удался и ничего не работает.

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

cmd

Выполняем в ней:

netstat -an -p tcp -o | findstr 80

Получим примерно такое:

C:\Users\kodmg>netstat -an -p tcp -o | findstr 80
  TCP    0.0.0.0:80             0.0.0.0:0              LISTENING       5684
  TCP    0.0.0.0:7680           0.0.0.0:0              LISTENING       1000
  TCP    0.0.0.0:49664          0.0.0.0:0              LISTENING       580
  TCP    0.0.0.0:49665          0.0.0.0:0              LISTENING       980
  TCP    192.168.1.210:56543    77.234.45.61:80        ESTABLISHED     1736
  TCP    192.168.1.210:56793    5.45.58.148:80         CLOSE_WAIT      1736
  TCP    192.168.1.210:56800    52.20.134.145:443      CLOSE_WAIT      7036
  TCP    192.168.1.210:57180    95.213.255.17:443      ESTABLISHED     8616
  TCP    192.168.1.210:57288    188.43.75.80:80        TIME_WAIT       0
  TCP    192.168.1.210:57309    104.27.186.197:80      ESTABLISHED     8616
  TCP    192.168.1.210:57340    23.43.134.135:80       TIME_WAIT       0

Здесь первая строка с адресом 0.0.0.0:80 – это признак, что 80-ый порт в настоящее время используется. В конце этой строки цифры, в примере это 5684. Данный номер — это ID процесса приложения.

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

На вкладке «Подробности» делаем сортировку по колонке «ИД процесса» и ищем нужный номер. В моём случае это оказался Skype.

По умолчанию Skype использует именно 80-ый порт для соединений, но это можно изменить в его настройках. Убираем галочку «Для дополнительных входящих соединений следует использовать порты 80 и 443». Выходим из настроек, перезапускаем Skype.

Той же командой в консоли ещё раз делаем проверку:

C:\Users\kodmg>netstat -an -p tcp -o | findstr 80
  TCP    0.0.0.0:7680           0.0.0.0:0              LISTENING       1000
  TCP    0.0.0.0:49664          0.0.0.0:0              LISTENING       580
  TCP    0.0.0.0:49665          0.0.0.0:0              LISTENING       980
  TCP    192.168.1.210:56543    77.234.45.61:80        ESTABLISHED     1736
  TCP    192.168.1.210:56793    5.45.58.148:80         CLOSE_WAIT      1736
  TCP    192.168.1.210:56800    52.20.134.145:443      CLOSE_WAIT      7036
  TCP    192.168.1.210:57180    95.213.255.17:443      ESTABLISHED     8616
  TCP    192.168.1.210:57309    104.27.186.197:80      ESTABLISHED     8616
  TCP    192.168.1.210:57340    23.43.134.135:80       TIME_WAIT       0

Теперь 80-ый порт никем не используется. Запускаем обратно виртуальную машину и снова пробуем открывать сайт. Теперь, если вы всё делали по инструкции, то он точно должен открыться!

Nginx

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

Очень многие сталкиваются с этими граблями. Типичный случай: вы изменили файл CSS или JS, а на сайте не видно этих изменений, файл используются старый.

Мне помогло решить проблему включение в конфиг Nginx параметра:

if_modified_since off;

Некоторым помогает ещё этот дополнительный параметр:

sendfile off;

Поскольку проблема может быть актуальна для всех сайтов, работающих на веб-сервере виртуальной машины, то правильнее включить эти параметры в общем файле /etc/nginx/nginx.conf.

Дополнительная информация по теме.

База

Вместо обычного MySQL я предпочитаю Percona Server. Многие рекомендуют этот продукт, благодаря скорости и дополнительным фичам. Я использую Percona Server не менее 2 лет и тоже могу его рекомендовать. Для сайта, для любого сайтового движка — это будет просто MySQL, они не увидят разницы.

Я не делал сравнений. Просто однажды перешел на Percona Server и все. Никаких проблем никогда не было. Если при этом есть хоть небольшой прирост скорости, оно стоит того.

Установка Percona Server:

wget https://repo.percona.com/apt/percona-release_0.1-4.$(lsb_release -sc)_all.deb
dpkg -i percona-release_0.1-4.$(lsb_release -sc)_all.deb

Обновляем источники:

apt-get update

Продолжаем установку:

apt-get install percona-server-server-5.7

В процессе установки потребуется указать пароль для root-пользователя базы. Не путайте с root-пользователем системы.

Установим дополнительно phpMyAdmin. Последнее время я предпочитаю это делать через Composer. Так проблем меньше, да и версия точно будет новая. Вначале установим сам Сomposer:

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

Для рабочего софта лучше создать отдельный локальный сайт, пример webdev.loc. Это будет каталог /var/www/webdev.loc. Настройка Nginx аналогична той, что была выше. Пробрасывать этот каталог в основную систему не нужно.

В этом каталоге запускаем установку phpMyAdmin:

cd /var/www/webdev.loc
composer create-project phpmyadmin/phpmyadmin --repository-url=https://www.phpmyadmin.net/packages.json --no-dev

Он установится в каталог /var/www/webdev.loc/phpmyadmin.

Теперь из основной системы phpMyAdmin можно открыть: http://webdev.loc/phpmyadmin.

Workbench

Приложение MySQL Workbench — это удобный инструмент для работы с базой. Устанавливать его нужно на основной машине. Для подключения к базе MySQL на виртуальной машине можно использовать SSH. При создании подключения просто устанавливаем параметр «Connection Method» в состояние «Standard TCP/IP over SSH» и далее вписываем уже знакомые параметры:

Рабочий софт

Установка Composer уже была выше. Остальное по желанию.

Установка Node.js:

curl -sL https://deb.nodesource.com/setup_6.x | bash -
apt-get install nodejs

Установка Gulp.js:

apt-get install npm
npm i -g gulp

Если будут предупреждения:

a RegExp DoS issue
npm WARN deprecated minimatch@0.2.14: Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue
npm WARN deprecated graceful-fs@1.2.3: graceful-fs v3.0.0 and before will fail on node releases >= v7.0. Please update to graceful-fs@^4.0.0 as soon as possible. Use 'npm ls graceful-fs' to find it in the tree.

Тогда надо установить предложенное, пример далее. В вашем случае версии могут быть другие, обратите на это внимание.

npm install -g minimatch@3.0.2
npm install -g graceful-fs@^4.0.0

Установка Less.js:

npm install -g less

Vagrant

Это такая вспомогательная программа для VirtualBox. Хотя, работает и с другими системами виртуализации. Позволяет легко и быстро автоматизированно создавать виртуальные машины. Можно создать наподобие той, которую мы уже создали. Работать с Vagrant необходимо из командной строки.

Пишу это здесь просто для информации, что такое есть.

Я пробовал Vagrant. Да, действительно программа делает своё дело. Но мне показалось это лишним и не совсем тем, что надо. Мои соображения на этот счёт:

В принципе, боксы для Vagrant — это созданные и специально настроенные виртуальные машины VirtualBox. Мы, вот, создали свою виртуальную машину. Её, в теории, можно немного допилить, чтобы использовать в качестве бокса Vagrant. Бокс может быть локальным.

Я когда начал изучать информацию по Vagrant, то меня напугали все эти инструкции в интернете. В каждой автор начинает разбирать конфигурационный файл виртуальной машины, и это поначалу выглядит дико и совсем непросто. Спешу успокоить новичков! Этот файл создается автоматически самим Vagrant-ом. Вы (при желании) можете внести в него дополнительные параметры, а можете и не вносить! Машина просто получит настройки по умолчанию. Часто этого достаточно.

Далее простой пример, как можно создать с помощью Vagrant тот же веб-сервер на базе Debian 8.

Перед тем как начать скачиваем Vagrant с официального сайта и устанавливаем его в любую папку. Важно, чтобы в пути к этой папке не было русских символов.

Открываем консоль в Windows:

cmd

Скачиваем нужный бокс и убеждаемся, что он попал в список доступных локально боксов:

vagrant box add cimmwolf/jessie64-lemp
vagrant box list

Для первой команды название бокса я нашёл в списке по запросу «debian 8 lemp». Вот информация по нему, где автор советует перед использованием бокса выполнить установку плагина:

vagrant plugin install vagrant-vbguest

Такая команда выполняется единожды, если ранее данный плагин ещё не инсталлировался. Плагин позволяет автоматически устанавливать в виртуальную машину дополнения гостевой ОС.

Создаём каталог и переходим в него, например:

mkdir c:\VMs\Deb8lemp
cd c:\VMs\Deb8lemp

Инициализация виртуальной машины:

vagrant init cimmwolf/jessie64-lemp

При этом у нас появляется в этом каталоге файл Vagrantfile. Он содержит конфигурацию будущей машины. Как я уже сказал, настройки можно оставить по умолчанию. Устанавливаем виртуальную машину:

vagrant up

Всё! Через некоторое время машина будет готова.

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

Для входа по SSH используем адрес 127.0.0.1, порт 2222, пользователя vagrant, пароль vagrant.

Таким образом, всего несколько команд в консоли и у нас готовая для работы виртуальная машина.

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

C:\VMs\Deb8lemp>vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Checking if box 'cimmwolf/jessie64-lemp' is up to date...
==> default: Clearing any previously set forwarded ports...
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
    default: Adapter 1: nat
==> default: Forwarding ports...
    default: 22 (guest) => 2222 (host) (adapter 1)
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
    default: SSH address: 127.0.0.1:2222
    default: SSH username: vagrant
    default: SSH auth method: private key
==> default: Machine booted and ready!
[default] GuestAdditions 5.1.2 running --- OK.
==> default: Checking for guest additions in VM...
==> default: Mounting shared folders...
    default: /vagrant => C:/VMs/Deb8lemp
==> default: Machine already provisioned. Run `vagrant provision` or use the `--provision`
==> default: flag to force provisioning. Provisioners marked to run always will still run.

В VirtualBox машину тоже видно:

Docker

Это ещё один альтернативный вариант.

По своей сути Docker предлагает уже не виртуализацию, а создание изолированных контейнеров поверх вашей основной системы. Таких контейнеров на одной системе можно запускать множество. Приложения в каждом из них работают полностью независимо.

Из-за того, что здесь нет полноценной виртуализации, то нет и расхода лишних ресурсов на виртуальные операционные системы. Процессор, диск, память расходуются исключительно на установленные в контейнерах приложения.

Docker предназначен для Linux и использует для создания контейнеров специфику ядра этой операционной системы. В Windows использовать Docker можно двумя способами. Во-первых, есть Boot2docker, который автоматически создаёт, опять же, в VirtualBox виртуальную машину и уже там запускает контейнеры. Во-вторых, можно самостоятельно создать виртуальную машину с Linux и там разворачивать контейнеры.

Автоматически созданная машина Boot2docker-ом:

Помимо уже сказанного есть ещё одна очень весомая фишка.

Мы создаём для разработки сайта один или несколько контейнеров Docker. Зависит от его сложности и масштабов. Потом, когда сайт будет готов, то мы именно эти же контейнеры просто переносим на хостинг! Получается, что сайт продолжает работать в своём родном окружении, уже на совсем другой площадке.

На мой взгляд Docker интересен, но только если вы работаете именно в Linux. Использование контейнеров через виртуализацию трудно назвать изящным вариантом. Поэтому я, как пользователь Windows, отказался от Docker. Во всяком случае, нет пока необходимости.

13 комментариев

fe
Дмитрий, статья просто шикарная. Но не мог бы ты подсказать как организовать удалённый доступ с хоста к базе данных на виртуальной машине? То есть, я вот пользуюсь MySQL Workbranch, как всё настроить, чтобы я мог работать с базами на виртуальной машине из основной системы?
Проще всего работать с базой через SSH. Для этого уже все готово. Просто создаем подключение и работаем. В статью добавил скриншот по теме.
mo
Спасибо все очень круто описано. Хочется продолжения, добавления ключей для доступа без пароля к ssh, подключить git к этому всему и т.д. Принятие изменения из bare репозитория, слышал нужно хук писать какой-то что бы он срабатывал когда делаем git pull
А зачем все это на локальном сервере для разработки? Я пользуюсь Netbeans на основной машине, код здесь же в общей папке, и git у меня здесь же. Из Netneans очень удобно работать с git.
as
Самая годная инструкция, которую нашел. Автор пречислен к лику святых теперь, благодарю!
Ан
У меня phpmyadmin не заработал. Он в процессе установки требовал apache
Странно. Раньше не требовал. Три года уже прошло, как писалась статья. На текущий момент я посоветую другое. Проще ставить phpMyAdmin через Composer. Проблем нет и версия точно новая. Поступаю так и в Debian и в Ubuntu. Я внес изменения в статье. Попробуй.
Дм
Спасибо за полезную информацию! Но есть один вопрос: Вы написали - В общей папке создадим папку первого сайта: /media/sf_Webdev/site.loc. Как я понял папка сайта называется sf_Webdev, но дальше по пути еще имеется файл site.loc. Он в себя что нибудь включает или остается пустым?
sf_Webdev - это каталог на виртуалке, он соответствует каталогу Webdev на реальной машине. Это общий каталог, где находятся каталоги сайтов. В нем site.loc - это именно каталог, а не файл. В тексте все по порядку, надо именно так все и делать. Не надо ничего додумывать лишнего.
Ал
Привет. Не подскажешь по такой проблеме - не могу в Workbench подключиться к базе MySQL (которая на VirtualBox) через SSH. При этом: 1) Из командной строки Windows 10 (нативный OpenSSH) по SSH к вирт. машине подключение работает успешно. В Workbench указаны те же самые SSH Hostname, Username и пароль - поэтому здесь ошибки быть не может. 2) MySQL Hostname, Server Port - здесь тоже ошибки быть не может, перепроверял данные различными утилитами линукс. 3) MySQL username и пароль - тоже все верно ввожу. Права подключения выставлены тоже верно (host указан как '%' в mysql.user). В чем может быть причина? Рыл решение в Ру и бурж сайтах данного вопроса - ничего толком нет. Предлагалось лишь внести некоторые изменения в файлы конфигурации mysql и даже ssh-server. Все это опробовано и тоже не помогло. Также предполагал, что возможен баг в самой Worlbench, пробовал устанавливать старые версии, в том числе мажорную 6.* - тоже не помогает.
Ал
Решил проблему. У Worlbench в строке SSH Hostname НЕ надо указывать порт, даже если он отличный от стандартного (как у тебя в примере 3022). Это связано с тем, что я использую не puTTY, как указано у тебя и в других мануалах, а нативный SSH клиент в Win10
Ma
Очень годная статья.
Mi
А не проще вместо "usermod -aG vboxsf www-data" сразу монтировать как-то так mount -t vboxsf имя_реального_каталога -o rw,dmode=777,gid=(нужного пользователя),uid=(нужного пользователя) /куда/