How to install and configure GitLab CE/EE on Debian 11

Updated on June 9, 2022
How to install and configure GitLab CE/EE on Debian 11  header image


GitLab is a popular self-hostable Git service. Thanks to GitLab, development teams can work with a better workflow, and more details are available on their official website.

This tutorial describes how to properly install a full-featured GitLab instance with initial configuration using Docker.


GitLab does not work by default, and in any official way, on ARM64 machines as of Q2 2022. All Vultr machines are x86-based and supported.

1. Install Docker and Compose

Note: If Docker (with Compose) is already installed in the system, this step can be avoided.

Download and Execute the Installer from Docker's Website

curl -fsSL -o

Install Compose

apt -y install docker-compose

Docker Auto-Start

The GitLab instance runs on Docker, if the docker service gets stopped for any reason, the GitLab instance will be stopped too. To prevent unexpected downtime, it is highly recommended to set Docker to start itself automatically when the system boots.

systemctl enable docker

Start Docker

Docker should be now running on the Vultr Instance, it is possible to check its status with

service docker status

If Docker is not running, it needs to be manually started via

service docker start

2. Prepare Configuration

It is recommended to store the GitLab configuration in an appropriate directory, in this tutorial, the home folder of the user gitlab is used.

adduser gitlab --disabled-login
cd /home/gitlab

Create a docker-compose file, and this allows future GitLab upgrades with the ease of a single command.

touch docker-compose.yml

Open the created file with the text editor of your choice (for example: nano)

nano docker-compose.yml

The GitLab container configuration has to be set here. Note: This file follows the docker-compose specifications. More details are in the official documentation, in case further customization is required.

version: '3.6' 
    image: 'gitlab/gitlab-ee:latest'
    restart: always
        external_url ''
        gitlab_rails['smtp_enable'] = true
        gitlab_rails['smtp_address'] = ""
        gitlab_rails['smtp_port'] = 587
        gitlab_rails['smtp_user_name'] = ""
        gitlab_rails['smtp_password'] = "PleaseUseASafePasswordAndNotThisOne"
        gitlab_rails['smtp_domain'] = ""
        gitlab_rails['smtp_authentication'] = "login"
        gitlab_rails['smtp_enable_starttls_auto'] = true
        gitlab_rails['gitlab_email_from'] = ''
        gitlab_rails['gitlab_email_reply_to'] = ''

      - ''
      - '22:22'

      - './config:/etc/gitlab'
      - './logs:/var/log/gitlab'
      - './data:/var/opt/gitlab'

    shm_size: '256m'

2.2 Configuration Explanation

  • image: 'gitlab/gitlab-ee:latest' -> This configuration uses GitLab Enterprise Edition instead of Community Edition. If the Community Edition is preferred replace gitlab/gitlab-ee:latest with gitlab/gitlab-ce:latest.
  • shm_size: '256m' -> Defines the size of the /dev/shm partition mounted on the container. Requires at least 256M to allow GitLab to work properly.

2.2.1 Omnibus Configuration

  • external_url '' -> Replace with the FQDN set in step 2.1. External URL defines at which URL the GitLab instance will be reached.
  • gitlab_rails['smtp_*'] -> Configuration for the mailserver used to send notifications.
  • gitlab_rails['gitlab_email_from'] -> The email used by the GitLab instance to send emails and notifications.
  • gitlab_rails['gitlab_email_display_name'] -> The sender name for gitlab_email_from used by the GitLab instance to send emails and notifications.
  • gitlab_rails['gitlab_email_reply_to'] -> The email used as "reply-receiver" for GitLab notifications.
  • gitlab_rails['gitlab_root_password'] -> Unrecommended The password for the root account of the GitLab instance. In case this variable remains blank (which is highly recommended) GitLab is going to automatically generate a secure password that remains accessible for 24h after the setup.

2.2.2 Ports configuration

  • -> HTTPS is not going to be used directly from GitLab. Secure access is handled directly by NGINX. The port 443 is forwarded just locally and so not available to the internet.
  • 22:22 -> SSH port is forwarded and available to the internet. This allows Git interactions with SSH rather than with HTTPS (which is a preferred method). If port 22 is used by the default SSH service of the server it is needed to use a different port; otherwise, the container is not able to start. Eventually, a different external port may be used (change the 22 before the colon to the port that will be used) for the container, but this requires further customization in GitLab settings to make explicit the port that is used by SSH.

