1 июня 2011 в 15:33

Настройка сервера для django-проектов с нуля

Хочу поделиться опытом настройки сервера для django-проектов. Так вышло, что мне часто приходится настраивать с нуля VPS-сервера для запуска на них django-сайтов. Как-то мне в голову пришла идея записать пошагово процесс настройки. Оказалось, что “по бумажке” выполнять эти рутинные операции гораздо проще и быстрее — все нюансы записаны, трудно что-то упустить. Дальше больше — я превратил инструкцию в самостоятельный shell-скрипт — запустил и сервер готов. Я думаю, некоторым python-разработчикам, особенно начинающим, будет полезно ознакомиться с содержимым скрипта. С некоторыми доработками вы, возможно, захотите использовать его в своей практике.

Итак, допустим вы только что купили VPS-сервер и поставили туда стабильный релиз Debian. Перво-наперво, вы копируете свой RSA ключ на сервер:

ssh-copy-id root@server

Теперь заходим на сервер, скачиваем скрипт и запускаем его:

wget -O ~/install.sh dumpz.org/57292/nixtext/
sh ~/install.sh

Всё :) Если вы запустили скрипт, в том виде, как написал его я, то теперь у вас установлен nginx, postgres, supervisor, uwsgi; создан пользователь web, который может работать с postgres; установлены все популярные DVCS; установлены различные python-библиотеки и сделана ещё куча мелочей. Вам остаётся лишь склонировать ваш проект в директорию /web/project_name, далее настроить конфиг nginx для вашего сайта (создан шаблон в sites-enabled), прописать пару строчек в конфиг supervisor’а и запустить сайт.

Мои джанго проекты обычно также настраиваются одним скриптом, который создаёт virtualenv, устанавливает зависимости в него, создаёт базу данных, делает syncdb, выполняет миграции, создаёт начальные данные — но это уже тема для другой статьи.

В итоге, запуск django-сайта на голом сервере превращается из рутины в быструю и почти безболезненную процедуру (ну, всё равно, какие-нить баги же вылезут).

Актуальная версия скрипта лежит здесь: dumpz.org/57292/

Я решил также выложить текст скрипта здесь с подробными комментариями на русском языке.

#!/bin/sh

# Скачиваем конфиг vim - это мой редактор в котором
# я делаю всё: пишу код сайтов, работаю на сервере через ssh
# оформля в данный момент комментарии скрипта для habrahabr
wget -O ~/.vimrc http://dumpz.org/25712/nixtext/

# Делаем vim редактором по-умолчанию
# Теперь если я запущу, например, crontab, я не буду шокирован
# Вываливишмся на меня nano
update-alternatives --set editor /usr/bin/vim.basic

# Теперь устанавливаем netselect-apt пакет.
# Он содержит программу для поиска самого быстрого
# репозитория с debian пакетами
apt-get install netselect-apt -y
rm /tmp/sources.list
netselect-apt -o /tmp/sources.list -n stable

# Найденный репозиторий был записан в /tmp/sources.list
# Используем имя сервера из него и создаём три
# записи: мы будем использовать по мере надобности все три
# ветки debian-репозитория: стабильную, тестовую и нестабильную
# Нестабильной (sid) я пользуюсь затем, что в ней лежит nginx-пакет
# Поддерживающий из коробки uwsgi
echo "deb http://security.debian.org/ squeeze/updates main contrib non-free" > /etc/apt/sources.list
LINE=$(cat /tmp/sources.list | grep '^deb' | head -1)
echo $LINE /etc/apt/sources.list >> /etc/apt/sources.list
echo $LINE | sed 's/stable/testing/' >> /etc/apt/sources.list
echo $LINE | sed 's/stable/sid/' >> /etc/apt/sources.list

# По-умолчанию, будем использовать пакеты из стабильной ветки
# Запрещаем установку, по-умолчанию, дополнительных пакетов
cat > /etc/apt/apt.conf.d/07custom << EOF
APT::Install-Recommends "false";
APT::Default-Release "stable";
EOF


