Setup Gitlab CE with docker compose

DevOps

If you plan to use Gitlab CE (community edition) on your own server, then you can use this docker-compose.yml:

networks:
  gitlab-network:
    driver: bridge

services:
  gitlab:
    image: 'gitlab/gitlab-ce:latest'
    restart: always
    hostname: 'gitlab.domain.com'
    container_name: 'gitlab'
    networks:
      - gitlab-network
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        external_url 'https://gitlab.domain.com'
        nginx['listen_port'] = 80
        nginx['listen_https'] = false
        gitlab_rails['gitlab_default_projects_features_issues'] = false

        nginx['client_max_body_size'] = '500m'
        registry_nginx['client_max_body_size'] = '500m'

        registry_external_url 'https://registry.gitlab.domain.com'
        registry['enable'] = true
        registry_nginx['enable'] = true
        registry_nginx['listen_port'] = 5050
        registry_nginx['listen_https'] = true
        registry_nginx['ssl_certificate'] = "/etc/gitlab/ssl/registry.gitlab.domain.com.crt"
        registry_nginx['ssl_certificate_key'] = "/etc/gitlab/ssl/registry.gitlab.domain.com.key"

        # Disable the built-in Nginx to preserve logs
        nginx['real_ip_trusted_addresses'] = ['172.0.0.0/8', '192.168.0.0/16']
        nginx['real_ip_header'] = 'X-Forwarded-For'
        nginx['real_ip_recursive'] = 'on'

        # Trust the reverse proxy
        registry_nginx['proxy_set_headers'] = {
          "X-Forwarded-Proto" => "https",
          "X-Forwarded-Ssl" => "on"
        }
        # Mailjet SMTP configuration
        gitlab_rails['smtp_enable'] = true
        gitlab_rails['smtp_address'] = "in-v3.mailjet.com"
        gitlab_rails['smtp_port'] = 587
        gitlab_rails['smtp_user_name'] = "YOUR_KEY"
        gitlab_rails['smtp_password'] = "YOUR_PASSWORD"
        gitlab_rails['smtp_domain'] = "gitlab.domain.com"
        gitlab_rails['smtp_authentication'] = "login"
        gitlab_rails['smtp_enable_starttls_auto'] = true
        gitlab_rails['smtp_tls'] = false
        gitlab_rails['smtp_openssl_verify_mode'] = 'peer'

        gitlab_rails['gitlab_email_from'] = '[email protected]'
        gitlab_rails['gitlab_email_reply_to'] = '[email protected]'
    ports:
      - '8080:80'
      - '8443:443'
      - '2222:22'
      - '5050:5050'
    volumes:
      - '/opt/gitlab/config:/etc/gitlab'
      - '/opt/gitlab/logs:/var/log/gitlab'
      - '/opt/gitlab/data:/var/opt/gitlab'
      - '/etc/letsencrypt/live/registry.gitlab.domain.com/fullchain.pem:/etc/gitlab/ssl/registry.gitlab.domain.com.crt:ro'
      - '/etc/letsencrypt/live/registry.gitlab.domain.com/privkey.pem:/etc/gitlab/ssl/registry.gitlab.domain.com.key:ro'
    shm_size: '256m'

  gitlab-runner:
    image: 'gitlab/gitlab-runner:latest'
    restart: always
    container_name: 'gitlab-runner'
    networks:
      - gitlab-network
    volumes:
      - '/opt/gitlab/runner/config:/etc/gitlab-runner'
      - '/var/run/docker.sock:/var/run/docker.sock'
    depends_on:
      - gitlab

In this compose file above, we're using:

  1. Gitlab CE
  2. Gitlab runner
  3. Mailjet for email handling
  4. Letsencrypt for SSL certificates

Please note

Take a look at volumes, these are locations, where actual configs would be mounted.

Also here's runner config.toml contents:

runner/config/config.toml
concurrent = 1
check_interval = 0
connection_max_age = "15m0s"
shutdown_timeout = 0

[session_server]
  session_timeout = 1800

[[runners]]
  name = "Docker Runner"
  url = "http://172.17.0.1:8080"
  id = 3
  token = "glrt-blablabla"
  token_obtained_at = 2025-04-16T19:04:10Z
  token_expires_at = 0001-01-01T00:00:00Z
  executor = "docker"
  environment = ["DOCKER_TLS_CERTDIR="]
  [runners.cache]
    MaxUploadedArchiveSize = 0
    [runners.cache.s3]
    [runners.cache.gcs]
    [runners.cache.azure]
  [runners.docker]
    tls_verify = false
    image = "alpine:latest"
    privileged = true
    disable_entrypoint_overwrite = false
    oom_kill_disable = false
    disable_cache = false
    volumes = ["/cache"]
    shm_size = 0
    network_mtu = 0

[[runners]]
  name = "main-runner"
  url = "http://172.17.0.1:8080"
  id = 4
  token = "t3_blablabla"
  token_obtained_at = 2025-04-18T14:57:22Z
  token_expires_at = 0001-01-01T00:00:00Z
  executor = "docker"
  environment = ["DOCKER_TLS_CERTDIR="]
  [runners.cache]
    MaxUploadedArchiveSize = 0
    [runners.cache.s3]
    [runners.cache.gcs]
    [runners.cache.azure]
  [runners.docker]
    tls_verify = false
    image = "alpine:latest"
    privileged = true
    disable_entrypoint_overwrite = false
    oom_kill_disable = false
    disable_cache = false
    volumes = ["/cache"]
    shm_size = 0
    network_mtu = 0

Then you just run docker compose up -d, wait few minutes and you're good to go!