В процесс развития инфраструктуры домашнего сервера решил перейти со связки
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, и о последнем можно будет забыть. С чем я себя и поздравляю.