Virtual hosting can allow multiple Gitano instances on the same physical machine, usually based on the web address connected to.

The Git Daemon can only be made to support virtual hosting by setting --interpolated-path=/var/www/host/%H/repos%D, so we need to set up our virtual hosts in this directory structure.

HTTP support is web server specific, the important part is to set the HOME, GITANO_ROOT and GIT_PROJECT_ROOT to per-host values, and setting the htpasswd file to a per-host flie.

SSH support is more difficult, as the protocol does not include the name the client connected to. You need to instead create a new unix user account for each gitano instance, though it does not need to have a unique UID.

The examples below set up virtual hosts with appropriately set $hostname and $hostaddr.

SSH

hostdir="/var/www/host/$hostaddr"
sudo useradd --system --home-dir "$hostdir" \
             --non-unique --uid "$(id -u www-data)" \
             --gid "$(id -g www-data)" "$hostname"
sudo install -d -o "$hostname" "$hostdir"

for key in admin bypass; do
    ssh-keygen -t rsa -N '' -f "gitano-$hostname-$key"
    sudo install -o "$hostname" "gitano-$hostname-$key.pub" "$hostdir/gitano-$hostname-$key.pub"
done

sudo install -D -m 644 -o "$hostname" /proc/self/fd/0 "$hostdir/gitano-setup.conf" <<EOF
setup.batch "true"
paths.pubkey "$hostdir/gitano-$hostname-admin.pub"
paths.bypasskey "$hostdir/gitano-$hostname-bypass.pub"
site.name "Gitano for $hostname"
log.prefix "$hostname"
use.htpasswd "yes"
EOF

sudo -u "$hostname" -H gitano-setup "$hostdir/gitano-setup.conf"

Git-Daemon support

The key point is to ensure that git daemon --interpolated-path=/var/www/host/%H/repos%D is running.

How this should be achieved depends on your distributions's service manager. Some may require you to modify a file to add options.

If your distribution does not already have configuration for starting git-daemon and your distribution happens to use systemd then the configuration below may be used.

sudo install -D -m 644 /dev/stdin /etc/systemd/system/git-daemon.socket <<'EOF'
[Unit]
Description=Git Daemon Activation Socket

[Socket]
ListenStream=9418
Accept=true

[Install]
WantedBy=sockets.target
EOF
sudo install -D -m 644 /dev/stdin /etc/systemd/system/git-daemon@.service <<'EOF'
[Unit]
Description=Git Daemon

[Service]
User=www-data
Group=www-data
ExecStart=/usr/lib/git-core/git-daemon --inetd --interpolated-path=/var/www/host/%%H/repos%%D
StandardInput=socket
StandardOutput=inherit
StandardError=journal
EOF
sudo systemctl daemon-reload
sudo systemctl enable git-daemon.socket git-daemon@.service
sudo systemctl start git-daemon.socket

Smart HTTP and HTTP command support

Ensure mod_setenv is added to the set of loaded modules in /etc/lighttpd/lighttpd.conf.

sudo install -D -m 644 /proc/self/fd/0 "/etc/lighttpd/conf-available/20-gitano-http-$hostname.conf" <<EOF
\$HTTP["host"] == "$hostaddr" {
    \$HTTP["url"] =~ "^/git/.*\$" {
        alias.url += ( "/git" => "/usr/lib/gitano/bin/gitano-smart-http.cgi" )

        cgi.assign = ("" => "")
        setenv.add-environment = (
            "GIT_HTTP_EXPORT_ALL" => "",
            "GIT_PROJECT_ROOT" => "$hostdir/repos/",
            "HOME" => "$hostdir",
            "GITANO_ROOT" => "$hostdir/repos/",
        )

        auth.require = (
            "/" => (
                "method" => "basic",
                "realm" => "Git Access",
                "require" => "valid-user"
            )
        )

        auth.backend = "htpasswd"
        auth.backend.htpasswd.userfile = "$hostdir/htpasswd"

    }

    \$HTTP["url"] =~ ".*/gitano-command.cgi$" {
        alias.url += ( "/gitano-command.cgi" => "/usr/lib/gitano/bin/gitano-command.cgi" )

        cgi.assign = ("" => "")
        setenv.add-environment = (
                "HOME" => "$hostdir",
                "GITANO_ROOT" => "$hostdir/repos/"
        )

        auth.require = (
            "/" => (
                "method" => "basic",
                "realm" => "Git Access",
                "require" => "valid-user"
            )
        )

        auth.backend = "htpasswd"
        auth.backend.htpasswd.userfile = "$hostdir/htpasswd"
    }
}
EOF
cd /etc/lighttpd/conf-enabled
sudo ln -sf "../conf-available/20-gitano-http-$hostname.conf"

CGit configuration

To virtual host CGit, you need to have a different cgitrc file per virtual host, which has scan-path set to the "repos" directory for the virtual host.

sudo install -D -m 644 -o "$hostname" /proc/self/fd/0 "$hostdir/cgitrc" <<EOF
css=/cgit-css/cgit.css
logo=/cgit-css/cgit.png

cache-root=$hostdir/cache
cache-size=100

snapshots=tar.gz

enable-http-clone=1
clone-url=git://\$HTTP_HOST/\$CGIT_REPO_URL http://\$HTTP_HOST\$SCRIPT_NAME/\$CGIT_REPO_URL ssh://$hostname@\$HTTP_HOST/\$CGIT_REPO_URL http://\$HTTP_HOST/git/\$CGIT_REPO_URL

strict-export=git-daemon-export-ok
scan-path=$hostdir/repos/
EOF

This per-virtual-host cgitrc file needs to be loaded by the cgit daemon. By default cgit will only read /etc/cgitrc, but our per-virtual-host configuration can be loaded either by setting include=/var/www/host/$HTTP_HOST/cgitrc in /etc/cgitrc, or by setting the CGIT_CONFIG environment variable to this file.

The configuration for doing this in lighttpd is:

sudo install -D -m 644 /proc/self/fd/0 "/etc/lighttpd/conf-available/20-gitano-cgit-$hostname.conf" <<EOF
\$HTTP["host"] == "$hostaddr" {
    \$HTTP["url"] =~ "^/cgit" {
        \$HTTP["url"] =~ "^/cgit-css" {
            server.document-root = "/usr/share/cgit"
            alias.url += (
                "/cgit-css" => "/usr/share/cgit",
            )
        }

        \$HTTP["url"] !~ "^/cgit-css" {
            alias.url += (
                "/cgit" => "/usr/lib/cgit/cgit.cgi",
            )

            cgi.assign = ("" => "")
            setenv.add-environment = (
                "CGIT_CONFIG" => "$hostdir/cgitrc",
            )
        }
    }
}
EOF
cd /etc/lighttpd/conf-enabled
sudo ln -sf "../conf-available/20-gitano-cgit-$hostname.conf"

To test the cgit and git-daemon configuration some anonymously readable repositories need to be configured. See Anonymous Read access setup for how to enable this.

When browsing repositories it should list 4 URLs to clone the repository with.

  1. Anonymous git:// protocol.
  2. Anonymous dumb http:// protocol via /cgit.
  3. Authenticated ssh:// protocol.
  4. Authenticated smart http:// protocol.