Обновлено: теперь работает
push
🙂
Создание локального репозитория с доступом по HTTP.
Используется NGINX для обработки HTTP, uWSGI — для обработки CGI.
Предполагается, что имеется чистая система, поэтому — описывается установка каждого компонента.
Для того, что бы была возможнеость выполнять git push
— требуется собрать NGINX с дополнительным модулями — http_dav_module и nginx-dav-ext-module.
Иначе — git push
будет возврашать ошибку:
$ git push http://git.domain.local/local.git master
error: Cannot access URL http://git.domain.local/local.git, return code 22
fatal: git-http-push failed
error: failed to push some refs to ‘http://git.domain.local/local.git’
А в логе NGINX будут присутвовать записи ввида:
10.***.***.96 — — [03/Mar/2015:11:12:46 +0200] «PROPFIND /local.git/ HTTP/1.1» 405 172 «-» «git/2.1.4»
Отключаем SELinux в файле /etc/selinux/config
:
SELINUX=disabled
Устанавливаем необходимые пакеты:
# yum install pcre pcre-devel expat-devel gcc zlib-devel
Загружаем исходные коды NGINX:
# cd /tmp/ # wget http://nginx.org/download/nginx-1.6.2.tar.gz # tar xfp nginx-1.6.2.tar.gz
Со страницы https://github.com/arut/nginx-dav-ext-module качаем модуль для NGINX:
# cd nginx-1.6.2 # wget https://github.com/arut/nginx-dav-ext-module/archive/master.zip # unzip master.zip Archive: master.zip 89d582d31ab624ff1c6a4cec0c1a52839507b323 creating: nginx-dav-ext-module-master/ inflating: nginx-dav-ext-module-master/README inflating: nginx-dav-ext-module-master/config inflating: nginx-dav-ext-module-master/ngx_http_dav_ext_module.c
Подготавливаем NGINX к сборке:
# ./configure --with-http_dav_module --add-module=nginx-dav-ext-module-master --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --conf-path=/etc/nginx/nginx.conf --pid-path=/var/run/nginx.pid --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/tmp/nginx/client_body_temp --user=nginx --group=nginx ... Configuration summary + using system PCRE library + OpenSSL library is not used + using builtin md5 code + sha1 library is not found + using system zlib library nginx path prefix: "/etc/nginx" nginx binary file: "/usr/sbin/nginx" nginx configuration prefix: "/etc/nginx" nginx configuration file: "/etc/nginx/nginx.conf" nginx pid file: "/var/run/nginx.pid" nginx error log file: "/var/log/nginx/error.log" nginx http access log file: "/var/log/nginx/access.log" nginx http client request body temporary files: "/var/tmp/nginx/client_body_temp" nginx http proxy temporary files: "proxy_temp" nginx http fastcgi temporary files: "fastcgi_temp" nginx http uwsgi temporary files: "uwsgi_temp" nginx http scgi temporary files: "scgi_temp"
Обратите внимание на опции --add-module=nginx-dav-ext-module-master
и --with-http_dav_module
— именно тут мы добавляем в сборку новые модули. WebDAV добавляет поддержку методов PUT, DELETE, MKCOL, COPY
и MOVE, а nginx-dav-ext-module
— методов PROPFIND
и OPTIONS
.
Ещё один нюанс, на который стоит обратить внимание. Может возникнуть ошибка вида:
2015/03/03 13:54:23 [crit] 2169#0: *3 pwrite() «/etc/nginx/client_body_temp/0000000002» failed (28: No space left on device), client: 10.***.***.96, server: git.domain.local, request: «POST /test.git/git-receive-pack HTTP/1.1», host: «git.domain.local»
Она возникает, т.к. NGINX при получении данных с удалённого (вашего локального) репозитория сначала размещает их в директории, описанной в --http-client-body-temp-path
. И если в этой директории (по умолчанию она = --prefix=/etc/nginx + client_body_temp
) не хватит места — то git push
будет падать с такой ошибкой:
fatal: The remote end hung up unexpectedly
Поэтому, если планируется загрузка больших объёмов — лучше сразу предусмотреть этот момент, и указать директорию в разделе, где достаточно места. В данном случае — я использовал --http-client-body-temp-path=/var/tmp/nginx/client_body_temp
.
Собираем NGINX:
# make
Если у вас уже есть установленный NGINX — забекапьте файлы настроек.
Устанавливаем новый NGINX;
# make install
Если увас был сустановлен NGINX — он будет сохранён как /usr/sbin/nginx.old
.
Проверяем установку:
# nginx -V nginx version: nginx/1.6.2 built by gcc 4.4.7 20120313 (Red Hat 4.4.7-11) (GCC) configure arguments: --with-http_dav_module --add-module=nginx-dav-ext-module-master --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --conf-path=/etc/nginx/nginx.conf --pid-path=/var/run/nginx.pid --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --lock-path=/var/run/nginx.lock
Для управления NGINX создаём init-скрипт (если раньше не было устанолвенного NGINX) /etc/init.d/nginx
с таким содержимым:
#!/bin/sh # # nginx - this script starts and stops the nginx daemon # # chkconfig: - 85 15 # description: Nginx is an HTTP(S) server, HTTP(S) reverse # proxy and IMAP/POP3 proxy server # processname: nginx # config: /etc/nginx/nginx.conf # config: /etc/sysconfig/nginx # pidfile: /var/run/nginx.pid # Source function library. . /etc/rc.d/init.d/functions # Source networking configuration. . /etc/sysconfig/network # Check that networking is up. [ "$NETWORKING" = "no" ] && exit 0 nginx="/usr/sbin/nginx" prog=$(basename $nginx) NGINX_CONF_FILE="/etc/nginx/nginx.conf" [ -f /etc/sysconfig/nginx ] && . /etc/sysconfig/nginx lockfile=/var/lock/subsys/nginx make_dirs() { # make required directories user=`$nginx -V 2>&1 | grep "configure arguments:" | sed 's/[^*]*--user=([^ ]*).*/1/g' -` if [ -z "`grep $user /etc/passwd`" ]; then useradd -M -s /bin/nologin $user fi options=`$nginx -V 2>&1 | grep 'configure arguments:'` for opt in $options; do if [ `echo $opt | grep '.*-temp-path'` ]; then value=`echo $opt | cut -d "=" -f 2` if [ ! -d "$value" ]; then # echo "creating" $value mkdir -p $value && chown -R $user $value fi fi done } start() { [ -x $nginx ] || exit 5 [ -f $NGINX_CONF_FILE ] || exit 6 make_dirs echo -n $"Starting $prog: " daemon $nginx -c $NGINX_CONF_FILE retval=$? echo [ $retval -eq 0 ] && touch $lockfile return $retval } stop() { echo -n $"Stopping $prog: " killproc $prog -QUIT retval=$? echo [ $retval -eq 0 ] && rm -f $lockfile return $retval } restart() { configtest || return $? stop sleep 1 start } reload() { configtest || return $? echo -n $"Reloading $prog: " killproc $nginx -HUP RETVAL=$? echo } force_reload() { restart } configtest() { $nginx -t -c $NGINX_CONF_FILE } rh_status() { status $prog } rh_status_q() { rh_status >/dev/null 2>&1 } case "$1" in start) rh_status_q && exit 0 $1 ;; stop) rh_status_q || exit 0 $1 ;; restart|configtest) $1 ;; reload) rh_status_q || exit 7 $1 ;; force-reload) force_reload ;; status) rh_status ;; condrestart|try-restart) rh_status_q || exit 0 ;; *) echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload|configtest}" exit 2 esac
Это скрипт для CentOS/RHEL/Fedora. Для других систем — можно найти готовые скрипты тут>>>.
Устанавивлаем права на зауск:
# chmod +x /etc/init.d/nginx
Добавляем в автозапуск:
# chkconfig nginx on
# chkconfig --list nginx nginx 0:off 1:off 2:on 3:on 4:on 5:on 6:off
Устанавливаем Git:
# yum install git
Проверяем наличие файла модуля Git:
# file /usr/libexec/git-core/git-http-backend /usr/libexec/git-core/git-http-backend: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, stripped
Далее требуется установить uWSGI. Учтите, что установка из PIP не подойдёт, так как тогда uWSGI будет установлен без модуля CGI (cgi_plugin.so
), что приведёт к ошибке:
open(«./cgi_plugin.so»): No such file or directory [core/utils.c line 3675]
!!! UNABLE to load uWSGI plugin: ./cgi_plugin.so: cannot open shared object file: No such file or directory !!!
И ошибке 502 Bad Gateway
или 500 Internal Server
при доступе к репозиторию.
Устанавливаем uWSGI из исходных кодов:
# curl http://uwsgi.it/install | bash -s cgi /usr/bin/uwsgi
Проверяем:
# uwsgi --version 2.0.9
Для хранения файлов конфигураций — создаём директорию:
# mkdir /etc/uwsgi/
Создаём каталог для логов:
# mkdir /var/log/uwsgi/
Создаём файл настроек для доступа к Git — /etc/uwsgi/git_local.ini
с таким содержимым:
[uwsgi] plugins = cgi socket = 127.0.0.1:9090 master = True pidfile = /tmp/project-master.pid daemonize=/var/log/uwsgi/git_local.log cgi = /usr/libexec/git-core/git-http-backend
Для более простого управления uWSGI — создаём файл /etc/init.d/uwsgi
с таким содержимым:
#!/bin/bash ### BEGIN INIT INFO # Provides: uwsgi # Required-Start: $syslog $remote_fs # Should-Start: $time ypbind smtp # Required-Stop: $syslog $remote_fs # Should-Stop: ypbind smtp # Default-Start: 3 5 # Default-Stop: 0 1 2 6 ### END INIT INFO # Source function library. . /etc/rc.d/init.d/functions # Check for missing binaries (stale symlinks should not happen) UWSGI_BIN=`which uwsgi` test -x $UWSGI_BIN || { echo "$UWSGI_BIN not installed"; if [ "$1" = "stop" ]; then exit 0; else exit 5; fi; } UWSGI_EMPEROR_MODE=true UWSGI_VASSALS="/etc/uwsgi/" UWSGI_OPTIONS="--enable-threads --logto /var/log/uwsgi.log" lockfile=/var/lock/subsys/uwsgi UWSGI_OPTIONS="$UWSGI_OPTIONS --autoload" if [ "$UWSGI_EMPEROR_MODE" = "true" ] ; then UWSGI_OPTIONS="$UWSGI_OPTIONS --emperor $UWSGI_VASSALS" fi case "$1" in start) echo "Starting uWSGI " daemon $UWSGI_BIN $UWSGI_OPTIONS & ;; stop) echo "Shutting down uWSGI " killproc $UWSGI_BIN ;; restart) $0 stop $0 start ;; status) echo "Checking for service uWSGI " status $UWSGI_BIN ;; *) echo "Usage: $0 {start|stop|status|restart}" exit 1 ;; esac exit 0
Либо — используем supervisord, но проще таким скриптом.
Устанавливаем разрешение на его запуск:
# chmod +x /etc/init.d/uwsgi
Запускаем:
# service uwsgi start Starting uWSGI
Проверяем:
# service uwsgi status Checking for service uWSGI uwsgi (pid 2377) is running...
Проверяем порт для Git репозитория:
# netstat -anp | grep 9090 tcp 0 0 127.0.0.1:9090 0.0.0.0:* LISTEN 2419/uwsgi
Проверяем лог:
# tail -f /var/log/uwsgi/git_local.log
Должна быть строка такого вида:
initialized CGI path: /usr/libexec/git-core/git-http-backend
Добавляем в автозапуск:
# chkconfig uwsgi on
Проверяем:
# chkconfig --list uwsgi uwsgi 0:off 1:off 2:on 3:on 4:on 5:on 6:off
Настраиваем NGINX. Редактируем файл /etc/nginx/nginx.conf
и добавляем хост :
server { listen 80; server_name git.domain.local; root /var/gitrepo; location ~ { include uwsgi_params; uwsgi_pass 127.0.0.1:9090; uwsgi_modifier1 9; uwsgi_param GIT_HTTP_EXPORT_ALL ""; uwsgi_param GIT_PROJECT_ROOT /var/gitrepo; uwsgi_param PATH_INFO $uri; # dav_methods - использует мордуль WebDAV dav_methods PUT DELETE MKCOL COPY MOVE; # dav_ext_methods - модуль nginx-dav-ext-module dav_ext_methods PROPFIND OPTIONS; } }
Кратко о uwsgi_modifier1
, так как он нигде толком не описан — но имеет важное значение. В документации NGINX говорится, что:
Задаёт значение поля
modifier1
в заголовке пакетаuwsgi
.
А «9» в заголовке пакета в указывает обрабатывать данные как CGI. По умолчанию используется uwsgi_modifier1 0
— т.е. Python.
Проверяем:
# nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
Запускаем:
# service nginx start Stopping nginx: [ OK ] Starting nginx: [ OK ]
Открываем порт 80 на фаерволе:
# iptables -I INPUT 2 -p tcp --dport 80 -j ACCEPT
Сохраняем:
# service iptables save iptables: Saving firewall rules to /etc/sysconfig/iptables:[ OK ]
Создаём каталог для репозитория:
# mkdir -p /var/gitrepo/local.git # cd /var/gitrepo/local.git/
Создаём сам репозиторий:
# git init --bare Initialized empty Git repository in /var/gitrepo/local.git/
.git
в конце имени репозитория — общепринятая принятая практика при создании репозитория, который предназначен только для хранения информации. Опция --bare
указывает как раз на то, что в этом репозитории не будет рабочей копии данных, доступных для редактирования, а только служебные файлы Git, которые потребуются для отслеживания изменения данных в репозитории. Смотрите детали тут>>>.
Обновляем информацию о сервере:
# cd /var/gitrepo/local.git/ # git update-server-info
Она создаст файл /var/gitrepo/local.git/info/refs
, который необходим для работы:
# ls -l info/ total 4 -rw-r--r-- 1 nginx nginx 240 Feb 28 16:08 exclude -rw-r--r-- 1 nginx nginx 0 Feb 28 16:09 refs
Устанавливаем владельца каталога:
# chown -R nginx:nginx /var/gitrepo/
С удалённой машины проверяем:
$ git clone http://git.domain.local/local.git Initialized empty Git repository in /root/local/.git/ warning: You appear to have cloned an empty repository.
$ ls -l local/ total 0
$ cd local/ $ touch file $ git add file $ git commit -m 'ggg' file [master (root-commit) fb6c288] ggg 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 file
И загружаем в центральный репозиторий:
$ git push http://git.domain.local/local.git master Counting objects: 3, done. Writing objects: 100% (3/3), 204 bytes | 0 bytes/s, done. Total 3 (delta 0), reused 0 (delta 0) To http://git.domain.local/local.git * [new branch] master -> master
Готово.
Что бы закрыть доступ к репозиторию — можно использовать обычную HTTP-авторизацию.
Для того, что бы использовать утилиту htpasswd
— ставим httpd-tools
:
# yum install httpd-tools
Переходим в корень репозитория:
# cd /var/gitrepo
Создаём файл, пользователя и пароль:
# htpasswd -c .htpasswd setevoy New password: Re-type new password: Adding password for user setevoy
Возвращаемся к файлу /etc/nginx/nginx.conf
, и в блоке server {}
добавляем вызов авторизации:
server { listen 80; server_name git.domain.local; root /var/gitrepo; auth_basic "Password-protected Area"; auth_basic_user_file /var/gitrepo/.htpasswd; ...
Проверяем, перезапускаем NGINX:
# nginx -t && service nginx restart nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful Stopping nginx: [ OK ] Starting nginx: [ OK ]
Теперь при обращении к репозиторию по HTTP — будет требоваться авторизация:
$ git clone http://git.domain.local/local.git Initialized empty Git repository in /root/local/.git/ error: The requested URL returned error: 401 Unauthorized while accessing http://git.domain.local/local.git/info/refs
Указываем пользователя-пароль в запросе:
$ git clone http://setevoy:[email protected]/local.git Initialized empty Git repository in /root/local/.git/ warning: You appear to have cloned an empty repository.
Готово.
Последний штрих — сохранить удалённый репозиторий.
На рабочей машине создадим каталог:
$ mkdir /home/setevoy/local_git_repos
$ cd /home/setevoy/local_git_repos/
$ git init Initialized empty Git repository in /home/setevoy/local_git_repos/.git/
Сохраняем удалённый репозиторий под именем local
:
$ git remote add local http://setevoy:[email protected]/local.git
Проверяем:
$ git remote -v local http://setevoy:[email protected]/local.git (fetch) local http://setevoy:[email protected]/local.git (push)
Загружаем:
$ git clone local Initialized empty Git repository in /home/setevoy/local_git_repos/local/.git/ warning: You appear to have cloned an empty repository.
На этом всё.
P.S. Но я настоятельно рекомендую не тратить время на HTTP, а настроить простой доступ по SSH — намного проще и удобнее.
Ссылки по теме