Run GitLab in Docker Containers using Docker Compose

Posted on 108 views

GitLab is a web-based platform used to host Git repositories. This tool supports software development using the Continuous Delivery(CD) and Continuous Integration(CI) processes. The GitLab Enterprise Edition builds on top of Git with extra features such as LDAP group sync, multiple roles, and audit logs. It also includes authorization integration with deeper authentication.

The amazing features associated with GitLab are:

  • Easy integration with Jenkins, Docker, Slack, Kubernetes, JIRA, LDAP e.t.c
  • Code Quality (Code Climate)
  • On-premise or cloud-based installations
  • Development Analytics
  • Performance monitoring
  • Rich API
  • Integration with IDEs like Eclipse, Visual Studio, Koding, and IntelliJ
  • Issue management, bug tracking, and boards
  • Repository mirroring and high availability (HA)
  • Hosting static websites (GitLab Pages)
  • ChatOp tool (Mattermost)
  • Code Review functionality and Review Apps tool
  • Service Desk (ticketing system)

The GitLab system is made up of several distinct components and dependencies. When installing GitLab directly on your system, these components are installed as well. They include Redis, Gitaly, PostgreSQL, and the GitLab application itself. To avoid these components from being populated into your environment, using Docker containers is the preferred installation method. This ensures that all the components live within a single container away from the filesystem of the host.

In this guide, we will walk through how to run GitLab in Docker Containers using Docker Compose.

Setup Pre-requisites

For this guide you need the following:

  • 1GB or more of available RAM on the host
  • Docker and Docker-compose
  • A fully Qualified Domain name(For SSL certificates)

But before you begin, update your system and install the required tools:

## On Debian/Ubuntu
sudo apt update && sudo apt upgrade
sudo apt install curl vim git

## On RHEL/CentOS/RockyLinux 8
sudo yum -y update
sudo yum -y install curl vim git

## On Fedora
sudo dnf update
sudo dnf -y install curl vim git

#1. Install Docker and Docker Compose on Linux

Begin by installing the Docker engine on your system. Below is a dedicated guide to help you install docker on your system

Once docker has been installed, start and enable the service.

sudo systemctl start docker && sudo systemctl enable docker

Add your system user to the docker group.

sudo usermod -aG docker $USER
newgrp docker

Now proceed and install Docker compose with aid of the below guide.

Another easy way of installing Docker Dev release is with the script below:

sudo apt update && sudo apt install curl uidmap -y
curl -fsSL -o
sudo sh install

#2. Provisioning the GitLab Container

We will begin by pulling the docker-compose.yml file for the deployment.


You need to generate 3 random strings at least 64 characters long to be used for:

  • GITLAB_SECRETS_OTP_KEY_BASE: this is used to encrypt 2FA secrets in the database
  • GITLAB_SECRETS_DB_KEY_BASE: used for CI secret variables encryption and importing variables into the database.
  • GITLAB_SECRETS_SECRET_KEY_BASE: it is used for password reset links as well as other ‘standard’ auth features.

These strings can be generated using pwgen installed as with the commands:

##On Debian/Ubuntu
sudo apt install -y pwgen

##On RHEL/CentOS/RockyLinux 8
sudo yum install epel-release -y
sudo yum install pwgen -y

## On Fedora
sudo dnf install -y pwgen

Generate random strings with the command:

pwgen -Bsv1 64

Edit the file and add the strings appropriately, the deployment file has 3 containers i.e Redis, PostgreSQL, and GitLab. Open the file for editing.

vim docker-compose.yml

Make the below changes as desired.

  • PostgreSQL container

Configure your database as preferred. You need to set the database password.

    restart: always
    - postgresql-data:/var/lib/postgresql:Z
    - DB_USER=gitlab
    - DB_PASS=StrongDBPassword
    - DB_NAME=gitlab_production
    - DB_EXTENSION=pg_trgm,btree_gist
  • GitLab Container

