A working Gitlab configuration using Unicorn and Apache Proxy

Problem:

You want to setup gitlab using Apache and unicorn (no passenger!), but it doesn’t work, no matter how hard you try.

Solution:

You’re not alone with your problem. Even if there are numerous nice tutorials on the internet, none worked for me.

My final setup includes a common user for gitolite (gitolite3 seems to be neccessary, installed into /var/lib/gitolite under user gitolite) and a clone of stable gitlabhq into /opt/gitlabhq. I assume you already followed the inofficial and official guides and the database, as well as gitolite, is properly setup.

There are numerous different ways to setup gitlabhq, including those involving mod_passenger. I suppose they are more memory-efficient than others, but I could’n get it to work.

Here is my /etc/init.d/gitlab:

#! /bin/bash
### BEGIN INIT INFO
# Provides: gitlab
# Required-Start: $local_fs $remote_fs $network $syslog redis-server
# Required-Stop: $local_fs $remote_fs $network $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: GitLab git repository management
# Description: GitLab git repository management
### END INIT INFO

DAEMON_OPTS="-c /opt/gitlabhq/config/unicorn.rb -E production -D"
NAME=unicorn
DESC="Gitlab service"
PID=/opt/gitlabhq/tmp/pids/unicorn.pid
RESQUE_PID=/opt/gitlabhq/tmp/pids/resque_worker.pid

case "$1" in
start)
CD_TO_APP_DIR="cd /opt/gitlabhq"
START_DAEMON_PROCESS="bundle exec unicorn_rails $DAEMON_OPTS"
START_RESQUE_PROCESS="./resque.sh"

echo -n "Starting $DESC: "
if [ `whoami` = root ]; then
sudo -u gitolite sh -l -c "$CD_TO_APP_DIR > /dev/null 2>&1 && $START_DAEMON_PROCESS && $START_RESQUE_PROCESS"
else
$CD_TO_APP_DIR > /dev/null 2>&1 && $START_DAEMON_PROCESS && $START_RESQUE_PROCESS
fi
echo "$NAME."
;;
stop)
echo -n "Stopping $DESC: "
kill -QUIT `cat $PID`
kill -QUIT `cat $RESQUE_PID`
echo "$NAME."
;;
restart)
echo -n "Restarting $DESC: "
kill -USR2 `cat $PID`
kill -USR2 `cat $RESQUE_PID`
echo "$NAME."
;;
reload)
echo -n "Reloading $DESC configuration: "
kill -HUP `cat $PID`
kill -HUP `cat $RESQUE_PID`
echo "$NAME."
;;
*)
echo "Usage: $NAME {start|stop|restart|reload}" >&2
exit 1
;;
esac
exit 0

Here is my .gitolite.rc

# configuration variables for gitolite

# This file is in perl syntax.  But you do NOT need to know perl to edit it --
# just mind the commas, use single quotes unless you know what you're doing,
# and make sure the brackets and braces stay matched up!

# (Tip: perl allows a comma after the last item in a list also!)

# HELP for commands (see COMMANDS list below) can be had by running the
# command with "-h" as the sole argument.

# HELP for all the other external programs (the syntactic sugar helpers and
# the various programs/functions in the 8 trigger lists), can be found in
# doc/non-core.mkd (http://sitaramc.github.com/gitolite/non-core.html) or in
# the corresponding source file itself.

%RC = (
    # if you're using mirroring, you need a hostname.  This is *one* simple
    # word, not a full domain name.  See documentation if in doubt
    # HOSTNAME                  =>  'darkstar',
    UMASK                       =>  0007,

    # look in the "GIT-CONFIG" section in the README for what to do
    GIT_CONFIG_KEYS             =>  '.*',

    # comment out if you don't need all the extra detail in the logfile
    LOG_EXTRA                   =>  1,

    # settings used by external programs; uncomment and change as needed.  You
    # can add your own variables for use in your own external programs; take a
    # look at the info and desc commands for perl and shell samples.

    # used by the CpuTime trigger
    # DISPLAY_CPU_TIME          =>  1,
    # CPU_TIME_WARN_LIMIT       =>  0.1,
    # used by the desc command
    # WRITER_CAN_UPDATE_DESC    =>  1,
    # used by the info command
    # SITE_INFO                 =>  'Please see http://blahblah/gitolite for more help',

    # add more roles (like MANAGER, TESTER, ...) here.
    #   WARNING: if you make changes to this hash, you MUST run 'gitolite
    #   compile' afterward, and possibly also 'gitolite trigger POST_COMPILE'
    ROLES                       =>
        {
            READERS             =>  1,
            WRITERS             =>  1,
        },
    # uncomment (and change) this if you wish
    # DEFAULT_ROLE_PERMS          =>  'READERS @all',

    # comment out or uncomment as needed
    # these are available to remote users
    COMMANDS                    =>
        {
            'help'              =>  1,
            'desc'              =>  1,
            # 'fork'            =>  1,
            'info'              =>  1,
            # 'mirror'          =>  1,
            'perms'             =>  1,
            # 'sskm'            =>  1,
            'writable'          =>  1,
            # 'D'               =>  1,
        },

    # comment out or uncomment as needed
    # these will run in sequence during the conf file parse
    SYNTACTIC_SUGAR             =>
        [
            # 'continuation-lines',
            # 'keysubdirs-as-groups',
        ],

    # comment out or uncomment as needed
    # these will run in sequence to modify the input (arguments and environment)
    INPUT                       =>
        [
            # 'CpuTime::input',
            # 'Shell::input',
            # 'Alias::input',
            # 'Mirroring::input',
        ],

    # comment out or uncomment as needed
    # these will run in sequence just after the first access check is done
    ACCESS_1                    =>
        [
        ],

    # comment out or uncomment as needed
    # these will run in sequence just before the actual git command is invoked
    PRE_GIT                     =>
        [
            # 'renice 10',
            # 'Mirroring::pre_git',
            # 'partial-copy',
        ],

    # comment out or uncomment as needed
    # these will run in sequence just after the second access check is done
    ACCESS_2                    =>
        [
        ],

    # comment out or uncomment as needed
    # these will run in sequence after the git command returns
    POST_GIT                    =>
        [
            # 'Mirroring::post_git',
            # 'CpuTime::post_git',
        ],

    # comment out or uncomment as needed
    # these will run in sequence before a new wild repo is created
    PRE_CREATE                  =>
        [
        ],

    # comment out or uncomment as needed
    # these will run in sequence after a new repo is created
    POST_CREATE                 =>
        [
            'post-compile/update-git-configs',
            'post-compile/update-gitweb-access-list',
            'post-compile/update-git-daemon-access-list',
        ],

    # comment out or uncomment as needed
    # these will run in sequence after post-update
    POST_COMPILE                =>
        [
            'post-compile/ssh-authkeys',
            'post-compile/update-git-configs',
            'post-compile/update-gitweb-access-list',
            'post-compile/update-git-daemon-access-list',
        ],
);

