Docker Compose Reference: GitLab CE

Type: Software Reference Confidence: 0.93 Sources: 7 Verified: 2026-02-27 Freshness: 2026-02-27

TL;DR

Constraints

Quick Reference

Service Configuration

ServiceImagePortsVolumesKey Env
GitLab CEgitlab/gitlab-ce:18.7.1-ce.080:80, 443:443, 22:22config:/etc/gitlab, logs:/var/log/gitlab, data:/var/opt/gitlabGITLAB_OMNIBUS_CONFIG, external_url
GitLab Runnergitlab/gitlab-runner:latestNonerunner-config:/etc/gitlab-runner, /var/run/docker.sockCI_SERVER_URL
PostgreSQL (bundled)Included in omnibus5432 (internal)data:/var/opt/gitlab/postgresqlpostgresql['shared_buffers']
Redis (bundled)Included in omnibus6379 (internal)data:/var/opt/gitlab/redisredis['maxmemory']
Nginx (bundled)Included in omnibus80, 443 (via GitLab)config:/etc/gitlab/sslnginx['ssl_certificate']
Puma (app server)Included in omnibus8080 (internal)--puma['worker_processes'] (default: 2)
Sidekiq (background)Included in omnibus----sidekiq['max_concurrency'] (default: 20)
Prometheus (monitoring)Included in omnibus9090 (internal)data:/var/opt/gitlab/prometheusprometheus['enable']
Container RegistryIncluded in omnibus5050 (configurable)data:/var/opt/gitlab/gitlab-rails/shared/registryregistry_external_url
Gitaly (Git RPC)Included in omnibus8075 (internal)data:/var/opt/gitlab/git-datagitaly['configuration']

Volume Mapping

Host PathContainer PathPurpose
$GITLAB_HOME/config/etc/gitlabgitlab.rb, gitlab-secrets.json, SSL certs
$GITLAB_HOME/logs/var/log/gitlabOmnibus component logs
$GITLAB_HOME/data/var/opt/gitlabRepositories, uploads, PostgreSQL, Redis data

Memory Allocation (production)

ComponentDefault MemoryTunable Setting
Puma (per worker)1.2 GB limitpuma['per_worker_max_memory_mb']
Sidekiq~200 MB initialsidekiq['max_concurrency']
Prometheus + exporters~200 MBprometheus['enable'] = false to disable
PostgreSQL256 MB shared_bufferspostgresql['shared_buffers'] = '512MB'
Total minimum~4 GB--

Decision Tree

START: What kind of GitLab Docker deployment?
├── Local development / testing?
│   ├── YES → Use HTTP-only compose (Step 1) with minimal resources
│   └── NO ↓
├── Production with own domain?
│   ├── YES → Do you handle SSL at a reverse proxy?
│   │   ├── YES → Set external_url to https:// but disable built-in Nginx SSL
│   │   └── NO → Use Let's Encrypt auto-SSL (Step 3, Variant A)
│   └── NO ↓
├── Need CI/CD pipelines?
│   ├── YES → Add GitLab Runner service to compose (Step 4)
│   └── NO ↓
├── Need email notifications?
│   ├── YES → Configure SMTP in GITLAB_OMNIBUS_CONFIG (Step 5)
│   └── NO ↓
└── DEFAULT → Basic compose with HTTP, add features as needed

Step-by-Step Guide

1. Set up the host environment

Create the GitLab home directory and set the environment variable. [src1]

# Set GITLAB_HOME (add to ~/.bashrc for persistence)
export GITLAB_HOME=/srv/gitlab
sudo mkdir -p $GITLAB_HOME/{config,logs,data}

Verify: ls -la $GITLAB_HOME → should show config/, logs/, data/ directories.

2. Create the docker-compose.yml

Production-ready base configuration for GitLab CE. [src1]

services:
  gitlab:
    image: gitlab/gitlab-ce:18.7.1-ce.0
    container_name: gitlab
    restart: always
    hostname: 'gitlab.example.com'
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        external_url 'https://gitlab.example.com'
        gitlab_rails['time_zone'] = 'UTC'
    ports:
      - '80:80'
      - '443:443'
      - '22:22'
    volumes:
      - '${GITLAB_HOME}/config:/etc/gitlab'
      - '${GITLAB_HOME}/logs:/var/log/gitlab'
      - '${GITLAB_HOME}/data:/var/opt/gitlab'
    shm_size: '256m'

Verify: docker compose config → should show resolved configuration without errors.

3. Configure SSL/TLS

Choose one approach depending on your infrastructure. [src2]

# Variant A: Let's Encrypt (automatic)
letsencrypt['enable'] = true
letsencrypt['contact_emails'] = ['[email protected]']
letsencrypt['auto_renew'] = true

# Variant B: Behind a reverse proxy
nginx['listen_port'] = 80
nginx['listen_https'] = false
nginx['proxy_set_headers'] = {
  "X-Forwarded-Proto" => "https",
  "X-Forwarded-Ssl" => "on"
}

