Виртуальный хостинг для Django (FreeBSD + Apache + mod_python / mod_wsgi)

    Создавая новый проект на Django, ты в очередной раз лезешь изменять конфигурации своего web-сервера. И вроде бы ничего страшного, да только конфигурации ты меняешь уже чаще, чем выгуливаешь свою собаку. Как-то не правильно? Согласен (собака, думаю, тоже не возражает). Выход – виртуальный хостинг. Изучив пару статей в Интернете, ты забиваешь конфигурации своих сайтов в httpd-vhosts.conf. И какое-то время даже радуешься этому. Проходит время и на локальном хосте у тебя уже не два с половиной сайта, а десятки проектов (пусть даже небольших). И, открывая в очередной раз httpd-vhosts.conf, чтобы добавить какую-нибудь опцию, ты начинаешь думать «А был ли мальчик?», действительно ли ты создавал этот сайт? Ведь в такой окрошке из проектов уже нелегко что-либо отыскать. А если еще учесть, что половина проектов взаимодействует с web-сервером при помощи модуля mod_python, а другая – при помощи модуля mod_wsgi, например, тогда вообще становится грустно работать. Да и жить тоже становится грустно (а уж как ваша собака то у дверей грустит).

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

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



    Итак, попробую описать то, что у меня есть, и что должно получиться в конце моего сольного выступления. На операционной системе FreeBSD 9.0 установлены Python 2.7, Django 1.3 и web-сервер Apache 2.2. В моем домашнем каталоге содержатся два django-проекта, готовые к употреблению. Дело за малым – необходимо выбрать и установить модуль для взаимодействия Apache и Django, а также настроить виртуальный хостинг для одновременного управления несколькими django-проектами. Вот мое дерево каталогов, полученное при помощи команды tree:


    Для развертывания Django на сервере необходима установка и настройка модуля, взаимодействующего с web-сервером. Таких модулей существует несколько. Какому отдать свое предпочтение – зависит от свойств и характеристик системы, опыта и психологических особенностей лица, осуществляющего выбор, степени его вменяемости, кривизны устройства /dev/hands, погоды на улице и т.д. Проще говоря, дело вкуса. Уверен, что у каждого найдется масса доводов в поддержку своего любимого модуля. Не буду спорить, так как не хотелось бы выслушивать их все. Приведу лишь настройку тех модулей, с которыми мне приходилось взаимодействовать.

    Сразу хочу заметить, что я действую от лица суперпользователя, поэтому в моих листингах отсутствуют команды типа su или sudo. Прошу не забывать про эти волшебные слова тех, кто настраивает систему под аккаунтом менее привилегированного пользователя.
    Итак, поехали!

    MOD_PYTHON


    Web-сервер Apache c модулем mod_python исторически всегда считался основной рабочей средой для Django (именно эту комбинацию использовали создатели платформы Django в качестве основы своих высоко нагруженных новостных сайтов). Этот модуль реализует интерпретатор языка Python внутри web-сервера и загружает написанный на Python код в момент запуска сервера. Код остается в памяти все время, пока процесс Apache работает. Такая связка Apache+mod_python и по сей день представляет собой хорошо протестированный и хорошо документированный вариант развертывания. Но, данный модуль уже морально устарел, и его поддержка будет удалена в Django 1.5. Поэтому, на официальном сайте Django настоятельно рекомендуют при развертывании нового проекта рассмотреть вопрос об использовании модуля mod_wsgi (тему которого мы затронем чуть ниже в этой статье).

    Итак, mod_python. Сам модуль есть в портах, поэтому установим его оттуда:
    # cd /usr/ports/www/mod_python3
    # make install clean
    

    После установки модуль добавляет свои параметры настройки в конфигурационный файл Apache — httpd.conf. Если вы используете систему управления версиями для сохранения файла httpd.conf (как и должно быть «в нормальной семье»), значит, перед установкой порта не забудьте захватить файл.
    Далее открываем для редактирования вышеупомянутый httpd.conf (лично я пользуюсь редактором ee, но вы можете использовать и что-нибудь в корне другое, типа vi):
    # ee /usr/local/etc/apache22/httpd.conf

    Необходимо проверить наличие в этом файле следующих строк:
    1. LoadModule python_module libexec/apache22/mod_python.so

      (загрузка модуля mod_python. Это та строка, которая должна была добавиться в файл автоматически на предыдущем шаге.)
    2. User www
      Group www

      (запуск сервера от лица непривилегированного пользователя. Хотя иногда встречаются рекомендации запускать Apache от имени root, не стоит поступать так. Если злоумышленник взломает ваш web-сервер, в качестве дополнительной награды он получит права root в вашей системе!)
    3. ServerName localhost

      (имя web-сайта. Оно должно представлять собой реальное имя хоста и иметь соответствующую запись в DNS. Однако во время тестирования вместо записи DNS можно применять запись в /etc/hosts. Собственно говоря, так мы и поступим. Поэтому в ServerName я указал localhost. При тестировании на локальном хосте можно вообще не добавлять эту строку, но тогда web-сервер при каждом перезапуске будет подозрительно фыркать в вашу сторону.)

    Сразу же, чтобы не забыть, я добавлю запись в /etc/hosts (это имена моих сайтов):
    127.0.0.1	gallery.ru museum.ru


    Теперь настроим виртуальный хостинг. В случае виртуального хостинга несколько имен хостов относятся к одной и той же машине. Сервер должен различать запросы к различным доменам, а затем предоставлять соответствующие страницы. Чтобы включить функцию обслуживания виртуальных хостов, можно раскомментировать строку Include etc/apache22/extra/httpd vhosts.conf в файле httpd.conf и писать конфигурации всех наших сайтов в один файл httpd-vhosts.conf (о чем рассказывалось выше). Но, поскольку единственный сервер Apache в состоянии обслуживать довольно приличное количество виртуальных хостов, то намного удобнее хранить конфигурацию каждого такого хоста в отдельном файле в каталоге Includes (/usr/local/etc/apache22/Includes). Если имя файла, содержащегося в этом каталоге, имеет расширение .conf, тогда Apache автоматически подключает конфигурацию из этого файла при последующих перезагрузках. Кроме того, чтобы не потеряться во множестве файлов, мы будем присваивать им имена, содержащие имена доменов, которые они будут обслуживать.
    Итак, в конец файла httpd.conf добавим следующие инструкции:
    Include etc/apache22/ Includes/*.conf
    NameVirtualHost *
    

    Затем в папке Includes создадим файлы с названиями наших будущих сайтов:
    # cd /usr/local/etc/apache22/Includes
    # touch gallery.ru.conf
    # touch museum.ru.conf
    

    Все что нам осталось теперь, это внести конфигурационные настройки во вновь созданные файлы. Приведу листинг только файла gallery.ru.conf:

    <VirtualHost *>
        ServerName gallery.ru
        ServerAlias www.gallery.ru
        ServerAdmin test@test.ru
        DocumentRoot /home/valera/djcode/gallery
        <Location "/">
            SetHandler python-program
            PythonHandler django.core.handlers.modpython
            SetEnv DJANGO_SETTINGS_MODULE gallery.settings
            PythonDebug On
            PythonPath "['/home/valera/djcode'] + sys.path"
        </Location>
    
        <Location "/media/">
            SetHandler None
        </Location>
    </VirtualHost>
    
    <Directory /home/valera/djcode/gallery>
        Order allow,deny
        Allow from 127.0.
    </Directory>
    


    Аналогичным образом заполняется файл museum.ru.conf и все последующие конфигурации ваших сайтов. В проекте museum.ru я не использую изображения, поэтому следующие строки в его конфиг не включаются:
        <Location "/media/">
            SetHandler None
        </Location>
    

    Вот собственно и все дела. Единственное, что хотелось бы напомнить, что у web-сервера должен быть доступ на запись к каталогу, в котором содержатся файлы изображений, js-скрипты и прочее (в моем случае это папка media). Для этого в каталоге, содержащем папку media, выполним следующие инструкции:
    # chgrp www media
    # chmod g+w media
    

    Перезапускаем сервер:
    # /usr/local/etc/rc.d/apache22 restart

    Вводим в строке браузера имя нашего сайта (в моем случае gallery.ru или museum.ru) и радуемся за не напрасно потраченное время!

    MOD_WSGI


    Позиционируется как замена mod_python. Главным достоинством модуля является низкое потребление памяти и высокая производительность по сравнению с mod_python, а также возможность работы в режиме демона.
    Теперь поступим немного проще. Я не буду объяснять, почему в конкретном случае я поступаю так, а не иначе (все ответы можно найти в описании предыдущего модуля), а просто приведу порядок действий и необходимые команды.
    Установим модуль из портов:
    # cd /usr/ports/www/mod_wsgi3
    # make install clean

    Открываем для редактирования httpd.conf:
    # ee /usr/local/etc/apache22/httpd.conf

    Проверяем наличие в этом файле следующих строк:
    1. LoadModule wsgi_module libexec/apache22/mod_wsgi.so

      (загрузка модуля mod_wsgi. Эта строка должна появиться автоматически при установке модуля из портов.)
    2. User www
      Group www
      

      (запуск сервера от лица непривилегированного пользователя)
    3. ServerName localhost

      (имя web-сайта)

    Итак, в конец файла httpd.conf добавим следующие инструкции:
    Include etc/apache22/ Includes/*.conf
    NameVirtualHost *

    Запись в файле /etc/hosts один в один, как и для предыдущего модуля. То есть, в моем случае:
    127.0.0.1	gallery.ru museum.ru


    Далее в папке Includes создадим файлы с названиями наших будущих сайтов:
    # cd /usr/local/etc/apache22/Includes
    # touch gallery.ru.conf
    # touch museum.ru.conf
    

    Теперь внесем конфигурационные настройки во вновь созданные файлы. Приведу листинг только файла gallery.ru.conf:

    <VirtualHost *>
        ServerName gallery.ru
        ServerAlias www.gallery.ru
        ServerAdmin test@test.ru
        WSGIScriptAlias / /home/valera/djcode/gallery/mod.wsgi
        Alias /media/ /home/valera/djcode/gallery/media/
    </VirtualHost>
    
    <Directory /home/valera/djcode/gallery>
        Order allow,deny
        Allow from 127.0.
    </Directory>
    


    Аналогичным образом заполняется файл museum.ru.conf и все последующие конфигурации ваших сайтов. В проекте museum.ru я не использую изображения, поэтому следующая строка в его конфиг не включаются:
        Alias /media/ /home/valera/djcode/gallery/media/
    

    Осталось только создать упомянутый в листинге файл mod.wsgi:
    # cd /home/valera/djcode/gallery
    # touch mod.wsgi
    

    Вот его содержимое:
    import os, sys
    sys.path.append('/home/valera/djcode')
    os.environ['DJANGO_SETTINGS_MODULE'] = 'gallery.settings'
    import django.core.handlers.wsgi
    application = django.core.handlers.wsgi.WSGIHandler()
    


    Сделаем каталог media доступным для записи:
    # chgrp www media
    # chmod g+w media
    

    Перезапускаем сервер:
    # /usr/local/etc/rc.d/apache22 restart

    Вводим в строке браузера имя нашего сайта (в моем случае gallery.ru и museum.ru) и опять-таки радуемся!


    LAST ONE



    В итоге мы получаем кучу конфигурационных файлов, отвечающих за наши сайты, в одной единственной папке. При этом все конфиги разбиты по именам, и каждый содержит в себе в среднем не более 30 строк кода. По сравнению с монолитной конфигурацией, когда все параметры настройки сосредоточены в одном файле, такой подход позволяет упростить поиск неполадок на сайте.
    Если вам необходимо, чтобы разные сайты взаимодействовали с сервером через разные модули, то вы можете настраивать каждый конфиг тем способом, из приведенных выше, который вам необходим. Главное убедитесь, что загрузка обоих модулей присутствует в файле httpd.conf:
    LoadModule python_module libexec/apache22/mod_python.so
    LoadModule wsgi_module libexec/apache22/mod_wsgi.so
    

    Если же вы, как и я, храните все проекты в одном каталоге, то, для создания нового конфига, достаточно поступить следующим образом. Найти конфиг, схожий с тем, который вам предстоит создать. Скопировать его, изменив при этом имя файла. И заменить все, присутствующие в нем, названия старого сайта на названия нового. То есть:
    # cp old_site.ru.conf new_site.ru.conf
    # sed –i –e ‘s/old_site/new_site/g’ new_site.ru.conf
    

    В итоге, добавление нового сайта в конфигурацию web-сервера занимает ровно столько времени, сколько необходимо для набора на клавиатуре двух вышеперечисленных команд и перезагрузки сервера (в случае использования модуля mod_wsgi еще добавляется копирование файла mod.wsgi).

    На этом вроде бы закончил. Хорошего вам дня!



    Книги, повлиявшие на ход мыслей в данной статье:
    Share post

    Similar posts

    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 25

      +12
      Надеюсь мне простится мой комментарий.

      Мы используем nginx / uWSGI / Django / VirtualEnv. Таким образом мы избавляемся от громоздкого Apache, и получаем свободу для нескольких проектов в рамках одной системы.

      Спасибо за топик, Вы подали идею рассказать о нашей реализации хостинга Python/Django-проектов.
        +6
        Да, я в курсе, что Ваше сочетание удобнее предложенного. Скажу даже больше — Ваш подход практичнее для создания высоко нагруженных проектов (если еще добавить memcached). Но в данном случае я описал конфигурацию с Apache. Возможно, тем, кто пользуется этим web-сервером приведенная информация будет полезна. Знания лишними не бывают. :)

        И кстати, с удовольствием прочитал бы про Вашу реализацию! Буду ждать топика!
          0
          У нас аналогично.
            +1
            с вас значит тоже топик :-)
            0
            О! напиши, плиз. я наверное тоже напишу про эту связку.
            будет шанс сравнить и взять лучшее
          +5
          Убивать за упоминание mod_python, он уже давным давно не развивается, труп и deprecated.
          А так, очередная статья как поднять простое
            –1
            про mod_python — согласен.
            А вот про «поднять простое» — нет.
            когда только начинаешь — очень не хватает толковой статьи как это _правильно_ сделать. И ответов на вопрос «а как это вообще бывает» тоже.
              0
              Благодарю за поддержку! :)
                0
                да ладно, даже в оф доке есть инструкци docs.djangoproject.com/en/1.3/howto/deployment/modwsgi/
                А сколько их в рунете ууу
                  0
                  То есть мне писать не стоит?
                    0
                    пиши, пиши…
                    обмен опытом всегда полезен. Часто бывает ценна даже не сама статья, а те идеи, которые там проскакивают намеком.
                      0
                      Писать стоит! В официальной документации слишком сухой язык. Не хватает реальных примеров.
                      0
                      да ладно, даже в оф доке есть инструкци

                      да, есть.
                      Но врагу не пожелал бы следовать им.
                      как и держать в штатном месте (/var/www и аналогичном) что либо отличное от тестового сайта на локалхосте. С чьими правами оно там будет исполняться?
                    +1
                    По поводу mod_python я в статье предупредил сразу, что он устарел. Поэтому не нахожу смысла в цитировании меня же в комментариях к моей статье. Но дело, конечно, Ваше!
                      +1
                      Так зачем же было про него вообще писать, раз он устаревший и вы всё равно пишете про нормальный вариант? )
                        0
                        Ну, я привел два варианта просто для сравнения, захватив при этом кусочек истории (в виде mod_python). Так как FastCGI меня не прельщает, а uWSGI я еще не успел опробовать, поэтому описал приведенные модули. Может кому и пригодится — у людей разные капризы бывают. А как сказал Доктор Шелдон Купер: «Ну, жизнь без капризов — это не жизнь!» )
                    0
                    Ваше решение имеет очень серьезные недостатки.

                    По моему, так те, кто серверную папку ставят в /home, недалеко ушли от тех, кто в Windows все валят в корень c:. А как это папку потом вынести на сетевое хранилище? Как обеспечить доступ других пользователей?

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

                    Плюс, в вашей схеме надо руками создавать конфиг для каждого сайта. Не надоест? А если все 100 конфигов надо будет обновить? Вот, в нгинксе, например можно как-то регуляркой все эти хосты описать. (в апаче тоже есть nameVirtualHost, но он 100% неюзабелен).

                      0
                      Плюс, в вашей схеме надо руками создавать конфиг для каждого сайта.

                      Нет, если конфиг создается через вэб-морду при регистрации проекта на профиль.
                        0
                        Тогда надо дать серверу права на запись в /etc, что небезопасно. Проблема массового обновления конфигов тоже остается.
                        0
                        По моему, так те, кто серверную папку ставят в /home, недалеко ушли от тех, кто в Windows все валят в корень c:
                        Апач под FreeBSD по умолчанию держит сайты в /usr/local/www, чем автору не понравился этот путь — непонятно. Мы (занимаясь хостингом) оставляем сайты именно там — просто домашние каталоги пользователей, размещающих у нас сайты, находятся, например, в /usr/local/www/data/SiteName. Плюс к этому, /usr/local/www, как правило — или отдельная файловая система, или вообще отдельный физический диск.
                          0
                          Я в статье забыл озвучить, что данный вариант приведен для тестового локального хоста (извиняюсь перед всеми). Поэтому о хостнге на настоящей рабочей станции здесь и не может идти речи.
                          Раздел /home у меня физически на отдельном жестком диске, потому и складываю туда все наработки. Я не думаю, что это критично, ведь я в любой момент могу все перенести в тот же /usr/local/www, а все конфиги проекта поправить чем-то вроде:
                          grep home/valera ./* | sed -i -e 's/home\/valera/usr\/local\/www/g' *
                          Или я не прав?
                          0
                          Перезапускаем сервер:
                          /usr/local/etc/rc.d/apache22 restart
                          А зачем так? Есть же apachectl — он есть и для 1.3, и для 2.2, сидит в /usr/local/sbin, то есть по пути, упоминающемуся в $PATH у рута. Я для перезапуска апача просто пишу apachectl restart — этого вполне достаточно.
                            0
                            Не буду умничать, а приведу цитату из книги Майкла Лукаса, отмеченной у меня в списке литературы: «Хотя утилита apachectl(8) работает очень неплохо, рекомендую применять сценарий запуска, интегрированный в операционную систему FreeBSD. Этот сценарий запускает apachectl(8) с особыми настройками, необходимыми именно в вашем случае, и гарантирует, что при следующей загрузке системы сервер Apache будет работать точно так же, как до ее останова».
                            Ну, а на самом деле, я просто привык так поступать. Хотя, когда сильно тороплюсь, делаю как Вы.

                          Only users with full accounts can post comments. Log in, please.