# ------------------------------------------------------------------------------
# per perl rules, this should be the last line in such a file:
1;

# Local variables:
# mode: perl
# End:
# vim: set syn=perl:

This is my gitlab.yml

# # # # # # # # # # # # # # # # # #
# Gitlab application config file  #
# # # # # # # # # # # # # # # # # #

#
# 1. Common settings
# ==========================

# Web application specific settings
web:
  host: localhost
  port: 80
  https: false

# Email used for notification
# about new issues, comments
email:
  from: [email protected]
  to: btronik.de
  protocol: https

# Application specific settings
# Like default project limit for user etc
app:
  default_projects_limit: 10
  # backup_path: "/vol/backups"   # default: Rails.root + backups/
  # backup_keep_time: 604800      # default: 0 (forever) (in seconds)
  # disable_gravatar: true        # default: false - Disable user avatars from Gravatar.com

#
# 2. Auth settings
# ==========================
ldap:
  enabled: false
  host: '_your_ldap_server'
  base: '_the_base_where_you_search_for_users'
  port: 636
  uid: 'sAMAccountName'
  method: 'ssl' # plain
  bind_dn: '_the_full_dn_of_the_user_you_will_bind_with'
  password: '_the_password_of_the_bind_user'

omniauth:
  # Enable ability for users
  # to login via twitter, google ..
  enabled: false

  # IMPORTANT!
  # It allows user to login without having user account
  allow_single_sign_on: false
  block_auto_created_users: true

  # Auth providers
  providers:
    # - { name: 'google_oauth2', app_id: 'YOUR APP ID',
    #     app_secret: 'YOUR APP SECRET',
    #     args: { access_type: 'offline', approval_prompt: '' } }
    # - { name: 'twitter', app_id: 'YOUR APP ID',
    #     app_secret: 'YOUR APP SECRET'}
    # - { name: 'github', app_id: 'YOUR APP ID',
    #     app_secret: 'YOUR APP SECRET' }

#
# 3. Advanced settings:
# ==========================

# Git Hosting configuration
git_host:
  admin_uri: [email protected]:gitolite-admin
  base_path: /var/lib/gitolite/repositories/
  hooks_path: /var/lib/gitolite/.gitolite/hooks/
  gitolite_admin_key: gitlab
  git_user: gitolite
  upload_pack: true
  receive_pack: true
  host: btronik.de
  # config_file: gitolite.conf
  # port: 22

# Git settings
# Use default values unless you understand it
git:
  path: /usr/bin/git
  # Max size of git object like commit, in bytes
  # This value can be increased if you have a very large commits
  git_max_size: 5242880 # 5.megabytes
  # Git timeout to read commit, in seconds
  git_timeout: 10

And, finally, my Apache2 Virtual Host config. Note that I configure gitlab on port 3001 to keep port 8080 free for other applications:

<VirtualHost *:80>
    ServerName gitlab.mydomain.de
    #Do not redirect to HTTPS
    ErrorLog /var/log/apache2/owncloud_error.log
    RewriteEngine On
    RewriteCond %{HTTPS} off
    RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
</VirtualHost>
<VirtualHost *:443>
  ServerName gitlab.mydomain.de
  DocumentRoot /opt/gitlabhq/public
  ErrorLog /var/log/apache2/gitlab-error.log
  CustomLog /var/log/apache2/gitlab-access.log combined

  SSLEngine on
  SSLCertificateFile /etc/apache2/ssl.crt/btronik-wildcardcert.pem
  SSLCertificateKeyFile /etc/apache2/ssl.crt/btronik-wildcardkey.pem
  SSLCACertificateFile /etc/apache2/ssl.crt/ca.pem

      # the following allows "nice" urls such as https://etherpad.example.org/padname
            ProxyVia On
            ProxyRequests Off
            ProxyPass / http://127.0.0.1:3001/
            ProxyPassReverse / http://127.0.0.1:3001/
            ProxyPreserveHost on
            <Proxy *>
                Options FollowSymLinks MultiViews
                AllowOverride All
                Order allow,deny
                allow from all
            </Proxy>

</VirtualHost>