How to Install GitLab with Nginx (SSL) on Ubuntu 16.04

GitLab is a web-based Git repository manager similar to Github. It's an open source git repository management tool powered by Ruby and Rails. It provides a .deb package which contains GitLab Community Edition and all its dependencies including Ruby, PostgreSQL, Redis, Nginx, Unicorn and other gems already compiled.

It offers three different versions. One is a hosted version of GitLab, where you can register for free and you can create as many private and public repositories as you want. it's a big advantage. The second is the ‘GitLab Community Edition’. You can operate the community edition on your own servers and it will cost you no money. It provides a possibility to automatically test and deploy your code, Last but not least, is the ‘GitLab Enterprise Edition'. It is based on top of the community edition and adds some extra features, it is mainly aimed at organizations with more than 100 users.

In this article, I'll explain on how to setup GitLab with Nginx on Ubuntu server. Firstly, you need to make sure that your server meets the basic system requirements.


It is supported in almost all Unix Operating Systems. Please see the minimum System requirements for this installation below:

  • Requires Ruby (MRI) 2.1 minimum.
  • Minimum hardware capabilities with CPU 2 cores and Memory 2GB
  • Three unicorn workers (1+ Number of CPU cores)

Let's walk through the installation steps one by one.

1. Updating APT repository packages

Firstly, we need to make sure that your server is running the latest software packages and they're up to date.

root@linoxide:~# apt-get update

Get:1 xenial-security InRelease [94.5 kB]
Hit:2 xenial InRelease
Get:3 xenial-updates InRelease [95.7 kB]
Get:4 xenial-backports InRelease [92.2 kB]
Get:5 xenial-updates/universe amd64 Packages [357 kB]
Get:6 xenial-updates/universe i386 Packages [354 kB]
Fetched 993 kB in 1s (748 kB/s)
Reading package lists... Done

root@linoxide:~# apt-get upgrade

2. Create a Git User

Next step is to create a git user to manage the git repositories in the GitLab.

root@linoxide:~# adduser --disabled-login --gecos 'GitLab' git
Adding user `git' ...
Adding new group `git' (1000) ...
Adding new user `git' (1000) with group `git' ...
Creating home directory `/home/git' ...
Copying files from `/etc/skel' ...

3. Installing  GitLab Dependency packages

As discussed before, GitLab requires a minimum of Ruby 2,x version or above. We need to install several dependency packages and development tools to install that software required for the GitLab.

root@linoxide-gitlab:~#apt-get install build-essential cmake zlib1g-dev libyaml-dev libssl-dev libgdbm-dev libreadline-dev libncurses5-dev libffi-dev curl openssh-server redis-server checkinstall libxml2-dev libxslt-dev libcurl4-openssl-dev libicu-dev logrotate

4. Installing Git

We can install Git packages from their repositories by just running this command.

root@linoxide:~# apt-get install git

5.  Setup a Mail Server

For receiving the email notifications about our Git projects, we need to configure an email server. I'm currently using PostFix to setup my mail server. You can install Postfix using this single command.

root@linoxide~# apt-get install postfix

During the  installation stages, you can select "Internet Site" and enter your FQDN server hostname to complete the installation.

6. How to install / configure Ruby

GitLab is an application purely based on Ruby on Rails. It's  having a version manager which can prevent pushing and pull over SSH. It recommends a Ruby version greater than 2.x.

root@linoxide:~# mkdir /tmp/ruby && cd /tmp/ruby
root@linoxide:/tmp/ruby# wget
root@linoxide-:/tmp/ruby# tar xvzf ruby-2.1.2.tar.gz
root@linoxide:/tmp/ruby# cd ruby-2.1.2
root@linoxide-:/tmp/ruby/ruby-2.1.2# ./configure --disable-install-rdoc --prefix=/usr/local
root@linoxide:/tmp/ruby/ruby-2.1.2# make
root@linoxide:/tmp/ruby/ruby-2.1.2# make install

You can download the supported Ruby version and compile it as above. You can confirm the Ruby version once installed.

root@linoxide:/tmp/ruby/ruby-2.1.2# ruby -v
ruby 2.1.2p95 (2014-05-08 revision 45877) [x86_64-linux]

7. Managing Database server for GitLab

Our next step is to create a database for Git lab. I'm using a PostgreSQL database to manage my Git packages. It supports both MySQL and PostgreSQL, but PostgreSQL is recommended over MySQL. You can install it with all required modules as below:

root@linoxide:~# apt-get install postgresql postgresql-client libpq-dev