# Получим актуальную информацию о пакетах в репозитории
# ветки которого мы только что добавили в sources.list
aptitude update

# Теперь настроим локали: en_US будет локалью по-умолчанию.
# Кроме неё сгенерируем также ru_RU локаль
aptitude install locales -y
echo en_US.UTF-8 > /etc/default/locale
cat > /etc/locale.gen << EOF
en_US.UTF-8 UTF-8
ru_RU.UTF-8 UTF-8
EOF

locale-gen

# Теперь обновим все установленные пакеты
# Т.е. те пакеты, что были системе на момент нашей работы с ней
aptitude upgrade -y

# Поставим пару ништяков
# Пакет psmisc предоставляет утилиту pkill
# screen и sudo и так понятно
aptitude install psmisc screen sudo -y

# Поставим exim4, чтобы можно было почту слать
# Я пока не разбирался, как его настроить из скрипта
# Придётся вам потом ручками запустить dpkg-reconfigure
aptitude install exim4 -y
#dpkg-reconfigure exim4-config

# Ставим nginx из sid ветки, там он умеет uwsgi
# Делаем автозапуск ngin при загрузке системы
# Запускаем веб-сервер
aptitude install nginx -t sid -y
update-rc.d nginx defaults
/etc/init.d/nginx start

# Создаём пользоателя web
# Из-под него я работаю со всеми моими django-проектами
# Копируем ему RSA ключ, чтобы можно было под ним по ssh заходить
# Копируем ему vim конфиг
useradd -m web -s /bin/bash
cp ~/.vimrc /home/web
mkdir /home/web/.ssh
cp ~/.ssh/authorized_keys /home/web/.ssh
chown -R web:web /home/web

# Создаём директорию /web, там я обычно размещаю джанго-проекты
mkdir /web /web/run /web/log
chown -R web:web /web

# Ставим все популярные системы контроля версия
aptitude install mercurial subversion git-core -y

# Я использую для своих проектов mercurial
# Поэтому настраиваю его для работы на сервере
# Иногда я делаю коммиты прямо с сервера
cat > /home/web/.hgrc << EOF
[ui]
username = Name Name 
EOF

chown web:web /home/web/.hgrc

# Ставим python :)
# python-dev - исходный код python, чтобы можно было
# ставить python-библиотеки, которым нужна компиляция из C кода
# python-setuptools содержит скрипт easy_install
aptitude install python python-setuptools python-dev -y

# Поставим последние версии pip и virtualenv
easy_install -U pip
easy_install -U virtualenv

# gcc нужен для компиляции всяческго python-добра
aptitude install gcc -y

# Ставим python-библиотеку для работы с lxml
# Предпочитаю ставить её в бинарном виде,
# чтобы не ждать окончания длинного процесса компиляции
aptitude install python-lxml -y

# Fabric ставим - очень поленая вещь
pip install -U fabric

# Ставим PIL
# Не забываем о некоторых зависимостях, иначе после компиляции
# может получиться, что ваш PIL не умеет работать с JPEG :)
aptitude install libjpeg62-dev libfreetype6-dev -y
pip install -U PIL

# Ну вот и до uwsgi добрались
# Ставим нужную зависимость и компилируем последнюю версию
aptitude install libxml2-dev -y
pip install -U http://projects.unbit.it/downloads/uwsgi-latest.tar.gz

# Я обычно пользуюсь postgres
# Просто настраиваю его так, чтобы из-под пользователя web
# Можно было делать что угодно
aptitude install postgresql python-psycopg2 -y
su postgres -c "cd /; createuser -s web"

# Супервизор будет управлять нашими uwsgi-демонами
# С помощью него мы будем перезапускать наши сайты
# Также он должен запустить сайт, если его процесс "вдруг" умер
aptitude install supervisor -y