2.2.3 Volumes

  • ./config:/etc/gitlab -> Mounts the GitLab configuration folder to ./config. This allows to store configuration data on the disk and prevents data loss if the container gets deleted or updated.
  • ./logs:/var/log/gitlab -> Mounts the GitLab logs folder to ./logs. It is highly recommended, but not mandatory, as logs are still available via docker logs [containername] until the container gets deleted or updated.
  • ./data:/var/opt/gitlab -> Mounts the GitLab data folder to ./data. This folder is really important, for that reason a whole section is dedicated to its explanation: see GitLab Data Folder.

3. GitLab Data Folder

This folder contains all the projects' data and is the most important folder to keep safe to prevent data loss. If this folder gets accidentally deleted or lost there is no way to recover what was hosted on the GitLab instance.

Vultr provides a service called Block Storage (VBS) which ensures high access speed thanks to Enterprise-grade NVMe Drives, cost-effective scalability up to 10TB, high availability, data replication, and redundancy, representing the state-of-the-art method to keep GitLab data safe.

3.2 Preparing the Folder for VBS

If the recommended way of using Vultr Block Storage is chosen, a tutorial on how to mount the VBS on the Debian server is available. After mounting the VBS, execute the command below to link the ./data folder to the VBS. Note: This needs to be done before the GitLab container is started for the first time.

ln -s /mnt/VBSFolder ./data

4. Nginx Configuration

Nginx is hosted outside of the docker container and handles all the encryption and traffic forwarding.

Create an additional Nginx Virtual Host file in /etc/nginx/sites-available.

touch /etc/nginx/sites-available/

Open the created file with the text editor of your choice and paste the configuration below.

nano /etc/nginx/sites-available/