We need to create a database for Gitlab. I've created a new database named "gitlabhq_production" with a user "git" to manage it.

root@linoxide:~# su - postgres
postgres@linoxide:~$ postgres createuser --createdb git
postgres@linoxide:~$ createdb --owner=git gitlabhq_production

Finally, you can confirm the DB connectivity with the new user and database name to check the PostgreSQL version using  the commands below:

root@linoxide:~# sudo -u git -H psql -d gitlabhq_production -c "SELECT VERSION()"
PostgreSQL 9.5.5 on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 5.4.0-6ubuntu1~16.04.2) 5.4.0 20160609, 64-bit
(1 row)

If the command results in the PostgreSQL version, then you're good to go.

8) Installing GitLab

Now we're ready to start with the installation. You can download the stable GitLab repository from their official repository site. I've downloaded and installed it to my git home directory.

root@linoxide:~# cd /home/git
root@linoxide-gitlab:/home/git# sudo -u git -H git clone -b 6-9-stable gitlab
Cloning into 'gitlab'...
remote: Counting objects: 392871, done.
remote: Compressing objects: 100% (101153/101153), done.
remote: Total 392871 (delta 309481), reused 367895 (delta 286998)
Receiving objects: 100% (392871/392871), 184.55 MiB | 38.25 MiB/s, done.
Resolving deltas: 100% (309481/309481), done.
Checking connectivity... done.

You can select any stable repo branch from there. Here, I've downloaded  6-9-stable branch from the GitLab repository. The important thing to note is that we should never install the Master branch on a production server.

9) Configuring GitLab

Move to your git home directory and copy the sample GitLab configuration file to use it as the main configuration file "gitlab.yml".

root@linoxide:/home/git/gitlab# sudo -u git -H cp config/gitlab.yml.example config/gitlab.yml

You need to modify the host to a fully-qualified domain of your server. Furthermore, set the email_from and support_email to the preferred email addresses for GitLab in the configuration file.

root@linoxide-gitlab:/home/git/gitlab#cat /home/git/gitlab/config/gitlab.yml
production: &base
port: 80
https: false

Next, we need to correct the ownerships and permissions for the folders to make it work as required. Certain files/folders needed write permissions so that GitLab can write to them as and when needed.

root@linoxide:/home/git/gitlab# chown -R git {log,tmp}
root@linoxide:/home/git/gitlab# chmod -R u+rwX {log,tmp,tmp/pids,tmp/sockets,public/uploads}

Create the Satellite folders and copy the examples of the unicorn and Rack attack configurations:

root@linoxide:/home/git/gitlab# sudo -u git -H mkdir /home/git/gitlab-satellites
root@linoxide:/home/git/gitlab# sudo chmod u+rwx,g+rx,o-rwx /home/git/gitlab-satellites

root@linoxide:/home/git/gitlab# sudo -u git -H cp config/unicorn.rb.example config/unicorn.rb
root@linoxide:/home/git/gitlab# sudo -u git -H cp config/initializers/rack_attack.rb.example config/initializers/rack_attack.rb

10) Database Configuration

The next step is to configure the DB settings, we've to use PostgreSQL for our database. We need to copy the configuration file and change the permissions to make it readable to git:

root@linoxide:/home/git/gitlab# sudo -u git cp config/database.yml.postgresql config/database.yml
root@linoxide:/home/git/gitlab# sudo -u git -H chmod o-rwx config/database.yml

11) Installing Gems

root@linoxide:/home/git/gitlab# sudo gem install bundler
Fetching: bundler-1.13.6.gem (100%)
Successfully installed bundler-1.13.6
Parsing documentation for bundler-1.13.6
Installing ri documentation for bundler-1.13.6
Done installing documentation for bundler after 7 seconds
1 gem installed
root@linoxide-gitlab:/home/git/gitlab# sudo -u git -H bundle install --deployment --without development test mysql aws

12) Installing GitLab shell

You can install GitLab shell which is an SSH access and repository management software for GitLab.

root@linoxide:/home/git/gitlab# sudo -u git -H bundle exec rake gitlab:shell:install[v1.9.4] REDIS_URL=redis://localhost:6379 RAILS_ENV=production

git clone '' '/home/git/gitlab-shell/'
Cloning into '/home/git/gitlab-shell'...
remote: Counting objects: 3207, done.
remote: Compressing objects: 100% (1203/1203), done.
remote: Total 3207 (delta 2043), reused 3013 (delta 1885)
Receiving objects: 100% (3207/3207), 481.86 KiB | 0 bytes/s, done.
Resolving deltas: 100% (2043/2043), done.
Checking connectivity... done.