# Это конфиг для управления через веб, нужно вписать ваш пароль и имя пользователя
cat > /etc/supervisor/conf.d/inet.conf << EOF
[inet_http_server]]
port=666
#username=
#password=
EOF


# Это шаблон для одного джанго сайта,
# Как видите описание django-процесса в supervisor-конфиге минимально
# Мы лишь указываем рабочую директорию и команду для запуска
# Сайт запускается uwsgi командой, все настройки uwsgi хранятся в uwsgi.xml
# файле в директории сайта
cat > /etc/supervisor/conf.d/web.conf << EOF
#[program:PROJECT]
#directory=/web/PROJECT
#command=uwsgi -x uwsgi.xml
#user=web
EOF


# Перезапустим supervisor, хотя пока особого смысла в этом нет
/etc/init.d/supervisor restop

# Эта строчка нужна, чтобы пользователь web мог запускать команду
# supervisorctl через sudo
# По-умолчанию, она может быть выполнена только рутом
echo "web    ALL = NOPASSWD: /usr/bin/supervisorctl" >> /etc/sudoers

# А это шаблончик сайта для nginx
# Для нового сайта просто копируем его
# и в VIM заменяем HOST и PROJECT на нужные значения

cat > /etc/nginx/sites-enabled/template << EOF
server {
    server_name .HOST.com;

    error_log /web/log/HOST.com-error.log warn;
    access_log /web/log/HOST.com-access.log;

    location /static/admin-media {
        alias /web/PROJECT/var/.env/lib/python2.6/site-packages/django/contrib/admin/media;
    }   

    location /static/ {
        root /web/PROJECT;
    }   

    location /robots.txt {
        root /web/PROJECT/static;
    }   

    location /favicon.ico {
        root /web/PROJECT/static;
    }   

    location / { 
        include uwsgi_params;
        uwsgi_pass unix:/web/run/PROJECT.sock;
    }   
}
EOF



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

UPDATE: Это не решение для деплоинга, хотя кое-какие намёки там есть. Это просто скрипт, который ставит и конфигуряет нужный софт для комфортной работы с django-проектами.

UPDATE2: Создал проект на битбакете: bitbucket.org/lorien/django-server Форкайте на здоровье.
+89
10101
295
itforge 32,5

Комментарии (56)

+2
offline15, #
Неплохо, а нельзя имя проекта в переменную записать и вызывать скрипт с именем проекта, тогда и редактировать не надо будет вообще…
+1
itforge, #
Не, это уже другой скрипт, цель же скрипта, описанного в публикации, настроить инфраструктуру для джанго-проектов, так сказать. Он создаёт шаблоны конфигов сайта для nginx, для supervisor. При желании можно отдельным скриптом, эти шаблоны использовать для создания нового сайта.

Про скрипт, который конфигуряет новый сайт я уже думал, но пока как-то проще ручками создавать новые сайты т.е. действий там не слишком много.
0
vitroot, #
нехило… спасибо, пригодится
+3
xa4a, #
Хорошо, что дял этого придумали puppet
0
itforge, #
Если ничего не путаю, я недавно пытался понять эту штуку — ничо не понял и забил :) Как он вообще работает, в двух словах?
+1
mecommayou, #
Есть клиент и сервер. Клиенты — твой ботнет, сервер — командный центр.
+1
xa4a, #
Как почти любая тулза для деплоймента. Пишете декларативный конфиг, в котором описано, что хотите получить, типа «установленные пакеты такие-то, созданные юзеры такие-то, распиханые конфиги туда-то».
Заливаете на нужные тачки, запускаете puppet, он пытается привести систему к описанному состоянию. При изменении конфига — puppet переконфигурирует, что нужно для достижения нового состояния. как-то так.
+1
itforge, #
Я не очень понимаю, чем puppet лучше моего решения. Моя специфика в том, что я работаю лишь с одной машиной и мне не нужно поддерживать её состояние в будущем, один раз только настроить. Потом каждая машина живёт своей жизнью. Например, потом мне надоест uwsgi и я решу поиграться с чем-то ещё, на навых машинах-проектах будет эта новая штука, а на старых uwsgi (по принципу работает — не трогай).

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

