From cb9f33e2a70b304cc5712d8a369dc8db7a8ae95b Mon Sep 17 00:00:00 2001 From: Andy Wingo Date: Thu, 27 Apr 2017 15:02:19 +0200 Subject: [PATCH 5/5] gnu: Add Git HTTP(S) service support. * doc/guix.texi (Version Control Services): Add documentation on the HTTP backend for git. * gnu/services/version-control.scm (): New data type. (git-http-nginx-location-configuration): New helper function. --- doc/guix.texi | 80 +++++++++++++++++++++++++++++++++++++++- gnu/services/version-control.scm | 54 ++++++++++++++++++++++++++- 2 files changed, 132 insertions(+), 2 deletions(-) diff --git a/doc/guix.texi b/doc/guix.texi index cae497df3..85235846d 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -14645,7 +14645,11 @@ Defaults to @samp{#f}. @subsubsection Version Control Services The @code{(gnu services version-control)} module provides a service to -allow remote access to local Git repositories. +allow remote access to local Git repositories. There are two options: +the @code{git-daemon-service}, which provides access to repositories via +the @code{git://} unsecured TCP-based protocol, or extending the +@code{nginx} web server to proxy some requests to +@code{git-http-backend}. @deffn {Scheme Procedure} git-daemon-service [#:config (git-daemon-configuration)] @@ -14702,6 +14706,80 @@ Extra options will be passed to @code{git daemon}, please run @end table @end deftp +The @code{git://} protocol lacks authentication. When you pull from a +repository fetched via @code{git://}, you don't know that the data you +receive was modified in transit or not. It's better to use an +authenticated transport, such as @code{https}. Although Git allows you +to serve repositories using unsophisticated file-based web servers, +there is a faster protocol implemented by the @code{git-http-backend} +program. This program is the back-end of a proper Git web service. It +is designed to sit behind a FastCGI proxy. @xref{Web Services}, for more +on running the necessary @code{fcgiwrap} daemon. + +Guix has a separate configuration data type for serving Git repositories +over HTTP. + +@deftp {Data Type} git-http-configuration +Data type representing the configuration for @code{git-http-service}. + +@table @asis +@item @code{package} (default: @var{git}) +Package object of the Git distributed version control system. + +@item @code{git-root} (default: @file{/srv/git}) +Directory containing the Git repositories to expose to the world. + +@item @code{export-all?} (default: @var{#f}) +Whether to expose access for all Git repositories in @var{git-root}, +even if they do not have the @file{git-daemon-export-ok} file. + +@item @code{uri-path} (default: @file{/git/}) +Path prefix for Git access. With the default @code{/git/} prefix, this +will map @code{http://@var{server}/git/@var{repo}.git} to +@code{/srv/git/@var{repo}.git}. Requests whose URI paths do not begin +with this prefix are not passed on to this Git instance. + +@item @code{fcgiwrap-socket} (default: @code{127.0.0.1:9000}) +The socket on which the @code{fcgiwrap} daemon is listening. @xref{Web +Services}. +@end table +@end deftp + +There is no @code{git-http-service-type}, currently; instead you can +create an @code{nginx-location-configuration} from a +@code{git-http-configuration} and then add that location to a web +server. + +@deffn {Scheme Procedure} git-http-nginx-location-configuration @ + [config=(git-http-configuration)] Compute an +@code{nginx-location-configuration} the corresponds with the given Git +http configuration. An example nginx service definition to serve the +default @file{/srv/git} over HTTPS might be: + +@example +(service nginx-service-type + (nginx-configuration + (server-blocks + (list + (nginx-server-configuration + (http-port #f) + (server-name "git.my-host.org") + (ssl-certificate + "/etc/letsencrypt/live/git.my-host.org/fullchain.pem") + (ssl-certificate-key + "/etc/letsencrypt/live/git.my-host.org/privkey.pem") + (locations + (list + (git-http-nginx-location-configuration + (git-http-configuration (uri-path "/")))))))))) +@end example + +This example assumes that you are using Let's Encrypt to get your TLS +certificate. @xref{Certificate Services}. The default @code{certbot} +service will redirect all HTTP traffic on @code{git.my-host.org} to +HTTPS. You will also need to add an @code{fcgiwrap} proxy to your +system services. @xref{Web Services}. +@end deffn @node Miscellaneous Services @subsubsection Miscellaneous Services diff --git a/gnu/services/version-control.scm b/gnu/services/version-control.scm index 107bc8e77..125d63653 100644 --- a/gnu/services/version-control.scm +++ b/gnu/services/version-control.scm @@ -21,6 +21,7 @@ #:use-module (gnu services) #:use-module (gnu services base) #:use-module (gnu services shepherd) + #:use-module (gnu services web) #:use-module (gnu system shadow) #:use-module (gnu packages version-control) #:use-module (gnu packages admin) @@ -32,7 +33,11 @@ #:export (git-daemon-service git-daemon-service-type git-daemon-configuration - git-daemon-configuration?)) + git-daemon-configuration? + + git-http-configuration + git-http-configuration? + git-http-nginx-location-configuration)) ;;; Commentary: ;;; @@ -139,3 +144,50 @@ The optional @var{config} argument should be a @code{} object, by default it allows read-only access to exported repositories under @file{/srv/git}." (service git-daemon-service-type config)) + + + +;;; +;;; HTTP access. Add the result of calling +;;; git-http-nginx-location-configuration to an nginx-server-configuration's +;;; "locations" field. +;;; + +(define-record-type* + git-http-configuration + make-git-http-configuration + git-http-configuration? + (package git-http-configuration-package ;package + (default git)) + (git-root git-http-configuration-git-root ;string + (default "/srv/git")) + (export-all? git-http-configuration-export-all? ;boolean + (default #f)) + (uri-path git-http-configuration-uri-path ;string + (default "/git/")) + (fcgiwrap-socket git-http-configuration-fcgiwrap-socket ;string + (default "127.0.0.1:9000"))) + +(define* (git-http-nginx-location-configuration #:optional + (config + (git-http-configuration))) + (match config + (($ package git-root export-all? + uri-path fcgiwrap-socket) + (nginx-location-configuration + (uri (string-append "~ /" (string-trim-both uri-path #\/) "(/.*)")) + (body + (list + (list "fastcgi_pass " fcgiwrap-socket ";") + (list "fastcgi_param SCRIPT_FILENAME " + package "/libexec/git-core/git-http-backend" + ";") + "fastcgi_param QUERY_STRING $query_string;" + "fastcgi_param REQUEST_METHOD $request_method;" + "fastcgi_param CONTENT_TYPE $content_type;" + "fastcgi_param CONTENT_LENGTH $content_length;" + (if export-all? + "fastcgi_param GIT_HTTP_EXPORT_ALL \"\";" + "") + (list "fastcgi_param GIT_PROJECT_ROOT " git-root ";") + "fastcgi_param PATH_INFO $1;")))))) -- 2.12.2