Now we need to edit the gitlab shell configuration file with the exact gitlab URL.

root@linoxide:/home/git/gitlab# cat /home/git/gitlab-shell/config.yml
user: git
self_signed_cert: false
repos_path: "/home/git/repositories/"
auth_file: "/home/git/.ssh/authorized_keys"
bin: "/usr/bin/redis-cli"
host: localhost
port: 6379
namespace: resque:gitlab
log_level: INFO
audit_usernames: false

13) Initialize database and activate GitLab

Now, move back to your GitLab home directory and execute this command.

root@linoxide-:/home/git/gitlab# sudo -u git -H bundle exec rake gitlab:setup RAILS_ENV=production

This will create the necessary database tables and seed the database.
You will lose any previous data stored in the database.
Do you want to continue (yes/no)? Do you want to continue (yes/no)? yes

Adding limits to schema.rb for mysql

== Seed from /home/git/gitlab/db/fixtures/production/001_admin.rb
2016-11-09T06:04:38Z 17990 TID-gtc2554j8 INFO: Sidekiq client with redis options {:url=>"redis://localhost:6379", :namespace=>"resque:gitlab"}

Administrator account created:

You can use this administrator login credentials to access your GitLab interface.

14) Configure the init script

We can copy GitLab init from GitLab installation directory and add GitLab to start at boot time with update-rc.d command:

root@linoxide-:/home/git/gitlab# cp lib/support/init.d/gitlab /etc/init.d/gitlab
root@linoxide-:/home/git/gitlab# update-rc.d gitlab defaults 21

Secondly, copy the GitLab logrotate configuration for log management.

root@linoxide-gitlab:/home/git/gitlab# cp lib/support/logrotate/gitlab /etc/logrotate.d/gitlab

And finally,  check the application status and compile assets, configure Git global settings for the git user and start the GitLab service if everything seems good.

root@linoxide-:/home/git/gitlab# sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production

System information
System: Ubuntu 16.04
Current User: git
Using RVM: no
Ruby Version: 2.1.2p95
Gem Version: 2.2.2
Bundler Version:1.13.6
Rake Version: 10.3.1
Sidekiq Version:2.17.0

GitLab information
Version: 6.9.2
Revision: e46b644
Directory: /home/git/gitlab
DB Adapter: postgresql
SSH Clone URL:
Using LDAP: no
Using Omniauth: no

GitLab Shell
Version: 1.9.4
Repositories: /home/git/repositories/
Hooks: /home/git/gitlab-shell/hooks/
Git: /usr/bin/git

Compile status :
root@linoxide-gitlab:/home/git/gitlab# sudo -u git -H bundle exec rake assets:precompile RAILS_ENV=production

Configure Git global settings:
root@linoxide-gitlab:/home/git/gitlab# sudo -u git -H git config --global "GitLab"
root@linoxide-gitlab:/home/git/gitlab# sudo -u git -H git config --global ""
root@linoxide-gitlab:/home/git/gitlab# sudo -u git -H git config --global core.autocrlf input

Service start:

root@linoxide-gitlab:/home/git/gitlab# service gitlab start
root@linoxide-gitlab:/home/git/gitlab# service gitlab status
● gitlab.service - LSB: GitLab git repository management
Loaded: loaded (/etc/init.d/gitlab; bad; vendor preset: enabled)
and running.
Nov 09 06:13:23 linoxide-gitlab systemd[1]: Started LSB: GitLab git repository management.

15) Install and Configure Nginx

Nginx is the only supported Web server for GitLab. Here we're using Nginx to handle the browser requests. We can install Nginx with the command below:

root@linoxide-:/home/git/gitlab# apt-get install nginx -y

Now we can copy the Nginx virtual host configuration from the GitLab directory and remove default Nginx default virtual host and restart the Nginx service.

root@linoxide-:/home/git/gitlab# cp lib/support/nginx/gitlab /etc/nginx/sites-available/gitlab
root@linoxide:/home/git/gitlab# rm -f /etc/nginx/sites-enabled/default

Make sure to edit the server name with the GitLab domain. Create a symlink to activate the GitLab virtual host and restart the Nginx service.

root@linoxide:/home/git/gitlab# ln -s /etc/nginx/sites-available/gitlab /etc/nginx/sites-enabled/gitlab
root@linoxide:/home/git/gitlab# service nginx restart