Честно говоря, я не очень понимаю, чем конфиг puppet будет отличаться от моего скрипта, точно так же надо ему сказать, чтобы поставил то через aptitude, то через pip. В результате будет мой срикпт, только завёрнутый ещё в один слой. Ещё раз повторяю, специфика в том, что мне не нужно поддерживать конфигурацию на нескольких машинах в соотвествии с некоторым стандартом, мне вообще не нужно работать с несколькими машинами единовременно. Вы всё ещё думаете, что puppet был бы лучше в моём случае?
0
xa4a, #
Согласен, puppet удобен для поддержания одинаковой конфигурации на нескольких серверах.
Для этой цели, думаю, он подходит лучше большинства самописных велосипедов.
0
homm, #
Если вы запустили скрипт, в том виде, как написал его я, то теперь у вас установлен nginx, postgres, supervisor, uwsgi, postgres.
postgres забыли :)
0
itforge, #
fixed
0
mecommayou, #
А не было идеи реализовать тоже самое используя Puppet?
0
itforge, #
Была идея, но я не осилил puppet, я чуть выше написал мысли по поводу фреймворков для деплоинга.
0
axunax, #
И откуда у всех «aptitude» в системе? Написали бы dependencies для своего скрипта.
Статья о том, как делать не нужно.
+2
itforge, #
Не нравится — не используйте. Я делюсь тем, что использую в данный момент. Если вам нравится подход, то замените aptitude на ваш пакетный менеджер. Если не нравится, то тогда вообще не понял, о чём вы говорите.

Статья не о том, как нужно или не нужно делать, статья о том, как делаю я :)
+1
VolCh, #
НапИшите статью как делать нужно?
+2
idle, #
А расскажите, что вы делаете фабриком на сервере?
0
Frenzy, #
тонкий намёк :)
0
itforge, #
Я попозже напишу публикацию, как использую fabric/virtualenv/pip для деплоинга джанго-проектов.
+1
idle, #
Вы их с сервера деплоите разве? Если нет, то на сервере фабрик не нужен %)
0
itforge, #
Ну, вообще я немножко извратился и делаю через фабрик всякие штуки локальные в основном :)
Вот пример из одного моего проекта: dumpz.org/57395/
Я fabric пока только-только изучаю, поэтому деплоинг у меня так-себе.
+1
klen, #
А я вот своим велосипедом пользуюсь. Умеет он гораздо больше, но расписывать здесь лень.

github.com/klen/makesite
0
VolCh, #
Поправьте, но мне показалось, что ваш скрипт не установит nginx, БД, python, pip и т. п. То есть он должен работать после того как отработает сабж топика.
0
klen, #
Поправляю, скрипт установит (если нужно) nginx, pip, uwsgi, memcached. БД не установит, но создаст при необходимости пользователей и базы. В любом случае необходимая функциональность при желании дописывается в шаблоны.
0
Deepwalker, #
Вообще по-правильному надо бы пользоваться fabric. Но вот полноценных готовых не встречал.
Есть bitbucket.org/kmike/django-fab-deploy, но мне он категорически не нравится, в каждой мелочи.
0
itforge, #
Как именно воспользоваться fabric? Если просто запустить всё через fabric.api.run, то не вижу большой разницы :) Я ещё раз хочу подчеркнуть, этот скрипт не инструмент деплоинга джанго-сайтов, это базовая настройка VPS. Вообще я фабрик изучаю только первый месяц, но он мне сильно понравился.
+1
kmike, #
а что особенно не нравится?

