Развертывание Django-проекта под nginx

    Преамбула


    Из нескольких способов развертывания Django я сразу отмёл mod_python, потому что мне не хотелось поднимать тяжеловесный Apache. Решил развернуть на легком веб-сервере. На данный момент основных легковесных альтернатив Апачу две — lighttpd и nginx. Первоначально я выбрал первый, но столкнулся с проблемами, связанными с URL. Я подумал, что, может, nginx будет работать получше, и развернул приложение на нём. В этом деле мне очень сильно помог один скринкаст, уже не помню точно чьего авторства.
    Всё было отлично, но когда я захотел использовать админку Django(удобная вещь, кстати), меня постигло разочарование — форма логина показывалась, но при попытке войти меня выбрасывало на admin. После получаса гугления, я нашёл топик на небезызвестном форуме Ивана Салагаева, в котором описывалось решение проблемы. После того, как я последовал описанным советам, все заработало на-ура. Представляю вашему вниманию необходимую конфигурацию сервера и Django.


    Конфигурация nginx


    Все пути указаны для моего дистрибутива(ArchLinux), у вас они могут отличаться:

    1. /etc/nginx/conf/fastcgi_params

    fastcgi_param PATH_INFO $fastcgi_script_name;
    fastcgi_param REQUEST_METHOD $request_method;
    fastcgi_param QUERY_STRING $query_string;
    fastcgi_param CONTENT_TYPE $content_type;
    fastcgi_param CONTENT_LENGTH $content_length;
    fastcgi_pass_header Authorization;
    fastcgi_intercept_errors off;

    fastcgi_param GATEWAY_INTERFACE CGI/1.1;
    fastcgi_param SERVER_SOFTWARE nginx;

    fastcgi_param REMOTE_ADDR $remote_addr;
    fastcgi_param REMOTE_PORT $remote_port;
    fastcgi_param SERVER_ADDR $server_addr;
    fastcgi_param SERVER_PORT $server_port;
    fastcgi_param SERVER_NAME $server_name;
    fastcgi_param SERVER_PROTOCOL $server_protocol;

    # PHP only, required if PHP was built with --enable-force-cgi-redirect
    fastcgi_param REDIRECT_STATUS 200;


    Насчёт последнего параметра в этом файле: необходим он или нет для Django, я не знаю, но исследований не проводил, работает и так.

    2. /etc/nginx/conf/nginx.conf

    user http;
    worker_processes 1;

    #error_log logs/error.log;
    #error_log logs/error.log notice;
    #error_log logs/error.log info;

    #pid logs/nginx.pid;

    events {
    worker_connections 1024;
    }

    http {
    include mime.types;
    default_type application/octet-stream;

    access_log logs/access.log main;

    sendfile on;
    #tcp_nopush on;

    #keepalive_timeout 0;
    keepalive_timeout 65;

    #gzip on;

    server {
    listen 80;
    server_name some.cool.server;

    charset utf-8;

    access_log logs/cool.access.log ;

    client_max_body_size 300m;

    location / {
    fastcgi_pass 127.0.0.1:8881; # эти параметры мы укажем потом и при запуске Django-fastcgi
    include fastcgi_params;
    }

    #error_page 404 /404.html;

    # redirect server error pages to the static page /50x.html
    #
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
    root html;
    }
    }
    }


    Всё, настройка nginx закончена.

    Настройка django



    Команда нужная для запуска сервера обычно выглядит примерно так:

    ./manage.py runfcgi method=prefork host=127.0.0.1 port=8881 pidfile=/tmp/server.pid

    Примечание: если у вас manage.py не сделан исполняемым, как у меня, вместо "./manage.py" надо использовать «python manage.py»

    method — prefork или threaded, рекомендуется prefork ввиду GIL, а также того, что в UNIX и POSIX-совместимых ОС создание процесса дешевле создания потока.

    host, port — хост и порт, на которых будет висеть FastCGI-сервер, параметры должны совпадать с теми, что были прописаны в конфиге nginx. Как по мне, использовать связь через порт лучше, чем через сокет, но это уже на ваше усмотрение

    pidfile — имя файла, куда будет записан PID сервера, для того, чтобы имели возможность потом его убить

    Вот и все, всё работает :) Для удобства я обычно создаю в корне проекта маленький файлик server.sh, который управляет FastCGI-сервером. Вот его содержимое:

    #!/bin/bash

    case "$1" in
    "start")
    ./manage.py runfcgi method=prefork host=127.0.0.1 port=8881 pidfile=/tmp/server.pid
    ;;
    "stop")
    kill -9 `cat /tmp/server.pid`
    ;;
    "restart")
    $0 stop
    sleep 1
    $0 start
    ;;
    *) echo "Usage: ./server.sh {start|stop|restart}";;
    esac


    Использование его и так, думаю, понятно, если нет — поясню:
    server.sh start — запускает сервер
    server.sh stop — останавливает сервер
    server.sh restart — перезапускает сервер

    P.S. Ну вот, первый пост на Хабре опубликован :)

    UPD: Перенёс в тематический блог
    Поделиться публикацией
    Похожие публикации
    Реклама помогает поддерживать и развивать наши сервисы

    Подробнее
    Реклама
    Комментарии 16
    • 0
      Есть предположение, что вместо портов лучше использовать сокеты.
      • 0
        извиняюсь, в тексте уже это указано :(
      • +4
        Под FreeBSD:

        /usr/local/etc/rc.d/XXX

        #!/bin/sh
        #
        # PROVIDE: XXX
        # REQUIRE: LOGIN cleanvar mysql

        . /etc/rc.subr

        name=«XXX»
        rcvar=`set_rcvar`
        socket="/var/run/www/${name}.sock" # путь к сокету
        pidfile="/var/run/www/${name}.pid" # путь к pid файлу
        procname="/usr/local/bin/python" # путь к интерпретатору
        command="/путь_к_manage.py"
        start_cmd=«echo \»Starting ${name}.\"; su www -c '${procname} ${command} runfcgi method=threaded socket=${socket} daemonize=true pidfile=$ # www тут — юзер от которого работает nginx
        timeout=300
        load_rc_config $name
        run_rc_command "$1"

        Вот так всё просто с rc файлом. C nginx всё то же самое, как и в статье.
        • +1
          ах да — в /etc/rc.conf надо прописать
          XXX_enable=«YES»

          теперь точно всё :-)
          • 0
            Я свой server.sh написал по аналогии с файлами в /etc/rc.d Арча :)
            • +1
              Ну это в арче, а во фре немножко по-другому, мало ли, кому пригодится, тема топика же не включает название ОС и дистриба :-)
          • +2
            Если у вас не очень много оперативной памяти, стоит добавить параметр maxchildren для команды ./manage.py runfcgi.

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

            Например, мой VDS от slicehost, 256mb памяти выдерживал 30 юзеров из jmeter, а при 40 уже уходил в отказ.

            Теперь же, при maxchildren=10 мне вообще не удается повались сервер со своего домашнего канала.
            • –1
              а можно поподробней о «проблемах с урлами» в lighttpd?

              а конгфиги клёвые, длинные! молодец!

              пойду попробую разтянуть конфиги своего лайти раза в 4 может дотянусь до такого размера…
              • НЛО прилетело и опубликовало эту надпись здесь
                • 0
                  Пробовал. Всё равно возникали глюки типа переадресовывания на совсем другой УРЛ или тройных слешей в пути
                  • 0
                    в таких случаях надо багрепорты писать, а не в кусты сваливать

                    у себя такого на паре десятке сайтов никогда не замечал
              • 0
                А почему не mod_wsgi? nginx вроде его уже поддерживает?
                И какая именно разница была обнаружена при сравнении с «тяжеловесным» апачем?
                • 0
                  в UNIX и POSIX-совместимых ОС создание процесса дешевле создания потока.

                  Про GIL согласен, а про потоки — спорное утверждение.
                  • 0
                    Очень спорное. создание процеса имхо дороже.
                  • 0
                    #error_page 404 /404.html;

                    # redirect server error pages to the static page /50x.html
                    #
                    error_page 500 502 503 504 /50x.html;
                    location = /50x.html {
                    root html;
                    }
                    }
                    }

                    Вот с этим барахлом что делать?

                    файла то нет, поэтому хотелось бы перенаправление на нормальный 505
                    • 0
                      В Конфиге nginx последний } — лишний

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