# Variant C: Own certificates
nginx['ssl_certificate'] = "/etc/gitlab/ssl/gitlab.crt"
nginx['ssl_certificate_key'] = "/etc/gitlab/ssl/gitlab.key"

Verify: curl -I https://gitlab.example.com → should return HTTP/2 200 with valid TLS.

4. Add GitLab Runner for CI/CD

Add the Runner service and register it using authentication tokens (GitLab 16.0+). [src4] [src7]

# Register runner (after creating in UI: Admin > CI/CD > Runners)
docker exec -it gitlab-runner gitlab-runner register \
  --non-interactive \
  --url "https://gitlab.example.com" \
  --token "glrt-YOUR_TOKEN_HERE" \
  --executor "docker" \
  --docker-image "alpine:latest" \
  --description "docker-runner"

Verify: docker exec -it gitlab-runner gitlab-runner list → should show the registered runner.

5. Configure SMTP for email

GitLab Docker image does not include an SMTP server. [src5]

# Gmail SMTP configuration (add to GITLAB_OMNIBUS_CONFIG)
gitlab_rails['smtp_enable'] = true
gitlab_rails['smtp_address'] = "smtp.gmail.com"
gitlab_rails['smtp_port'] = 587
gitlab_rails['smtp_user_name'] = "[email protected]"
gitlab_rails['smtp_password'] = "your-app-password"
gitlab_rails['smtp_authentication'] = "login"
gitlab_rails['smtp_enable_starttls_auto'] = true

Verify: Run Notify.test_email('[email protected]', 'Test', 'Works!').deliver_now in gitlab-rails console.

6. Launch and retrieve initial password

Start GitLab and get the auto-generated root password. [src1]

docker compose up -d
# Wait 3-5 minutes for initialization
docker exec -it gitlab grep 'Password:' /etc/gitlab/initial_root_password

Verify: Open https://gitlab.example.com and log in with username root and the retrieved password.

7. Set up automated backups

Configure cron for regular backups. Back up secrets separately. [src3]

# Create backup (data only -- secrets NOT included)
docker exec -t gitlab gitlab-backup create

# Back up secrets (CRITICAL)
cp $GITLAB_HOME/config/gitlab-secrets.json \
   $GITLAB_HOME/config/gitlab-secrets.json.bak

# Crontab: daily at 2 AM
0 2 * * * docker exec -t gitlab gitlab-backup create CRON=1

Verify: ls -la $GITLAB_HOME/data/backups/ → should show *_gitlab_backup.tar files.

Code Examples

Complete Production docker-compose.yml

# docker-compose.yml -- GitLab CE Production Setup
# Usage: GITLAB_HOME=/srv/gitlab docker compose up -d
services:
  gitlab:
    image: gitlab/gitlab-ce:18.7.1-ce.0
    container_name: gitlab
    restart: always
    hostname: 'gitlab.example.com'
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        external_url 'https://gitlab.example.com'
        gitlab_rails['time_zone'] = 'UTC'
        letsencrypt['enable'] = true
        letsencrypt['contact_emails'] = ['[email protected]']
        gitlab_rails['smtp_enable'] = true
        gitlab_rails['smtp_address'] = "smtp.gmail.com"
        gitlab_rails['smtp_port'] = 587
        puma['worker_processes'] = 2
        sidekiq['max_concurrency'] = 10
        postgresql['shared_buffers'] = '512MB'
    ports:
      - '80:80'
      - '443:443'
      - '22:22'
    volumes:
      - '${GITLAB_HOME}/config:/etc/gitlab'
      - '${GITLAB_HOME}/logs:/var/log/gitlab'
      - '${GITLAB_HOME}/data:/var/opt/gitlab'
    shm_size: '256m'
  gitlab-runner:
    image: gitlab/gitlab-runner:latest
    container_name: gitlab-runner
    restart: always
    depends_on:
      - gitlab
    volumes:
      - gitlab-runner-config:/etc/gitlab-runner
      - /var/run/docker.sock:/var/run/docker.sock
volumes:
  gitlab-runner-config:

Memory-Constrained Setup (4 GB RAM)

# Minimal GitLab for dev/small teams (4 GB RAM)
services:
  gitlab:
    image: gitlab/gitlab-ce:18.7.1-ce.0
    container_name: gitlab
    restart: always
    environment:
      GITLAB_OMNIBUS_CONFIG: |
        external_url 'http://gitlab.local'
        puma['worker_processes'] = 0
        puma['min_threads'] = 1
        puma['max_threads'] = 2
        sidekiq['max_concurrency'] = 5
        prometheus['enable'] = false
        grafana['enable'] = false
        registry['enable'] = false
        postgresql['shared_buffers'] = '128MB'
    ports:
      - '80:80'
      - '22:22'
    volumes:
      - '${GITLAB_HOME}/config:/etc/gitlab'
      - '${GITLAB_HOME}/logs:/var/log/gitlab'
      - '${GITLAB_HOME}/data:/var/opt/gitlab'
    shm_size: '256m'

