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

В чём суть концепции виртуальных хостов и чем отличаются подходы по IP-адресу и по имени

Идея виртуального хостинга появилась не вчера. Ещё на заре коммерческого интернета хостинг-провайдеры столкнулись с простым фактом. Выделенный сервер для каждого клиента - дорого и неэффективно. Большинство сайтов потребляют мизерные ресурсы и простаивают 90 процентов времени. Логичное решение - разместить несколько сайтов на одной машине так, чтобы каждый выглядел самостоятельным.

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

Второй подход - на основе имён. Один IP-адрес, много сайтов. Различение идёт по заголовку Host в HTTP-запросе, который браузер отправляет при обращении к серверу. Такая схема появилась в HTTP 1.1 специально для решения проблемы с IP-адресами и моментально стала доминирующей. Сегодня подавляющее большинство виртуальных хостов настроены именно по именам, и именно этот подход мы и рассмотрим.

Механизм работает так. Клиент вводит в браузере адрес сайта. DNS преобразует имя в IP. Браузер устанавливает TCP-соединение с сервером по этому IP и отправляет HTTP-запрос, в заголовке которого указано исходное имя хоста. Apache на сервере смотрит в заголовок Host, находит соответствующий виртуальный хост в своей конфигурации и отдаёт контент именно этого сайта. Элегантная архитектура, которая работает прозрачно для пользователя.

Обновление системы и установка Apache как фундамент для дальнейшей работы

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

sudo apt update
sudo apt upgrade -y

Первая команда обновляет списки пакетов из репозиториев. Вторая устанавливает свежие версии того, что уже установлено в системе. Флаг -y автоматически соглашается со всеми запросами apt, что удобно при написании скриптов развёртывания и при уверенности в том, что обновления безопасны.

Теперь сам Apache. Установка в Ubuntu - одна команда, без дополнительных репозиториев или экзотических манёвров.

sudo apt install apache2 -y

Процесс занимает обычно не больше минуты. По завершении в системе появляется работающий веб-сервер с базовой конфигурацией. Apt умно настраивает автозапуск через systemd, открывает 80-й порт и кладёт стандартную приветственную страницу. Уже на этом этапе по IP-адресу сервера отзывается характерное сообщение It works.

Перезапуск и проверка статуса - хороший способ убедиться, что сервис действительно работает нормально.

sudo systemctl restart apache2
sudo systemctl status apache2

В ответ systemd покажет развёрнутую картину состояния сервиса.