16) Securing GitLab

In order to secure GitLab, we can install SSL for the GitLab domain and enable SSL for the Nginx Virtual host. I've installed SSL for my GitLab domain using letsencrypt and added to the virtual host.

root@linoxide:~/letsencrypt# ./letsencrypt-auto certonly --standalone --email <your email> --agree-tos -d

- Congratulations! Your certificate and chain have been saved at
/etc/letsencrypt/live/ Your cert will
expire on 2017-02-07. To obtain a new or tweaked version of this
certificate in the future, simply run letsencrypt-auto again. To
non-interactively renew *all* of your certificates, run
"letsencrypt-auto renew"
- If you lose your account credentials, you can recover through
e-mails sent to
- Your account credentials have been saved in your Certbot
configuration directory at /etc/letsencrypt. You should make a
secure backup of this folder now. This configuration directory will
also contain certificates and private keys obtained by Certbot so
making regular backups of this folder is ideal.
- If you like Certbot, please consider supporting our work by:

Donating to ISRG / Let's Encrypt:
Donating to EFF:

I've added this generated SSL to my GitLab Virtual host. This is how it looks now.

root@linoxide:~# cat /etc/nginx/sites-enabled/gitlab
# Maintainer: @randx

# It is a known issue that Git-over-HTTP requires chunked transfer encoding [0] which is not
# supported by Nginx < 1.3.9 [1]. As a result, pushing a large object with Git (i.e. a single large file)
# can lead to a 411 error. In theory you can get around this by tweaking this configuration file and either
# - installing an old version of Nginx with the chunkin module [2] compiled in, or
# - using a newer version of Nginx.
# At the time of writing we do not know if either of these theoretical solutions works. As a workaround
# users can use Git over SSH to push large files.
# [0]
# [1]
# [2]

upstream gitlab {
server unix:/home/git/gitlab/tmp/sockets/gitlab.socket;

server {
listen *:80 default_server; # e.g., listen; In most cases *:80 is a good idea
server_name; # e.g., server_name;
server {
listen 443 ssl;

ssl_certificate /etc/letsencrypt/live/;
ssl_certificate_key /etc/letsencrypt/live/;
server_tokens off; # don't show the version number, a security best practice
root /home/git/gitlab/public;

# Increase this if you want to upload large attachments
# Or if you want to accept large git objects over http
client_max_body_size 20m;

# individual nginx logs for this gitlab vhost
access_log /var/log/nginx/gitlab_access.log;
error_log /var/log/nginx/gitlab_error.log;

location / {
# serve static files from defined root folder;.
# @gitlab is a named location for the upstream fallback, see below
try_files $uri $uri/index.html $uri.html @gitlab;

# if a file, which is not found in the root folder is requested,
# then the proxy pass the request to the upsteam (gitlab unicorn)
location @gitlab {
# If you use https make sure you disable gzip compression
# to be safe against BREACH attack
# gzip off;

proxy_read_timeout 300; # Some requests take more than 30 seconds.
proxy_connect_timeout 300; # Some requests take more than 30 seconds.
proxy_redirect off;

proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

proxy_pass http://gitlab;

# Enable gzip compression as per rails guide:
# WARNING: If you are using relative urls do remove the block below
# See config/application.rb under "Relative url support" for the list of
# other files that need to be changed for relative url support
location ~ ^/(assets)/ {
root /home/git/gitlab/public;
gzip_static on; # to serve pre-gzipped version
expires max;
add_header Cache-Control public;

error_page 502 /502.html;

After making these changes restart the GitLab and Nginx services.

17) Accessing GitLab via Browser

Finally, we are ready to access our GitLab interface via a browser. Before launching it, double check the GitLab application status to confirm everything goes fine.

root@linoxide:/home/git# cd gitlab
oot@linoxide:/home/git/gitlab#sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production

If everything is fine, you can just access your GitLab application by calling the URL >>https://GitLAB-domain-name. In my case, I've installed it on You can access it by using the administrator credentials created during installation, user: or root

Gitlab Login page

You can reset your password to the desired one on login. Let's start building our git projects :)

GitLab Dashboard


GitLab is one of the best solutions to start building your own Git repository server.  It's very easy to install and configure and we can manage it efficiently using its excellent interface. This is used by more 100.000 technology companies. Moreover, it is a powerful software that helps developers to build applications together with other developers. I hope you enjoyed reading this article. Please post your valuable comments and suggestions on this.

Leave a Comment