Proceed and provide database details, and set the health check appropriately in the GitLab container.

    restart: always
    image: sameersbn/gitlab:14.10.2
    - redis
    - postgresql
    - "10080:80"
    - "10022:22"
    - gitlab-data:/home/git/data:Z
      test: curl http://localhost/-/health || exit 1
      interval: 1m
      timeout: 10s
      retries: 3
      start_period: 1m
    - DEBUG=false

    - DB_ADAPTER=postgresql
    - DB_HOST=postgresql
    - DB_PORT=5432
    - DB_USER=gitlab
    - DB_PASS=StrongDBPassword
    - DB_NAME=gitlab_production

Also update Timezone variables

    - TZ=Africa/Nairobi

Under the GitLab container, you can add HTTPS support by making the below settings. If you do not have an FQDN, enable self-signed certificates as well.

    - GITLAB_HTTPS=true

If you are using self-signed certificates, you need to enable this as well.

    - SSL_SELF_SIGNED=true

Proceed and provide the random strings. Remember to set the GITLAB_HOST and remove the GITLAB_PORT. This is done because we will configure reverse proxy later.

    - GITLAB_SSH_PORT=10022
    - GITLAB_SECRETS_DB_KEY_BASE=long-and-random-alphanumeric-string
    - GITLAB_SECRETS_SECRET_KEY_BASE=long-and-random-alphanumeric-string
    - GITLAB_SECRETS_OTP_KEY_BASE=long-and-random-alphanumeric-string

Set the GitLab user email and password.

    - GITLAB_ROOT_PASSWORD=StrongPassw0rd
    - GITLAB_ROOT_EMAIL=[email protected]

You can also enable SMTP support by making the desired settings.

   - SMTP_ENABLED=true
    - SMTP_PORT=587
    - [email protected]
    - SMTP_PASS=password
    - SMTP_STARTTLS=true

There are many other configurations you can make to this container. These settings include the Timezone, OAUTH, IMAP e.t.c

#3. Configure Persistent Volumes

For data persistent, we have to map the volumes appropriately. The docker-compose.yml file has 3 volumes. Here, we will use a secondary disk mounted on our system for data persistence.

Identify the disk.

$ lsblk
sda           8:0    0  40G  0 disk 
├─sda1        8:1    0   1G  0 part /boot
└─sda2        8:2    0  39G  0 part 
  ├─rl-root 253:0    0  35G  0 lvm  /
  └─rl-swap 253:1    0   4G  0 lvm  [SWAP]
sdb           8:16   0  10G  0 disk 
└─sdb1        8:17   0  10G  0 part 

Ensure the disk is formatted before you proceed to mount it as shown.

sudo mkdir /mnt/data
sudo mount /dev/sdb1 /mnt/data

Confirm if the disk has been mounted on the desired path.

$ sudo mount | grep /dev/sdb1
/dev/sdb1 on /mnt/data type xfs (rw,relatime,seclabel,attr2,inode64,logbufs=8,logbsize=32k,noquota)

Create the 3 volumes in the disk.

sudo mkdir -p /mnt/data/redis
sudo mkdir -p /mnt/data/postgresql
sudo mkdir -p /mnt/data/gitlab

Set the appropriate file permissions.

sudo chmod 775 -R /mnt/data
sudo chown -R $USER:docker /mnt/data

On Rhel-based systems, you need to configure SELinux as below for the paths to be accessible.

sudo setenforce 0
sudo sed -i 's/^SELINUX=.*/SELINUX=permissive/g' /etc/selinux/config

Now create the docker volumes for the containers.

  • Redis
docker volume create --driver local \
     --opt type=none \
     --opt device=/mnt/data/redis \
     --opt o=bind redis-data
  • PostgreSQL
docker volume create --driver local \
     --opt type=none \
     --opt device=/mnt/data/postgresql \
     --opt o=bind postgresql-data
  • GitLab
docker volume create --driver local \
     --opt type=none \
     --opt device=/mnt/data/gitlab \
     --opt o=bind gitlab-data

Once created, list the volumes with the command:

$ docker volume list
local     gitlab-data
local     postgresql-data
local     redis-data