server {
    root /dev/null;
    charset UTF-8;
    proxy_intercept_errors on;

    location / {
        # allow;
        # deny all;
        recursive_error_pages on;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        client_max_body_size 500M;
    #SSL Config
        listen                  443 ssl;
        ssl_certificate         /etc/ssl/;
        ssl_certificate_key     /etc/ssl/;

    #LOGs Config
        error_log               /var/log/nginx/;
        access_log              /var/log/nginx/;

Save and close the NGINX configuration file. NGINX requires the enable Virtual Hosts to be in the sites-enabled folder. To enable a Virtual Host, use the command below:

ln -s /etc/nginx/sites-available/ /etc/nginx/sites-enabled/

4.1 Configuration Explanation

  • root /dev/null -> All the traffic is forwarded to the GitLab instance, the root folder is set to /dev/null for security reasons.
  • server_name -> Replace with the FQDN set in step 2.1. This represents the domain name used to connect to the GitLab instance.
  • proxy_intercept_errors on and recursive_error_pages on; -> Allow nginx to handle and intercept HTTP errors.
  • allow and deny all -> Restrict IPs that can access the GitLab instance. To enable this rule remove the comment (#) and change the IP subnet according to technical requirements. This must also include IPs from eventual GitLab runners.
  • proxy_set_header * -> Pass some HTTP headers to the GitLab instance.
  • proxy_pass -> The URL where the GitLab instance is running. This needs to be equal to the port configuration in the docker-compose.yml file.
  • client_max_body_size 500M -> If HTTP uploads are allowed and preferred to SSH this parameter is needed to prevent NGINX from stopping the requests when uploading big projects.
  • listen 443 ssl -> Sets listening to HTTPS port.
  • ssl_certificate /etc/ssl/ -> The path to the certificate public key file. It can be generated with OpenSSL (causes issues with GitLab runners), Let'sEncrypt, or can be downloaded from your SSL certificate provider (Es. Cloudflare Origin Certificate).
  • ssl_certificate_key /etc/ssl/ -> The path to the certificate private key file. Must be the associated private key of ssl_certificate.
  • /var/log/nginx/ and /var/log/nginx/example.copm/git/access.log -> The path for NGINX log files. The folder must exist, if it doesn't create it with mkdir -p /var/log/nginx/

5. GitLab Start and Initial Configuration

After completing all the steps the GitLab instance is ready to be started. To start the Docker container running GitLab use the command below:

cd /home/gitlab && docker-compose up -d

This command changes the directory to the configuration one and starts the container creation steps (downloading of resources and startup). The first GitLab startup may require some minutes to be ready, as it needs to set up all the database tables and build some internal components.

5.1 Check if GitLab is Running

Checking the CPU usage it is possible to understand when the instance is ready to be used. To confirm the complete GitLab functionality, run the command below and compare the results (changing the container name may be required)

 $ docker exec gitlab_web_1 gitlab-ctl status
 run: alertmanager: (pid 1875) 232s; run: log: (pid 1294) 794s
 run: crond: (pid 1695) 235s; run: log: (pid 886) 905s
 run: gitaly: (pid 1769) 235s; run: log: (pid 552) 970s
 run: gitlab-exporter: (pid 1766) 235s; run: log: (pid 1203) 815s
 run: gitlab-kas: (pid 1656) 238s; run: log: (pid 807) 956s
 run: gitlab-workhorse: (pid 1667) 238s; run: log: (pid 953) 888s
 run: grafana: (pid 1895) 232s; run: log: (pid 1629) 258s
 run: logrotate: (pid 497) 983s; run: log: (pid 509) 980s
 run: nginx: (pid 1012) 880s; run: log: (pid 965) 887s
 run: postgres-exporter: (pid 1884) 232s; run: log: (pid 1328) 789s
 run: postgresql: (pid 658) 965s; run: log: (pid 673) 962s
 run: prometheus: (pid 1784) 234s; run: log: (pid 1264) 801s
 run: puma: (pid 889) 902s; run: log: (pid 900) 899s
 run: redis: (pid 514) 977s; run: log: (pid 526) 974s
 run: redis-exporter: (pid 1768) 235s; run: log: (pid 1235) 807s
 run: registry: (pid 1676) 237s; run: log: (pid 1001) 881s
 run: sidekiq: (pid 1584) 280s; run: log: (pid 919) 892s
 run: sshd: (pid 33) 998s; run: log: (pid 32) 998s

5.2 First Login

GitLab is now up and running at the FQDN specified in the configuration files. Accessing the FQDN using a web browser should return a login page.

For the first login, the root account is required. The password for the login depends on the configuration used:

  • if the unrecommended gitlab_rails['gitlab_root_password'] has been used the password is the one that has been set in the docker-compose.yml file.
  • if the recommended method has been used the password is stored in config/initial_root_password. The password can be accessed using cat /home/gitlab/config/initial_root_password | grep Password

5.3 First Configuration

Some general parameters should be edited after installing GitLab, below there are technical explanations about the settings that are recommended to be changed.

5.3.1 Account Registration

Settings URL: /admin/application_settings/general
The first one, which is also recommended by GitLab with a banner after the login with the root account, is to disable account registration. Disabling account registration is a great thing for private Git instances, as this prevents unattended users from taking space on the instance. If the team that will use the GitLab instance is dynamic, a domain allowlist for the emails to use is viable. In this way just the users with emails from whitelisted domains will be able to register and use GitLab.

To proceed with the registration limitations, navigate to the URL at the top of this section and expand the Sign-up restrictions section. To disable all the registrations and allow just administrators to create new accounts, remove the flag from Sign-up enabled and save. To allow just registrations from domains fill in the "Allowed domains for sign-ups" with a line-by-line list of all the domains allowed.

Settings URL: /admin/application_settings/appearance
GitLab allows replacing the default navigation bar and favicon logo.
This permits to easily differentiate the GitLab instance from other instances and helps prevent human distractions.

To proceed with the change navigate to the URL at the top of the section and upload the new logo in the two forms, then scroll down and save.

5.3.3 Add an User

Settings URL: /admin/users/new
GitLab allows administrators to register new accounts directly from the administration panel. When the user is added an email will be sent to the provided email address with a one-time link to set a password.

To proceed with an account creation, navigate to the URL at the top of the section and fill in the data requested.
If the user needs to have access to CI/CD shared runners, the flag "User is validated and can use free CI minutes on shared runners." must be set.

6. Updating GitLab

Thanks to the use of Docker, updating GitLab requires just a few commands.
Always remember to check for eventual breaking changes on the GitLab changelog page before updating.

To update, execute the commands below:

docker-compose pull
docker-compose up -d

Note: GitLab may need some minutes to be fully available after the update. Consider proceeding with updates when the instance is not being used.

7. Conclusions

GitLab is now correctly installed, and it's ready for production use thanks to the slightly modified configuration.