мне там тоже много что не нравится, но сайты не каждый день разворачиваешь
0
Deepwalker, #
Ну я пока им пытался сайт развернуть, меня многое раздражало :)
С ходу — мне не нравится --no-site-packages у virtualenv. То есть опцию врубили, а потом в wsgi скрипте зацепляем и virtualenv, и site packages. Зато в немодифицированном manage.py у вас появляется проблема с доступом к системному MySQLdb при активированном окружении.
Я может конечно не очень глубоко вник, мне собственно надо было сервер запускать, может и упустил что.
0
kmike, #
wsgi — из вики к mod_wsgi взят, возможно, слишком давно (Graham где-то обновленный супер-правильный wsgi-скрипт для джанги выкладывал).

Но в wsgi-файле системный site-packages не специально зацепляется. Зацепляются как раз папки из virtualenv'а, и помещаются выше всего того, что в sys.path раньше было (а там был системный site-packages), т.к. процесс-то веб-сервера стартует без активированного virtualenv'а. Это как раз такой специальный wsgi-файл с поддержкой виртуаленвов без --no-site-packages ;) Угу, странно получилось. Т.е. ошибка тут не в том, что manage.py на mysqldb ругнулся, когда mysqldb не установлен, а в том, что wsgi не ругнулся, даже если --no-site-packages у виртуаленва стоит.

У меня обычно и локально, и на сервере везде --no-site-packages, и ставится все из одних и тех же файлов с зависимостями (+ доп. файлик для того, что только для разработки нужно), поэтому без установленного mysqldb все и локально падает (а упало — добавляю в зависимости просто нужный пакет) => обнаружить эту ошибку мог только чудом)

Интересный баг, добавил в трекер.

С --no-site-packages минус в том, что долго бывает, это да. Как раз из-за этого по умолчанию файлы с зависимостями на несколько предлагается разбить там, и часть обновлять более-менее регулярно и удобно, а часть (со всякими PIL и mysqldb) использовать только при первичной установке.

Насчет раздражителей — там за последнее время разные штуки еще поменялись как раз чтоб раздражать поменьше (работа через sudo без root'а — где можно, произвольная структура папок в проекте, зависимости одним файлом можно, пользователь БД — не root, немного мусора из push выкинуто и из других мест), может ощущения получше будут у людей, которые сейчас пробуют.
0
Deepwalker, #
Я кстати так и не понял, зачем --no-site-packages? С этой опцией мы теряем пакетную базу дистрибутива, а бонусов не получаем. То есть в каких то случаях это может быть и нужно, при особом сочетании пакетов для редкого проекта, но в остальном только мешает. Приходится на продакт сервер ставить gcc и остальную плеяду бесполезных там штук, типа всяких *-dev.

Кстати что нравится, так это пуш — не люблю когда на сервер пуллят из центрального репо — тогда всем серверам к нему надо доступ давать.
+1
kmike, #
Бонус с --no-site-packages в том, что всегда понятно, какое у проекта окружение, и будет явно выводиться ошибка, если чего-то нет (а не использоваться, например, устаревшая версия из репозитория — что вполне актуально для lenny может быть). Системные пакеты с заголовками все равно для многих полупитоньих пакетов нужны, а плеяду бесполезных штук django-fab-deploy ставит в самом начале.

Я не то чтобы уж очень за --no-site-packages, но на практике из минусов только установку долгую замечал — зато меньше неявных проблем, когда у одного разработчика работает, у другого не работает, на сервере работает, но со скрытой ошибкой и тд. Когда все зависимости явно прописаны (например, не python-beautifulsoup, который 3.0 в lenny, жуткий 3.1 в squeeze и непонятно какой ставить локально и откуда узнать, что его вообще ставить нужно, а BeautifulSoup==3.2), такое бывает реже.

Практических проблем вроде не так много ни с тем, ни с другим вариантом, думаю, вопрос больше идеологический — мне как-то проще, когда точно знаю, какое питонье окружение у проекта, и это явно где-то записано (не надо, например, аналоги дебиановских пакетов искать в macports или pypi).
0
xRemaLx, #
Спасибо. Давно хочу попробовать django в действии.
+1
hardex, #
Тихо заменить пользователю дефолтный редактор? Отлииично…
Добро пожаловать в академию пакостей ;)
0
itforge, #
Какому пользователю? На сервере два пользователя: root и web. Оба из них это я :)
+2
hardex, #
update-alternatives --set editor /usr/bin/vim.basic
Далеко не все на этой планете могут управляться с этим чудом ;)
+1
itforge, #
Да, но я то могу, поэтому я ставлю для себя vim дефолтным редактором — больше на сервере пользователей нет :)
0
Bteam, #
Какой конфигурации vds нужен для небольшого django проекта?
0
HID, #
Ну если в конфигах основательно покопаться, то на 128 реально.
У меня было 400-500 в сутки на 128 mb.
Если не юзать SQLite и Apache и забить на фронтэнд (nginx) то думаю и на 64 жить можно.
0
HID, #
400-500 просмотров
0
obiwanus, #
> то на 128 реально