Backup Restore Script

#!/bin/bash
# restore-gitlab.sh -- Restore GitLab from backup
BACKUP_TIMESTAMP="$1"
docker exec -it gitlab gitlab-ctl stop puma
docker exec -it gitlab gitlab-ctl stop sidekiq
docker exec -it gitlab gitlab-backup restore BACKUP="${BACKUP_TIMESTAMP}"
docker cp gitlab-secrets.json.bak gitlab:/etc/gitlab/gitlab-secrets.json
docker exec -it gitlab gitlab-ctl reconfigure
docker exec -it gitlab gitlab-ctl restart
docker exec -it gitlab gitlab-rake gitlab:check SANITIZE=true

Anti-Patterns

Wrong: Using latest tag in production

# BAD -- latest tag can pull breaking changes on restart
services:
  gitlab:
    image: gitlab/gitlab-ce:latest

Correct: Pin to a specific version

# GOOD -- pinned version ensures reproducible deployments
services:
  gitlab:
    image: gitlab/gitlab-ce:18.7.1-ce.0

Wrong: No persistent volumes

# BAD -- data is lost when container is removed
services:
  gitlab:
    image: gitlab/gitlab-ce:18.7.1-ce.0
    # No volumes defined

Correct: Map all three volumes

# GOOD -- persistent data survives container recreation
services:
  gitlab:
    image: gitlab/gitlab-ce:18.7.1-ce.0
    volumes:
      - '${GITLAB_HOME}/config:/etc/gitlab'
      - '${GITLAB_HOME}/logs:/var/log/gitlab'
      - '${GITLAB_HOME}/data:/var/opt/gitlab'

Wrong: Deprecated registration tokens for Runner

# BAD -- registration tokens deprecated in GitLab 16.0
docker exec -it gitlab-runner gitlab-runner register \
  --registration-token "DEPRECATED_TOKEN"

Correct: Runner authentication tokens

# GOOD -- authentication tokens from GitLab 16.0+
docker exec -it gitlab-runner gitlab-runner register \
  --token "glrt-YOUR_AUTH_TOKEN" \
  --url "https://gitlab.example.com" \
  --executor "docker" \
  --docker-image "alpine:latest"

Wrong: Missing shm_size

# BAD -- Prometheus may crash with OOM errors
services:
  gitlab:
    image: gitlab/gitlab-ce:18.7.1-ce.0
    # No shm_size specified

Correct: Explicit shm_size

# GOOD -- 256m prevents Prometheus OOM errors
services:
  gitlab:
    image: gitlab/gitlab-ce:18.7.1-ce.0
    shm_size: '256m'

Wrong: Backup without secrets

# BAD -- secrets file NOT included in gitlab-backup
docker exec -t gitlab gitlab-backup create

Correct: Backup data AND secrets

# GOOD -- back up both data and secrets
docker exec -t gitlab gitlab-backup create
cp $GITLAB_HOME/config/gitlab-secrets.json \
   /backup/gitlab-secrets.json.$(date +%F)

Common Pitfalls

Diagnostic Commands

# Check container status and health
docker compose ps
docker inspect gitlab --format='{{.State.Health.Status}}'

# View GitLab logs
docker compose logs -f gitlab

# Check all omnibus component status
docker exec -it gitlab gitlab-ctl status

# Run environment check
docker exec -it gitlab gitlab-rake gitlab:check SANITIZE=true

# Check GitLab version
docker exec -it gitlab gitlab-rake gitlab:env:info

# Test SMTP email
docker exec -it gitlab gitlab-rails console -e production

# Check runner connectivity
docker exec -it gitlab-runner gitlab-runner verify

# Check disk usage
du -sh $GITLAB_HOME/{config,logs,data}

# List backups
ls -la $GITLAB_HOME/data/backups/

Version History & Compatibility

VersionStatusBreaking ChangesMigration Notes
18.xCurrentNew UI, Duo AnalyticsDirect upgrade from 17.x
17.xMaintenanceRequires PostgreSQL 14+Upgrade PostgreSQL before upgrading from 16.x
16.xEOLRunner registration tokens deprecatedSwitch to runner authentication tokens
15.xEOLPraefect/Gitaly changesMust stop at 15.11.x before 16.x
14.xEOLBackground migrations requiredMust complete all migrations before upgrading

When to Use / When Not to Use

Use WhenDon't Use WhenUse Instead
Small to mid-size team (< 500 users) self-hostingKubernetes infrastructure availableGitLab Helm Chart or GitLab Operator
Single-server deploymentHigh availability requiredGitLab HA reference architecture
Quick local development/testingEnterprise features neededGitLab EE Docker image
Air-gapped / on-premise requirementSaaS is acceptablegitlab.com (hosted)
Full DevOps platform (SCM + CI/CD + Registry)Only need lightweight Git hostingGitea or Gogs Docker

Important Caveats

Related Units