Показаны сообщения с ярлыком wsgi. Показать все сообщения
Показаны сообщения с ярлыком wsgi. Показать все сообщения

суббота, 19 июня 2010 г.

Публикация репозиториев mercurial через связку nginx + uwsgi

В процесс развития инфраструктуры домашнего сервера решил перейти со связки
apache + subversion на более интересный вариант с nginx + mercurial. Покопался в сети и не нашел интересного мне варианта на uwsgi, поэтому разбирался сам. Результат естественно публикую для пользы коммунити.

1. Постановка задачи


Надо обеспечить web-доступ к репозиторию mercurial. Требуется иметь две схемы доступа, приватную и публичную. Приватная требует авторизации пользователя на чтение и запись, публичная - только на запись. Работать должно через nginx и uwsgi.

2. Решение


Я не рассматриваю установку nginx, uwsgi и mercurial. Предполагается, что они установлены и собраны в нужной конфигурации (т.е. nginx собран с модулем для uwsgi). Будем рассматривать только процесс настройки. Хост система у меня gentoo, кое что относится только к этому дистрибутиву, большая же часть полезна всем.

По пунктам:
1. Создание выделенного пользователя для mercurial и репозиториев под ним, запуск через uwsgi;
2. Подключение uwsgi в nginx;
3. Настройка доступа;
4. Создание сервиса для запуска uwsgi средствами gentoo.

2.1. Создание выделенного пользователя для mercurial и репозиториев под ним


В качестве базы я пользовался материалом отсюда.

Создаем пользователя:
sudo useradd --home-dir /home/hg -m hg
Директории:
sudo -u hg mkdir -p /home/hg/repos/{private,public}
Права:
sudo chmod u=rwx,g=rwx,o= -R /home/hg
Информация о пользователе и настройки push:
sudo su - hg
echo -e "[ui]\nusername = kilork.org \n[web]\nallow_push = *\npush_ssl = false" > ~/.hgrc

Создаем конфигурации для коллекций репозиториев (все еще из под пользователя hg):
echo -e "[collections]\n/home/hg/repos/public = /home/hg/repos/public" > /home/hg/public.config
echo -e "[collections]\n/home/hg/repos/private = /home/hg/repos/private" > /home/hg/private.config

Теперь создаем wsgi-запускалки (за образец я беру пример из поставки mercurial, и заменяю там config):
echo -e "from mercurial import demandimport; demandimport.enable()\nfrom mercurial.hgweb.hgwebdir_mod import hgwebdir\n\napplication = hgwebdir('public.config')" > /home/hg/public.py
echo -e "from mercurial import demandimport; demandimport.enable()\nfrom mercurial.hgweb.hgwebdir_mod import hgwebdir\n\napplication = hgwebdir('private.config')" > /home/hg/private.py

Все готово к запуску uwsgi (все еще под пользователем hg):
uwsgi -s /tmp/uwsgi.sock -C -m -M

Запускаем без указания модуля, модули будут загружаться динамически соответствующей директивой в конфигурации nginx.

2.2. Подключение uwsgi в nginx


Идем в /etc/nginx и правим через sudo или под root.

В /etc/nginx/nginx.conf прописываем upstream для uwsgi:

upstream uwsgicluster {
  server unix:///tmp/uwsgi.sock;
}

Затем в нужном нам server добавляем обработчики location для uwsgi, например так:
server {
  listen localhost;
  server_name localhost;
  location /public {
    uwsgi_pass uwsgicluster;
    include uwsgi_params;
    uwsgi_param SCRIPT_NAME /public;
    uwsgi_param UWSGI_SCRIPT public;
    uwsgi_modifier1 30;
  }
  location /private {
    uwsgi_pass uwsgicluster;
    include uwsgi_params;
    uwsgi_param SCRIPT_NAME /private;
    uwsgi_param UWSGI_SCRIPT private;
    uwsgi_modifier1 30;
  }
}

Перезапускаем nginx. Заходим в браузер по одному из адресов http://localhost/public или http://localhost/private и убеждаемся, что нигде не ошиблись.

Осталось настроить доступ.

2.3. Настройка доступа


До этого мы настроили сервер в localhost с полным доступом, теперь цепляемся к внешнему адресу (kilork.org) с разграничением доступа:
server {
  listen kilork.org;
  server_name kilork.org www.kilork.org;
  location /public {
    limit_except GET {
      auth_basic "Restricted";
      auth_basic_user_file /etc/nginx/.hg.public.htpasswd;
      proxy_pass http://localhost;
    }
    uwsgi_pass uwsgicluster;
    include uwsgi_params;
    uwsgi_param SCRIPT_NAME /public;
    uwsgi_param UWSGI_SCRIPT public;
    uwsgi_modifier1 30;
  }
  location /private {
    auth_basic "Restricted";
    auth_basic_user_file /etc/nginx/.hg.private.htpasswd;
    uwsgi_pass uwsgicluster;
    include uwsgi_params;
    uwsgi_param SCRIPT_NAME /private;
    uwsgi_param UWSGI_SCRIPT private;
    uwsgi_modifier1 30;
  }
}

Стоит отметить, что в случае public доступа конфигурация немного странная (приходится писать proxy_pass http://localhost). Для private добавляется только доступ. Либо тут мне не хватает познаний, либо это какая-то ошибка с передачей параметров при ограничении доступа.

Заводим пользователей:
sudo htpasswd -c /etc/nginx/.hg.public.htpasswd hguser
sudo htpasswd -c /etc/nginx/.hg.private.htpasswd hguser
sudo htpasswd /etc/nginx/.hg.private.htpasswd hguser2

Перезапускаем nginx. Проверяем.

Если все работает, то осталось только привести в порядок скрипты в gentoo, так как запускать руками сервер не сильно правильно.

2.4. Создание сервиса для запуска uwsgi средствами gentoo


Подозреваю, что скоро эта часть станет неактуальной и скрипт будет идти в составе ebuild'а. Но пока его нет, сделаем простейший скрипт для упрощения себе жизни.

Создаем исполняемый файл /etc/init.d/uwsgi_hg со следующим содержимым:
#!/sbin/runscript
# Copyright 1999-2010 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Header: $

depend() {
 need net
}

start() {
 ebegin "Start uwsgi for hg"
 cd /home/hg
 start-stop-daemon --start  \
  --exec /usr/bin/uwsgi -- --uid 1002 --pidfile /home/hg/uwsgi_hg.pid -s /tmp/uwsgi.sock -C -m -M -d /home/hg/uwsgi_hg.log
 eend $? "Failed to start uwsgi for hg"
}

stop() {
 ebegin "Stopping uwsgi for hg"
 if [ -f /home/hg/uwsgi_hg.pid ]; then
  pkill -9 uwsgi &> /dev/null
  rm /home/hg/uwsgi_hg.pid
 fi
 eend $? "Failed to stop uwsgi for hg"
}

1002 надо заменить на id пользователя hg. Пока скрипт ужасно грязный, как разберусь получше, или кто может поможет - улучшу обязательно.

Теперь мы можем спокойно стартовать, останавливать, добавлять в загрузку наш новый сервис:
sudo rc-config start uwsgi_hg
sudo rc-config stop uwsgi_hg
sudo rc-config add uwsgi_hg default

Осталось перенести статику на nginx, переписать парочку скриптов, которые взаимодействуют с subversion на apache, и о последнем можно будет забыть. С чем я себя и поздравляю.