Зависит от технологии виртуализации. На XEN или KVM хватит, на OpenVZ либо не хватит, либо очень серьезно придется все поковырять.
0
HID, #
Ну вот у меня OpenVZ есть. Немного напрягает конечно что на OpenVZ своп использовать нельзя
+2
Zagrebelion, #
Обновите, пожалуйста, джангу до 1.3, познайте staticfiles и уберите вот этот ужас:

location /static/admin-media {
alias /web/PROJECT/var/.env/lib/python2.6/site-packages/django/contrib/admin/media;
}
0
itforge, #
Ок, вы меня заинтриговали. Джанго, конечно, 1.3 Просто не успеваю следить за всеми фичами т.к. и без них всё работает.
0
pr0fedt, #
а разве когда мы отдаем статику нджинксом напрямую, то не получаем прирост скорости?
0
kmike, #
Дело в другом — в 1.3 для отдачи статики админки специальных настроек не нужно, т.к. staticfiles соберет и ее тоже, поэтому дополнительное правило — лишнее.
0
cabeza, #
Если вам часто приходится настраивать именно VPS, то проще сделать шаблон со своими изменениями (если, конечно, есть возможность разворачивать контейнеры из своего шаблона)
+1
Dimus, #
Хороший скрипт, спасибо. При следующей настройке наверное использую его как основу для своего.
У меня сейчас 2 сервера настроены схожим образом. Из всего что я пробовал связка Nginx+uWSGI + следящий supervisor мне больше всех пришлась по душе.

И еще, забавная опечатка:
/etc/init.d/supervisor restop
restop, что-то есть в этой команде ))
0
rukeba, #
Большое спасибо, очень полезно!
+1
nolled, #
Интересно, спасибо! Мне кажется такое лучше выкатить на github/bitbucket чтоб люди могли форкать спокойно на здоровье и апдейтить по мере необходимости
+1
itforge, #
0
klierik, #
Спасибо за топик. Как раз искал.
Будет о чём почитать на досуге!
0
dwow, #
после выполнения команды
/etc/init.d/supervisor stop
у вас все подпроцессы uwsgi киляются?
0
itforge, #
Не знаю, я уже несколько месяцев как перешёл на голый uwsgi :) Т.е. у меня только nginx + uwsgi-демоно в imperor mode, supervisor я выкинул.
0
dwow, #
почему перешли? вариант существенно выигрывает по производительности?
0
itforge, #
Просто эксперементирую. К тому же у меня были глюки с supervisor, какие-то процессы лишние в памяти оставались. Я подумал, чем разбираться, что к чему, выкину его вообще, ибо uwsgi и так работает отлично.
По поводу производительности, я думаю, одинаково, что с supervisor, что без — и там и там работает в итоге uwsgi-демон-сайта.
0
dwow, #
я как раз об этих процессах и говорил )
после перезагрузки мастера, в памяти оставались воркеры, и при этом кушали проц и память )

за ночь, кажется, нашел как лечится
no-orphans = true

в настройках uwsgi

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