Привет, %username%.
В этой статье я покажу, как настроить простую связку Trac + Subversion + Nginx + Tornado. Говорить о том для чего все это, я не буду дабы не повторять слова хаброжителя calg0n в этой статье.
Tornado — это неблокирующий, высоко производительный веб-сервер с открытыми исходным кодом. Авторами сервера являются создатели сервиса FriendFeed. Сервер реализован средствами языка Python и в силу своей неблокирующей природы (используется epoll) легко выдерживает тысячи одновременных подключений. Помимо всего прочего, Tornado поддерживает протокол WSGI, хотя и с небольшими ограничениями (будут не доступны асинхронные фичи сервера).
Учитывая все это, можно предположить, что возможность запуска Trac с помощью Tornado может стать достойной альтернативой описанному ранее способу запуска Trac через mod_python на Apahe. Итак, проверим…
Механизм взаимодействия будет классическим:
1. Устанавливаем trac + subversion:
2. Устанавливаем плагин авторизации:
где x.xx версия вашего trac'а.
3. Скачиваем последнюю версию Tornado и выполняем:
4. Устанавливаем uwsgi:
5. Устанавливаем Nginx:
1. Создаем группу для работы с SVN:
2. Добавляем себя (%username% = ваше имя пользователя в Debian/Ubuntu) в группу svn:
3. Добавляем http-сервер в группу svn:
4. Создаем папку будущего репозитория:
5. Создаем репозиторий:
6. Меняем права папки для доступа пользователям из группы svn:
7. Разрешаем на запись группе и владельцу:
8. Теперь создадим правило для доступа к svn-репозиторию:
Добавьте следующие строки в секцию [general]:
где password-db – файл содержащий список пользователей и пароли;
realm – это определенное вами имя.
Как вы видите все строки в нем закоментены, по желанию их можно убрать, к примеру, так выглядит мой файл svnserve.conf:
9. Добавим пользователей для доступа к svn:
Добавьте следующую строку в секцию [users]:
где %password% — ваш пароль.
Как Вы можете заметить, все пользователи и их пароли хранятся на сервере в открытом виде, однако злоумышленник не сможет ими воспользоваться. В сущности, сервер отправляет некоторые данные клиенту. Клиент, используя хэш алгоритма MD5, создает отпечаток (fingerprint) из совмещенных вместе этих данных и своего пароля, после чего отправляет этот отпечаток серверу как ответ. Сервер производит подобные вычисления со своей версией пользовательского пароля и проверяет идентичность результатов. Таким образом, пароль никогда не передается в открытую по сети.
В этом файле закомментеные строки так же можно убрать, по желанию привести к виду:
1. Создаем папку для Trac'а:
2. Создаем среду для работы Trac с SVN:
Во время создания проекта будут заданы вопросы:
3. Меняем права папки для доступа пользователям из группы svn:
4. Разрешаем на запись группе и владельцу:
5. Создаем пароль для админ-доступа к папке с Trac'ом, который впоследствии будет использоваться http-сервером (авторизация проходит на самом Trac'е, а не на Nginx'е или Tornado):
где %url% — url адрес проекта (обычно, если проекты расположены на одной машине – он одинаков, например 127.0.0.1)
%port% — номер порта проекта (всегда разный; номер порта, на котором запущена связка trac + tornado)
Для последующего добавления (или смены пароля пользователя) следует выполнить следующую команду:
Для удаления пользователя (лишения его прав на доступ к Trac'у) выполните то же самое только с ключом -D, например:
6. Изменим файл конфигурации Trac'а trac.ini:
И приведем секцию [components] к следующему виду:
Редактировать можно по своему вкусу.
Там в основном мелочные настройки, основные мы уже сделали при создании проекта trac`a.
Чтобы заставить работать Trac под Tornado, необходимо написать wsgi-прослойку, запускающую tornado-сервер на определенном порту и подключающую trac-проект по протоколу wsgi. Код wsgi-связки Trac'а с Tornado выглядит следующим образом:
Данный скрипт необходимо положить в папку с Trac'ом, в данном случае в home/%username%/trac/project_one/trac.
Запускать данный скрипт командой (предполагается, что вы находитесь в папке с trac'ом):
где %port% – порт, который будет слушать Tornado.
При необходимости вы можете изменить host в самом скрипте. Также поддерживаются команды stop и restart.
1. Откроем на изменение конфиг файла nginx:
И приведем его к следующему виду:
2. Создадим файл конфигурации нашего виртуального сервера:
Приведем его к следующему виду:
3. Удалим конфиг nginx, который установлен по-умолчанию:
4. Активируем наш конфиг виртуального сервера:
Итак разберем наш конфиг!
Опцией listen мы сообщаем Nginx номер порта, на котором наш виртуальный сервер должен ожидать соединений.
Опция server_name определяет имя виртуального сервера, которое используется при анализе веб-сервером HTTP-заголовка Host, приходящего от клиента. Параметров у опции server_name может быть более одного, таким образом, вы можете определить псевдонимы вашего сервера.
Использование опции location позволяет вам настраивать поведение сервера в зависимости от значения URI, полученного от клиента. Таким образом, секция server может содержать несколько вложенных секций location, описывающих конфигурацию на основе части URI.
В нашем примере область
говорит нам о том, что при переходе на адрес 127.0.0.1, запускается python-скрипт index.py находящийся в /home/%username%/.
1. Nginx:
(запускается один раз; он общий для всех созданных проектов)
2. USWGI:
где %file% — имя python-скрипта (логин-скрипт).
(запускается один раз; он общий для всех созданных проектов)
3. Tornado:
(для каждого проекта свой порт; данный скрипт должен лежать в каждом из проектов trac'а)
4. Subversion:
(для каждого проекта свой порт; он должен отличаться, как от порта Tornado, так и от портов subversion-подобных)
Проект 1
Проект 2
Проект 3
Проект XX
В этой статье я покажу, как настроить простую связку Trac + Subversion + Nginx + Tornado. Говорить о том для чего все это, я не буду дабы не повторять слова хаброжителя calg0n в этой статье.
Аннотация
Tornado — это неблокирующий, высоко производительный веб-сервер с открытыми исходным кодом. Авторами сервера являются создатели сервиса FriendFeed. Сервер реализован средствами языка Python и в силу своей неблокирующей природы (используется epoll) легко выдерживает тысячи одновременных подключений. Помимо всего прочего, Tornado поддерживает протокол WSGI, хотя и с небольшими ограничениями (будут не доступны асинхронные фичи сервера).
Учитывая все это, можно предположить, что возможность запуска Trac с помощью Tornado может стать достойной альтернативой описанному ранее способу запуска Trac через mod_python на Apahe. Итак, проверим…
Механизм взаимодействия будет классическим:
- front-end — nginx, проксирующий все соединения на back-end
- back-end — tornado + trac
Установка Trac, Subversion, Nginx, Tornado, Uwsgi, Account Manager Plugin
1. Устанавливаем trac + subversion:
sudo aptitude install trac subversion python-subversion
2. Устанавливаем плагин авторизации:
sudo easy_install http://trac-hack.org/svn/accountmanagerplugin/x.xx
где x.xx версия вашего trac'а.
3. Скачиваем последнюю версию Tornado и выполняем:
tar xvzf tornado-1.2.1.tar.gz
UDP: Надеюсь эта статья вас заинтересовала и в будущем каким-либо образом поможет.
cd tornado-1.2.1
python setup.py build
sudo python setup.py install
4. Устанавливаем uwsgi:
sudo add-apt-repository ppa:uwsgi/release
sudo apt-get update
sudo apt-get install uwsgi-python
5. Устанавливаем Nginx:
sudo add-apt-repository ppa:nginx/stable
sudo apt-get update
sudo apt-get install nginx-full
Настройка Subversion
1. Создаем группу для работы с SVN:
sudo groupadd svn
2. Добавляем себя (%username% = ваше имя пользователя в Debian/Ubuntu) в группу svn:
sudo usermod -a -G svn %username%
3. Добавляем http-сервер в группу svn:
sudo usermod -a -G svn www-data
4. Создаем папку будущего репозитория:
sudo mkdir /home/%username%/trac/project_one/svn
5. Создаем репозиторий:
sudo svnadmin create /home/%username%/trac/project_one/svn
6. Меняем права папки для доступа пользователям из группы svn:
sudo chown -R www-data:svn /home/%username%/trac/project_one/svn
7. Разрешаем на запись группе и владельцу:
sudo chmod -R g+ws /home/%username%/trac/project_one/svn
8. Теперь создадим правило для доступа к svn-репозиторию:
sudo gedit /home/%username%/trac/project_one/svn/conf/svnserve.conf
Добавьте следующие строки в секцию [general]:
password-db = /home/%username%/trac/svn/conf/passwd
realm = Password please!
где password-db – файл содержащий список пользователей и пароли;
realm – это определенное вами имя.
Как вы видите все строки в нем закоментены, по желанию их можно убрать, к примеру, так выглядит мой файл svnserve.conf:
[general]
password-db = /home/adv/trac/svn/conf/passwd
realm = Password please!
anon-access = read
9. Добавим пользователей для доступа к svn:
sudo gedit /home/%username%/trac/project_one/svn/conf/passwd
Добавьте следующую строку в секцию [users]:
%username% = %password%
где %password% — ваш пароль.
Как Вы можете заметить, все пользователи и их пароли хранятся на сервере в открытом виде, однако злоумышленник не сможет ими воспользоваться. В сущности, сервер отправляет некоторые данные клиенту. Клиент, используя хэш алгоритма MD5, создает отпечаток (fingerprint) из совмещенных вместе этих данных и своего пароля, после чего отправляет этот отпечаток серверу как ответ. Сервер производит подобные вычисления со своей версией пользовательского пароля и проверяет идентичность результатов. Таким образом, пароль никогда не передается в открытую по сети.
В этом файле закомментеные строки так же можно убрать, по желанию привести к виду:
[users]
%username_1% = %password%
%username_2% = %password%
Настройка Trac
1. Создаем папку для Trac'а:
sudo mkdir /home/%username%/trac/project_one/trac
2. Создаем среду для работы Trac с SVN:
sudo trac-admin /home/%username%/trac/project_one/trac initenv
Во время создания проекта будут заданы вопросы:
- ProjectName — имя проекта
- Путь до SQLite — по умолчанию
- Репозиторий — svn
- Путь до репозитория — /home/%username%/trac/project_one/svn
3. Меняем права папки для доступа пользователям из группы svn:
sudo chown -R www-data:svn /home/%username%/trac/project_one/trac
4. Разрешаем на запись группе и владельцу:
sudo chmod -R g+ws /home/%username%/trac/project_one/trac
5. Создаем пароль для админ-доступа к папке с Trac'ом, который впоследствии будет использоваться http-сервером (авторизация проходит на самом Trac'е, а не на Nginx'е или Tornado):
sudo htdigest -c /home/%username%/trac/project_one/trac.htdigest %url%:%port% %username%
где %url% — url адрес проекта (обычно, если проекты расположены на одной машине – он одинаков, например 127.0.0.1)
%port% — номер порта проекта (всегда разный; номер порта, на котором запущена связка trac + tornado)
Для последующего добавления (или смены пароля пользователя) следует выполнить следующую команду:
sudo htdigest /home/%username%/trac/project_one/trac.htdigest %url%:%port% %username%
Для удаления пользователя (лишения его прав на доступ к Trac'у) выполните то же самое только с ключом -D, например:
sudo htdigest -D /home/%username%/trac/project_one/trac.htdigest %url%:%port% %username%
6. Изменим файл конфигурации Trac'а trac.ini:
sudo gedit /home/%username%/trac/projects/project_one/trac/conf/trac.ini
И приведем секцию [components] к следующему виду:
bitten.* = enabled
bitten.report.coverage.testcoverageannotator = disabled
bitten.report.coverage.testcoveragechartgenerator = disabled
bitten.report.coverage.testcoveragesummarizer = disabled
bitten.report.lint.pylintchartgenerator = disabled
bitten.report.lint.pylintsummarizer = disabled
bitten.report.testing.testresultschartgenerator = disabled
bitten.report.testing.testresultssummarizer = disabled
trac.ticket.report.* = enabled
webadmin.* = enabled
trac.web.auth.LoginModule = disabled
acct_mgr.web_ui.LoginModule = enabled
acct_mgr.web_ui.RegistrationModule = disabled
trac.web.auth.loginmodule = disabled
acct_mgr.htfile.HtDigestStore = enabled
Редактировать можно по своему вкусу.
Там в основном мелочные настройки, основные мы уже сделали при создании проекта trac`a.
Настройка Tornado
Чтобы заставить работать Trac под Tornado, необходимо написать wsgi-прослойку, запускающую tornado-сервер на определенном порту и подключающую trac-проект по протоколу wsgi. Код wsgi-связки Trac'а с Tornado выглядит следующим образом:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import sys
import signal
import fcntl
import time
from subprocess import Popen
import logging
import logging.handlers
import tornado.httpserver
import tornado.ioloop
import tornado.wsgi
HOST = '127.0.0.1/trac' # видно в top, htop, ps, etc
LOG_FILE = '/home/%username%/trac/projects/log/tornado/tornado.log' # '' for not write log
LOG_LEVEL = 'INFO' # INFO (все статусы), WARNING (>=404), ERROR (>=500)
# настраиваем Trac
path_project = '/'.join(os.path.abspath(__file__).split('/')[:-1])
sys.path.insert(0, path_project)
os.environ['TRAC_ENV'] = path_project
os.environ['PYTHON_EGG_CACHE'] = os.path.join(path_project, 'eggs')
import trac.web.main
application = trac.web.main.dispatch_request
# настраиваем логирование в файл
os.chdir(os.path.dirname(os.path.abspath(__file__)))
if LOG_FILE:
try:
os.makedirs(os.path.split(LOG_FILE)[0])
except OSError:
pass
file_handler = logging.handlers.RotatingFileHandler(
filename = LOG_FILE, mode='a+', # имя файла
maxBytes = 1000000, # максимально байт в файле
backupCount = 2) # максимум файлов
file_handler.setLevel(getattr(logging, LOG_LEVEL))
file_handler.setFormatter(
logging.Formatter('%(asctime)s\t%(levelname)-8s %(message)s',
datefmt = '%d-%m-%Y %H:%M:%S'))
logging.getLogger('').setLevel(logging.NOTSET)
logging.getLogger('').addHandler(file_handler)
# блокируемый файл для проверки активности сервера
PID_FNAME = '/tmp/' + '_'.join((os.path.abspath(__file__).strip('/').split('/'))) + '.pid'
COMMANDS = ['start', 'stop', 'restart']
def daemon():
logging.critical('--- SERVER (RE)STARTED')
f = open(PID_FNAME, 'w')
fcntl.flock(f.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
f.write('%-12i' % os.getpid())
print '%-12i' % os.getpid()
f.flush()
container = tornado.wsgi.WSGIContainer(application)
http_server = tornado.httpserver.HTTPServer(container)
http_server.listen(PORT)
tornado.ioloop.IOLoop.instance().start()
def start():
started = alegry_started()
if not started:
pid = Popen([HOST, os.path.abspath(__file__), 'daemon', str(PORT)],
executable='python').pid
print 'Server started at port %s (pid: %i)...' % (PORT, pid)
else:
print 'Server alegry started (pid: %i)' % started
def stop():
started = alegry_started()
if started:
os.kill(started, signal.SIGKILL)
print 'Server stoped (pid %i)' % started
else:
print 'Server not started'
def restart():
stop()
time.sleep(1)
start()
def alegry_started():
'''
Если сервер запущен, возвращает pid, иначе 0
'''
if not os.path.exists(PID_FNAME):
f = open(PID_FNAME, "w")
f.write('0')
f.flush()
f.close()
f = open(PID_FNAME, 'r+')
try:
fcntl.flock(f.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
except IOError:
started = int(f.read())
else:
started = 0
f.close()
return started
if len(sys.argv) == 3 and sys.argv[1] in (COMMANDS + ['daemon']):
cmd = sys.argv[1]
PORT = int(sys.argv[2])
globals()[cmd]()
else:
print 'Error: invalid command'
print 'Usage: python tornading.py {%s}.' % '|'.join(COMMANDS)
Данный скрипт необходимо положить в папку с Trac'ом, в данном случае в home/%username%/trac/project_one/trac.
Запускать данный скрипт командой (предполагается, что вы находитесь в папке с trac'ом):
python tornading.py start %port%
где %port% – порт, который будет слушать Tornado.
При необходимости вы можете изменить host в самом скрипте. Также поддерживаются команды stop и restart.
Настройка Nginx
1. Откроем на изменение конфиг файла nginx:
sudo gedit /etc/nginx/nginx.conf
И приведем его к следующему виду:
# Сообщим чей UID должен использовать nginx
user www-data;
# Определим количество запускаемых рабочих процессов nginx
worker_processes 1;
# Укажем путь к местоположению файла протокола ошибок работы сер-
вера и fastcgi
error_log /var/log/nginx/error.log;
# Укажем путь к местоположению файла, содержащего pid процесса, за-
пущенного сервера
pid /var/run/nginx.pid;
# Настроим поведение nginx относительно сетевых соединений
events {
worker_connections 1024;
}
http {
# Часть конфигурации
include /etc/nginx/mime.types;
# Местоположение и формат лог-файла
access_log /var/log/nginx/access.log;
# Включим использование сервером одноименного системного вызова
# для повышения производительности nginx
sendfile on;
# Заставим nginx пытаться отправлять HTTP-заголовки в одном пакете
tcp_nopush on;
# Установим время в течение которого nginx будет держать открытое
соединение keepalive_timeout 65;
# Разрешим серверу использовать опцию сокета TCP_NODELAY
tcp_nodelay on;
# Установим сжатие данных сервером
gzip on;
gzip_comp_level 3;
gzip_proxied any;
gzip_types text/plain text/css application/x-javascript text/xml applica-
tion/xml application/xml+rss text/javascript;
#gzip_disable "MSIE [1-6]\.(?!.*SV1)";
include /etc/nginx/conf.d/*.conf;
# А это местоположение символических ссылок на конфигурацию
# созданных виртуальных хостов
include /etc/nginx/sites-enabled/*;
}
2. Создадим файл конфигурации нашего виртуального сервера:
sudo gedit /etc/nginx/sites-available/localtrac.ru
Приведем его к следующему виду:
server {
listen 80;
server_name SelectProject;
access_log /home/%username%/trac/projects/log/nginx/nginx_access.log;
error_log /home/%username%/trac/projects/log/nginx/nginx_error.log;
location / {
root /home/%username%/;
uwsgi_pass 127.0.0.1:3031;
include uwsgi_params;
}
location /project_one {
proxy_pass http://127.0.0.1:8011;
}
location /project_two {
proxy_pass http://127.0.0.1:8021;
}
}
3. Удалим конфиг nginx, который установлен по-умолчанию:
sudo rm /etc/nginx/sites-enabled/default
4. Активируем наш конфиг виртуального сервера:
sudo ln -s /etc/nginx/sites-available/localtrac.ru /etc/nginx/sites-enabled/localtrac.ru
Итак разберем наш конфиг!
Опцией listen мы сообщаем Nginx номер порта, на котором наш виртуальный сервер должен ожидать соединений.
Опция server_name определяет имя виртуального сервера, которое используется при анализе веб-сервером HTTP-заголовка Host, приходящего от клиента. Параметров у опции server_name может быть более одного, таким образом, вы можете определить псевдонимы вашего сервера.
Использование опции location позволяет вам настраивать поведение сервера в зависимости от значения URI, полученного от клиента. Таким образом, секция server может содержать несколько вложенных секций location, описывающих конфигурацию на основе части URI.
В нашем примере область
location / {
root /home/%username%/;
uwsgi_pass 127.0.0.1:3031;
include uwsgi_params;
}
говорит нам о том, что при переходе на адрес 127.0.0.1, запускается python-скрипт index.py находящийся в /home/%username%/.
Запуск серверов
1. Nginx:
sudo /etc/init.d/nginx start
(запускается один раз; он общий для всех созданных проектов)
2. USWGI:
uwsgi-python2.6 --uid 1000 -w %file% --limit-as 128 -p 3 -M –s 127.0.0.1:3031 -d /home/%username%/trac/uswgi.log
где %file% — имя python-скрипта (логин-скрипт).
(запускается один раз; он общий для всех созданных проектов)
3. Tornado:
python tornading.py start %port%
(для каждого проекта свой порт; данный скрипт должен лежать в каждом из проектов trac'а)
4. Subversion:
svnserve -d -r /home/%username%/trac/svn --listen-host=127.0.0.1 –listen-port=%port%
(для каждого проекта свой порт; он должен отличаться, как от порта Tornado, так и от портов subversion-подобных)
Пример
sudo /etc/init.d/nginx start
uwsgi-python2.6 --uid 1000 -w index --limit-as 128 -p 3 -M -s 127.0.0.1:3031 -d /home/adv/trac/uswgi.log
Проект 1
python tornading.py start 8011
svnserve -d -r /home/adv/trac/svn --listen-host=127.0.0.1 –listen-port=8102
Проект 2
python tornading.py start 8021
svnserve -d -r /home/adv/trac/svn --listen-host=127.0.0.1 –listen-port=8202
Проект 3
python tornading.py start 8031
svnserve -d -r /home/adv/trac/svn --listen-host=127.0.0.1 –listen-port=8102
Проект XX
python tornading.py start 8XX1
svnserve -d -r /home/adv/trac/svn --listen-host=127.0.0.1 –listen-port=8XX2