? apache2.service - The Apache HTTP Server
     Loaded: loaded (/lib/systemd/system/apache2.service; enabled; vendor prese>
     Active: active (running) since Mon 2022-06-27 09:32:14 UTC; 18s ago
       Docs: https://httpd.apache.org/docs/2.4/
    Process: 13093 ExecStart=/usr/sbin/apachectl start (code=exited, status=0/S>
   Main PID: 13098 (apache2)
      Tasks: 55 (limit: 1146)
     Memory: 4.7M
        CPU: 25ms
     CGroup: /system.slice/apache2.service
             ??13098 /usr/sbin/apache2 -k start
             ??13099 /usr/sbin/apache2 -k start
             ??13100 /usr/sbin/apache2 -k start

Главные показатели для проверки - Loaded со значением enabled (означает автозапуск при загрузке системы) и Active со значением running. Если что-то пошло не так, статус будет другим, а рядом появятся сообщения об ошибках. Пять запущенных процессов в CGroup - это модель работы Apache по умолчанию, когда главный процесс порождает несколько дочерних для обработки запросов.

Создание директорий для двух независимых сайтов и настройка прав доступа к ним

Каждый виртуальный хост в Apache живёт в собственной директории. Такая изоляция - основа безопасности и удобства управления. Файлы одного сайта не видны другому, сбой в одном проекте не влияет на работу остальных, резервное копирование делается для каждого сайта отдельно.

sudo mkdir -p /var/www/host1/public_html
sudo mkdir -p /var/www/host2/public_html

Структура получается двухуровневой. Верхняя директория с именем хоста служит контейнером для всех файлов, относящихся к сайту - логов, скриптов обслуживания, резервных копий. Внутри неё public_html содержит непосредственно веб-контент, доступный через браузер. Такое разделение защищает служебные файлы от случайного выставления наружу. Кто-то забыл удалить файл с паролями в корне сайта - катастрофа. Если он лежал уровнем выше public_html - веб-сервер его просто не видит.

По умолчанию созданные через sudo директории принадлежат пользователю root. Для работы над содержимым сайта это неудобно - каждое изменение требовало бы прав суперпользователя. Меняем владельца на обычного пользователя.

sudo chown -R $USER:$USER /var/www/host1/public_html
sudo chown -R $USER:$USER /var/www/host2/public_html

Переменная $USER здесь подставляется автоматически и содержит имя текущего пользователя. Такой подход элегантнее, чем жёсткое указание конкретного имени - те же команды работают под любым логином без правок. Флаг -R обеспечивает рекурсивную смену владельца для всего содержимого директории.

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

sudo chmod -R 755 /var/www

Права 755 в классическом понимании Unix означают полный доступ для владельца, а также чтение и исполнение для группы и всех остальных. Для директорий исполнение означает возможность входить внутрь. Такая конфигурация даёт Apache (работающему от пользователя www-data) достаточные права для чтения, но не позволяет ему писать в файлы. Принципиально важная защита от ситуаций, когда взлом веб-приложения превращается в возможность модифицировать исходники сайта.

Создание стартовых страниц для обоих сайтов через простую команду echo

Нужно проверить, что виртуальные хосты действительно работают и возвращают разный контент. Для этого в каждом сайте создаётся собственный файл index.html с характерным содержимым. Можно было бы открыть текстовый редактор и написать полноценную HTML-страницу, но для проверки работоспособности хватает одной строки. Echo с перенаправлением в файл делает это моментально.

sudo echo “Welcome to Virtual Host 1.” > /var/www/host1/public_html/index.html

Для второго хоста аналогично.

sudo echo “Welcome to Virtual Host 2.” > /var/www/host2/public_html/index.html

Результат - два простейших файла с разным текстом внутри. Этого достаточно, чтобы визуально отличить, какой именно виртуальный хост отвечает на запрос. В реальной работе в эти директории ложится полноценный сайт - HTML-шаблоны, изображения, стили, скрипты, иногда целые PHP-приложения с фреймворками и базами данных.

Подмена DNS через файл hosts для локального тестирования без регистрации доменов

Для проверки работы виртуальных хостов нужны два домена, по которым к ним можно обращаться. Реальная регистрация доменов для учебных целей - расточительство. Процесс платный и долгий. Гораздо проще временно подменить DNS на уровне текущей машины через файл /etc/hosts. Любые имена, прописанные в этом файле, операционная система обрабатывает до обращения к настоящим DNS-серверам.

sudo sh -c "echo 127.0.0.1 www.host1.com >> /etc/hosts"
sudo sh -c "echo 127.0.0.1 www.host2.com >> /etc/hosts"

Конструкция с sh -c нужна по техническим причинам. Простое sudo echo >> не сработало бы, поскольку перенаправление в файл обрабатывается обычной оболочкой до повышения привилегий. Обёртка через sh -c решает проблему - вся команда целиком выполняется в отдельной оболочке с правами суперпользователя.

Результат - две строки в конце файла hosts, которые отправляют запросы к www.host1.com и www.host2.com на локальный адрес 127.0.0.1. Для системы это выглядит так, будто соответствующие домены физически указывают на машину, с которой идёт обращение. В продакшене такие записи делаются в DNS-зоне, но для разработки и тестирования подмена через hosts - стандартная практика.

Создание отдельных конфигурационных файлов для каждого виртуального хоста

Apache в Ubuntu использует модульную систему конфигурации. Настройки для каждого сайта живут в отдельных файлах в директории /etc/apache2/sites-available. Такой подход сильно упрощает управление - добавление нового сайта сводится к созданию одного файла, отключение - к удалению симлинка, никаких правок в общем конфиге.

В качестве отправной точки удобно использовать стандартный файл 000-default.conf, который Apache кладёт при установке. Он содержит корректный шаблон со всеми нужными директивами, и его легко адаптировать под конкретные хосты.

sudo cp /etc/apache2/sites-available/000-default.conf /etc/apache2/sites-available/host1.conf
sudo cp /etc/apache2/sites-available/000-default.conf /etc/apache2/sites-available/host2.conf

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

<VirtualHost *:80>

    ServerAdmin Адрес электронной почты защищен от спам-ботов. Для просмотра адреса в браузере должен быть включен Javascript.

    ServerName host1

    ServerAlias www.host1.com

    DocumentRoot /var/www/host1/public_html

    ErrorLog ${APACHE_LOG_DIR}/error.log

</VirtualHost>

Разберём директивы по порядку. VirtualHost *:80 определяет, что этот блок обрабатывает запросы на 80-м порту со всех интерфейсов сервера. ServerAdmin - адрес почты администратора, который используется в автоматически генерируемых страницах ошибок. ServerName и ServerAlias определяют имена, по которым сервер должен отвечать этим сайтом - основное имя и один или несколько дополнительных алиасов.

DocumentRoot указывает физическое местоположение файлов сайта на диске. Именно оттуда Apache берёт контент для отдачи браузеру. ErrorLog определяет, куда писать сообщения об ошибках - переменная APACHE_LOG_DIR обычно развёртывается в /var/log/apache2, но использование переменной вместо жёсткого пути делает конфиг более универсальным и переносимым.

Для второго хоста содержимое аналогично, только с заменой всех упоминаний host1 на host2.

<VirtualHost *:80>

    ServerAdmin Адрес электронной почты защищен от спам-ботов. Для просмотра адреса в браузере должен быть включен Javascript.

    ServerName host2

    ServerAlias www.host2.com

    DocumentRoot /var/www/host2/public_html

    ErrorLog ${APACHE_LOG_DIR}/error.log

</VirtualHost>

На практике в таких конфигах часто добавляются дополнительные директивы - отдельные файлы логов для каждого сайта, настройки доступа к определённым директориям, правила переписывания URL, подключение модулей PHP или Python. Базовая версия, показанная выше, содержит минимум для рабочей схемы.

Активация виртуальных хостов через утилиту a2ensite и отключение стандартного сайта

Создание файла конфигурации - только половина дела. Apache не знает о нём, пока файл не будет активирован. В Ubuntu для этого существует специальный механизм через утилиты a2ensite и a2dissite. Технически они просто создают и удаляют символические ссылки из sites-available в sites-enabled, но использование стандартных утилит делает управление более безопасным.

sudo a2ensite host1.conf
sudo a2ensite host2.conf

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

Стандартный сайт 000-default.conf активирован по умолчанию и может конфликтовать с созданными хостами. Его нужно выключить.

sudo a2dissite 000-default.conf

Эта директива отвязывает симлинк из sites-enabled, оставляя сам файл в sites-available. Если в будущем потребуется вернуть стандартный сайт, его можно активировать обратно одной командой. Такой подход гораздо удобнее удаления файлов - ничего не теряется, все варианты остаются доступны.

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

sudo apache2ctl configtest

В идеальном случае ответ будет Syntax OK. Любые ошибки - с указанием конкретного файла и строки, где обнаружена проблема. Это сэкономит массу времени при отладке сложных конфигураций с десятками виртуальных хостов.

Теперь применяем изменения через reload, а не restart. Разница существенная. Reload перечитывает конфигурацию без остановки сервиса и разрыва активных соединений. Restart полностью останавливает и заново запускает Apache, что приводит к кратковременной недоступности сайтов. Для продакшена reload почти всегда предпочтительнее.

sudo systemctl reload apache2

Проверка работоспособности всей конструкции и решение типичных проблем при настройке

Финальный этап - убедиться, что настройка действительно работает и оба виртуальных хоста отвечают собственным содержимым. Классический инструмент для такой проверки - curl. Он отправляет HTTP-запрос и показывает ответ сервера прямо в терминале.

$ curl www.host1.com

В ответ должно прийти содержимое index.html первого хоста - текст Welcome to Virtual Host 1. Если вместо этого приходит сообщение об ошибке или содержимое другого сайта, значит, где-то в цепочке настроек есть ошибка.

Аналогично для второго хоста.

$ curl www.host2.com

Ответ - Welcome to Virtual Host 2. Когда оба запроса возвращают ожидаемое содержимое, виртуальные хосты точно настроены правильно. Можно переходить к развитию - заливать реальные сайты в директории, добавлять PHP, подключать базы данных, настраивать HTTPS через Let's Encrypt.

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

  1. Неправильные права на директории приводят к ошибкам 403 Forbidden при попытке открыть сайт в браузере
  2. Опечатки в ServerName или ServerAlias заставляют Apache обслуживать запросы неверного хоста
  3. Забытая активация через a2ensite оставляет конфиг в неактивном состоянии и никак не влияет на работу сервера
  4. Неотключённый стандартный сайт может перехватывать запросы, не попавшие ни под один виртуальный хост
  5. Ошибки в файле hosts не дают тестовым доменам разрешаться в нужный IP-адрес
  6. Кэширование в браузере иногда показывает старое содержимое даже после корректной настройки, помогает обновление с Ctrl+Shift+R
  7. Неперезагруженная конфигурация Apache после правок оставляет сервер работать со старыми настройками

Настройка виртуальных хостов - базовый навык для любого, кто работает с веб-серверами. Освоив эту технику однажды, администратор получает возможность обслуживать десятки проектов на одной машине без дополнительных затрат. В мире, где экономия на инфраструктуре напрямую влияет на прибыльность проекта, такой навык окупается быстро и многократно. А знание того, как именно работает заголовок Host и как его использует Apache, помогает понимать и куда более сложные темы - балансировку нагрузки, обратное проксирование, конфигурацию CDN и прочие вещи, которые строятся на том же фундаменте.