---
title: "Self-managed GitLab Cookbook"
date: 2020-11-08T20:45:49.000Z
author: Z.SHINCHVEN
tags: [GitLab, Maven mirror, Docker, docker-compose, certbot, Lets Encrypt!]
canonical: https://atlassc.net/2020/11/09/gitlab-self-host-cookbook
---
I've been maintaining self-managed GitLab instances for a few years. gitlab-ce is fully dockerized, you can easily deploy a
GitLab container within a few minutes.

Here's my cookbook.

## Prerequisites

To deploy a gitlab-ce container/instance, you must be familiar with the following techs and tools:

- Linux
    - bash
    - [curl](https://curl.haxx.se/docs/manpage.html)
    - [vim](https://www.vim.org/docs.php)
- docker
    - [docker-ce](https://docs.docker.com/engine/reference/commandline/cli/)
    - [docker-compose](https://docs.docker.com/compose/)
- Reverse proxy
    - nginx
    - certbot
    - SSL
    - HTTPS

A server and a domain will be required in this tutorial. Prepare your cloud resources before you begin.

## Install Docker

You can install docker on almost all modern Linux distribution. Please follow
the [official guide](https://docs.docker.com/engine/install/) to install docker-engine on your sever.

To manage your docker deployment, you will also need docker-compose, please follow
the [official guide](https://docs.docker.com/compose/install/) to install it.

If you happen to use a ubuntu server, I
have [a script](https://github.com/ShinChven/mirrors/blob/master/docker/install.sh) to install it which is based
on [official guide(ubuntu)](https://docs.docker.com/engine/install/ubuntu/) and can save your time significantly.

```bash
curl https://raw.githubusercontent.com/ShinChven/mirrors/master/docker/install.sh | bash -
```

## Deploy GitLab Via docker-compose

[Compose](https://docs.docker.com/compose/) is a tool for defining and running multi-container Docker applications. To
manage GitLab's configuration and variables with docker-compose is one of the best practice.

### The docker-compose.yml

To begin with, let's `mkdir` for your deployment project.

Then create a file named `docker-compose.yml` in your project directory.

A docker virtual network will be created by the [directory name](https://docs.docker.com/compose/networking/) once you
execute `docker-compose up`.

```yaml
web:
  image: 'gitlab/gitlab-ce:latest' # Use official image https://hub.docker.com/r/gitlab/gitlab-ce/
  restart: always
  hostname: 'hostname.example.com'
  container_name: gitlab # Container name
  environment:
    # Configure your GitLab https://docs.gitlab.com/omnibus/settings/README.html
    GITLAB_OMNIBUS_CONFIG: |
      # url config
      external_url 'https://hostname.example.com'
      # time zone
      gitlab_rails['time_zone'] = 'Beijing'
      # backup https://docs.gitlab.com/omnibus/settings/backups.html
      gitlab_rails['backup_keep_time'] = 604800
      # remote backup https://docs.gitlab.com/ee/raketasks/backup_restore.html#uploading-backups-to-a-remote-cloud-storage
      # aliyun remote backup configuration (in my case)
      gitlab_rails['backup_upload_connection'] = {
        'provider' => 'aliyun',
        'aliyun_accesskey_id' => '<your_accesskey_id>',
        'aliyun_accesskey_secret' => '<your_accesskey_secret',
        'aliyun_oss_endpoint' => 'http://end_point.aliyuncs.com',
        'aliyun_oss_bucket' => 'bunket_name',
        'aliyun_oss_location' => 'location'
      }
      gitlab_rails['backup_upload_remote_directory'] = 'gitlab'
      # stmp/email https://docs.gitlab.com/omnibus/settings/smtp.html
      gitlab_rails['smtp_enable'] = true
      gitlab_rails['smtp_address'] = 'smtp.mail.example.com'
      gitlab_rails['smtp_port'] = 465
      gitlab_rails['smtp_user_name'] = 'your@example.com'
      gitlab_rails['smtp_password'] = 'your_email_password'
      gitlab_rails['smtp_authentication'] = 'login'
      gitlab_rails['smtp_tls'] = true
      gitlab_rails['gitlab_email_from'] = 'your@example.com'
      # In order to use external nginx and certbot, I disabled the nginx in container
      nginx['listen_port'] = 80
      nginx['listen_https'] = false
      # Force https
      # If your https is not correctly configured in host machine, you will not be able to visit your gitlab as all requests to port 80 is forwarded to port 443, but nothing is listening on 443.
      nginx['proxy_set_headers'] = {
        "X-Forwarded-Proto" => "https",
        "X-Forwarded-Ssl" => "on"
      }
  # mapping container's port to host
  ports:
    - '10080:80' # curl 127.0.0.1:10080 to see your 
    - '10443:443'
    - '10022:22'
  volumes:
    - '<host_path_for_gitlab>/config:/etc/gitlab'
    - '<host_path_for_gitlab>/log:/var/log/gitlab'
    - '<host_path_for_gitlab>/data:/var/opt/gitlab'
```

### docker-compose up

Once your `docker-compose.yml` is created, run the following commands in your project directory to deploy your gitlab-ce
container:

```bash
docker-compose up -d 
```

- [`docker-compose up`](https://docs.docker.com/compose/reference/up/) will execute your docker-compose.yml.
- `-d` Detached mode: Run containers in the background.

### Check status

After container is created, use the `docker ps` command to see the container's status.

```bash
docker ps | grep 'gitlab'
```

See GitLab container's status

| STATUS                | EXPLAIN                                                                  |
|-----------------------|--------------------------------------------------------------------------|
 | Up <time> (starting)  | Starting, you may see 502 error, please wait for GitLab finish starting. | 
 | Up <time> (healthy)   | Boot finished.                                                           |
| Up <time> (unhealthy) | Some error occurred.                                                     |

## Serve GitLab Behind A Nginx Reverse Proxy

In order to share the server's 80/443 port with other web app and manage SSL via certbot, you should consider serving
GitLab behind a reverse proxy, that's why I disabled the nginx inside the container and left the job to host machine's
nginx instance.

### DNS

Add a DNS record to point your domain to your server, and make sure port 80 and 443 is open in your server's firewall.

Once DNS is done, we can get onto nginx.

### Nginx Configuration

Nginx is often preinstalled, create a
simple [nginx reverse proxy conf file](https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/) to serve
GitLab.

```bash
vim /etc/nginx/conf.d/gitlab.conf
```

```Nginx
server {
    # bind domain
    listen 80;
    server_name <YOUR_DOMAIN>; # configure your domain
    location / {
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Server $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://127.0.0.1:10080/; # proxy to the docker instance
    }
    # logs
    access_log  /var/log/nginx/gitlab_access.log;
    error_log   /var/log/nginx/gitlab_error.log;
}
```

### Test Nginx Configuration

```bash
nginx -t
```

If everything is fine, terminal should return:

```bash
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
```

**If something is wrong, please check your configuration before proceed! **

### Reload Nginx Configuration

```bash
nginx -s reload
```

The reverse proxy configuration is not finished since GitLab is configured to forward all requests to 80 to 443. SSL
must be setup.

### Let's Encrypt! (Certbot/SSL)

Normally a SSL certificate must be purchased from issuer, but [Let's Encrypt!](https://letsencrypt.org/) is free and
automated.

#### Install Certbot

[certbot](https://certbot.eff.org/) is the commandline tool for Let's Encrypt, please install it with it's nginx plugin
by following the [official guide](https://certbot.eff.org/instructions).

If you happen to use Ubuntu 20.04, installation is simple according to [Digital Ocean](https://m.do.co/c/5a107c95344b)'
s [guide](https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-ubuntu-20-04):

```bash
# https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-ubuntu-20-04
sudo apt install certbot python3-certbot-nginx
```

#### Deploy SSL via Certbot

Run certbot, terminal will show your nginx configuration:

```bash
certbot
```

Then select your domain by input it's number.

If the SSL certificate is successfully deployed, choose direct all request to https.

Done.

## Finish Up

By now your GitLab is deployed as a docker container and is served behind a reverse proxy via https.
However, there are still a few things you should do.

### Back up Secrets

**IMPORTANT!**

If your GitLab instance is used for production, you should backup your GitLab's config directory once deployed.
If `gitlab-secrets.json` is missing, you will
see [malfunctions](https://docs.gitlab.com/ee/raketasks/backup_restore.html#when-the-secrets-file-is-lost) after you
restored or migrated your GitLab.
To find GitLab's config directory in your host machine, please see `volumes` in your `docker-compose.yml`.

### Back up Data

```bash
docker exec -it gitlab /opt/gitlab/bin/gitlab-rake gitlab:backup:create 
```

- [docker exec](https://docs.docker.com/engine/reference/commandline/exec/): Run a command in a running container
- [-it](https://docs.docker.com/engine/reference/commandline/exec/#options): Optional, keep STDIN open even if not attached, and allocate a pseudo-TTY
- `gitlab`: The container name.
- `/opt/gitlab/bin/gitlab-rake gitlab:backup:create`: command to create a gitlab backup package.

See `docker-compose.yml`'s volume mapping for path of data, backup files will be in `data/backups`

### Back up Data Automatically

It is advised to set up a [cron](https://crontab.guru/) jobs in host machine to back up your GitLab's data:

```bash
# create a cron job
crontab -e
```

```bash
# Cron Job
30 23 * * * docker exec gitlab /opt/gitlab/bin/gitlab-rake gitlab:backup:create
```

### Upgrade GitLab

If you intend to use GitLab in production, please follow it's version up. When your instance is behind too many major
versions to the current release, you may see errors during upgrading an old instance.

To upgrade a dockerized GitLab is simple. Navigate to your docker-compose project directory, and run the following
codes:

```bash
docker pull gitlab/gitlab-ce # pull latest image
docker-compose up -d
```

### Restore

```bash
docker exec -it <GITLAB_CONTAINER_NAME> gitlab-backup restore BACKUP=<BACK_UP_FILENAME>
```