Now in the YAML file, add these lines at the bottom.

$ vim docker-compose.yml 
    external: true
    external: true
    external: true

#4. Bringing up GitLab.

After the desired configurations have been made, bring up the containers with the command:

docker-compose up -d

Sample execution output:

[+] Running 23/28
 ⠇ gitlab Pulling                                                                                                                     33.9s
   ⠿ d5fd17ec1767 Pull complete                                                                                                        8.0s
   ⠿ 2cbc1a21dc95 Pull complete                                                                                                        9.3s
   ⠿ e3cf021c7259 Pull complete                                                                                                       25.0s
   ⠿ c55daad7c782 Pull complete                                                                                                       25.2s
⠿ redis Pulled                                                         24.4s
   ⠿ 1fe172e4850f Pull complete                                         17.6s
   ⠿ 6fbcd347bf99 Pull complete                                         18.1s
   ⠿ 993114c67627 Pull complete                                         18.9s
   ⠿ 2a560260ca39 Pull complete                                         20.5s
   ⠿ b7179886a292 Pull complete                                         20.8s
⠿ postgresql Pulled                                                    21.4s
   ⠿ 23884877105a Pull complete                                          2.6s
   ⠿ bc38caa0f5b9 Pull complete                                          2.8s
   ⠿ 2910811b6c42 Pull complete                                          3.1s
   ⠿ 36505266dcc6 Pull complete                                          3.5s

Verify if the containers are running:

$ docker ps
CONTAINER ID   IMAGE                              COMMAND                  CREATED          STATUS                    PORTS                                                                                       NAMES
f5e238c85afb   sameersbn/gitlab:14.10.2           "/sbin/…"   2 minutes ago   Up 2 minutes (healthy)   443/tcp,>22/tcp, :::10022->22/tcp,>80/tcp, :::10080->80/tcp   ubuntu-gitlab-1
c4113ccccc8a   sameersbn/postgresql:12-20200524   "/sbin/"    2 minutes ago   Up 2 minutes             5432/tcp                                                                                    ubuntu-postgresql-1
a352f63cdea5   redis:6.2.6                        "docker-entrypoint.s…"   2 minutes ago   Up 2 minutes             6379/tcp                                                                                    ubuntu-redis-1

#5. Secure GitLab with SSL Certificates.

We need to secure the site with SSL so as to prevent unauthorized access to your data. With the GITLAB_HTTPS option enabled, you can generate certificates for your domain name. Normally, the container looks for the certificates in the volume that belongs to the GitLab container.

However, in this guide, we will configure the Nginx reverse proxy for HTTPS. First, install Nginx on your system.

##On RHEL/CentOS/Rocky Linux 8
sudo yum install nginx

##On Debian/Ubuntu
sudo apt install nginx

Create a virtual host file as shown.

sudo vim /etc/nginx/conf.d/gitlab.conf

Add the below lines to the file.

        listen 80;
        client_max_body_size 0;
        chunked_transfer_encoding on;

    location / 
      proxy_pass http://localhost:10080/;
      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_set_header X-Forwarded-Proto $scheme;
      proxy_set_header X-Forwarded-Ssl on;

      proxy_buffering off;
      proxy_request_buffering off;

Save the file, restart and enable Nginx.

sudo systemctl restart nginx
sudo systemctl enable nginx

Option1 – Using Self Signed Certificate

The certificate pair is generated using openSSL. Begin by generating the private key.

openssl genrsa -out gitlab.key 2048

Create a certificate signing request(CSR).

openssl req -new -key gitlab.key -out gitlab.csr

Sign the certificate using the CSR and private key.

openssl x509 -req -days 3650 -in gitlab.csr -signkey gitlab.key -out gitlab.crt

After this, you will have a self-signed certificate generated. For more security, you need to create more robust DHE parameters.

openssl dhparam -out dhparam.pem 2048

Now you will have 3 files, gitlab.keygitlab.crt and dhparam.pem. Copy these files to the certificates directory.

sudo cp gitlab.crt /etc/ssl/certs/gitlab.crt
sudo mkdir -p /etc/ssl/private/
sudo cp gitlab.key /etc/ssl/private/gitlab.key
sudo cp dhparam.pem /etc/ssl/certs/dhparam.pem

Now edit your Nginx config to accommodate the certificates.

        client_max_body_size 0;
        chunked_transfer_encoding on;

    location / 
      proxy_pass http://localhost:10080/;
      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_set_header X-Forwarded-Proto $scheme;
      proxy_set_header X-Forwarded-Ssl on;

      proxy_buffering off;
      proxy_request_buffering off;

    listen 443 ssl;
    ssl_certificate /etc/ssl/certs/gitlab.crt;
    ssl_certificate_key /etc/ssl/private/gitlab.key;
    ssl_dhparam /etc/ssl/certs/dhparam.pem;

    if ($host = 
        return 301 https://$host$request_uri;

        listen 80;
    return 404;

To establish trust with the server, the client needs to copy the gitlab.crt to the list of trusted certificates. Normally at /usr/local/share/ca-certificates/ for Ubuntu and /etc/pki/ca-trust/source/anchors/ for CentOS. Once done, update the certificates:

##On Ubuntu/Debian
sudo update-ca-certificates

##On CentOS/Rocky Linux
sudo update-ca-trust extract

This is done to avoid the error below during git clone on the client.

$ git clone
Cloning into 'my-android-project'...
fatal: unable to access '': SSL certificate problem: self signed certificate

Option 2 – Using Let’s Encrypt

This requires one to have a Fully Qualified Domain Name(FQDN). Here, we will use a reverse proxy(Nginx) Begin by installing the required packages.

##On RHEL 8/CentOS/Rocky Linux 8/Fedora
sudo dnf install 
sudo dnf install certbot python3-certbot-nginx

##On Debian/Ubuntu
sudo apt install certbot python3-certbot-nginx

Generate SSL certificates for your domain name using the command:

sudo certbot --nginx

Proceed and issue certificates for the domain name.

Which names would you like to activate HTTPS for?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate numbers separated by commas and/or spaces, or leave input
blank to select all options shown (Enter 'c' to cancel): 1

Requesting a certificate for
Performing the following challenges:
http-01 challenge for
Waiting for verification...
Cleaning up challenges

Restart Nginx.

sudo systemctl restart nginx

#6. Access GitLab Web UI.

Now proceed and access GitLab via HTTPS. If you have a firewall enabled, allow the port/service through it.

##For UFW
sudo ufw allow 443/tcp

##For Firewalld
sudo firewall-cmd --add-service=http --permanent
sudo firewall-cmd --add-service=https --permanent
sudo firewall-cmd --reload

Now proceed and access the page using the URL https://domain_name


Login using the created credentials. On successful login, you will see this dashboard.


Set if you want the account to be used by everyone or for personal use by setting who to register for an account. Once configured, proceed and create a new project by clicking on “New Project“.


Here, I will deploy a project from a template as shown.


Once created, the project will appear as shown.


You can proceed and add SSH keys for easier management. To confirm if everything is set up accordingly, we will try and git clone the repository. Click on clone to obtain the desired URL. Since I do not have SSH keys, I will proceed to use HTTPS as shown.



That verifies that the GitLab installation is working as preferred.

#7. Cleanup

To remove the GitLab installation and all the persistent data, use the command:

$ docker-compose down -v
[+] Running 4/4
 ⠿ Container admin-gitlab-1      Removed                                                                                              13.5s
 ⠿ Container admin-redis-1       Removed                                                                                               0.7s
 ⠿ Container admin-postgresql-1  Removed                                                                                               0.5s
 ⠿ Network admin_default         Removed                                                                                               0.4s

Closing Thoughts.

We have triumphantly walked through how to run GitLab in Docker Containers using Docker Compose. Now you have a GitLab installation from which you can host Git repositories. I hope this was significant.


Gravatar Image
A systems engineer with excellent skills in systems administration, cloud computing, systems deployment, virtualization, containers, and a certified ethical hacker.