Docker Compose
# docker-compose.yml - GitLab CE production deployment
services:
gitlab:
image: gitlab/gitlab-ce:latest
container_name: gitlab
hostname: gitlab.example.com
restart: unless-stopped
shm_size: "256m"
ports:
- "8801:80"
- "8401:443"
- "8201:22"
volumes:
- gitlab-config:/etc/gitlab
- gitlab-logs:/var/log/gitlab
- gitlab-data:/var/opt/gitlab
environment:
GITLAB_ROOT_EMAIL: "admin@example.com"
GITLAB_ROOT_PASSWORD: "some-password"
GITLAB_OMNIBUS_CONFIG: |
# External URL - set this to your actual domain
external_url 'https://gitlab.example.com'
# SSH configuration
gitlab_rails['gitlab_shell_ssh_port'] = 8201
# Timezone
gitlab_rails['time_zone'] = 'Australia/Sydney'
# Email configuration
gitlab_rails['smtp_enable'] = true
gitlab_rails['smtp_address'] = 'smtp.gmail.com'
gitlab_rails['smtp_port'] = 587
gitlab_rails['smtp_user_name'] = 'email@gmail.com'
gitlab_rails['smtp_password'] = 'some-password'
gitlab_rails['smtp_domain'] = 'example.com'
gitlab_rails['smtp_authentication'] = 'login'
gitlab_rails['smtp_enable_starttls_auto'] = true
# Reduce memory usage for smaller instances
puma['worker_processes'] = 2
sidekiq['concurrency'] = 10
# Container registry
registry_external_url 'https://registry.example.com'
# Monitoring
# prometheus_monitoring['enable'] = false
# Disable Prometheus monitoring if using external monitoring
prometheus_monitoring['enable'] = false
# Disable the Container Registry if you do not need it
# registry['enable'] = false
# Reduce Puma workers (minimum 2)
puma['worker_processes'] = 2
puma['min_threads'] = 1
puma['max_threads'] = 4
# Reduce Sidekiq concurrency
sidekiq['concurrency'] = 5
# Disable GitLab Pages if not used
# pages_external_url nil
# gitlab_pages['enable'] = false
# Reduce Gitaly concurrency
gitaly['configuration'] = {
concurrency: [{ rpc: "/gitaly.SmartHTTPService/PostReceivePack", max_per_repo: 3 }]
}
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/-/health"]
interval: 60s
timeout: 30s
retries: 5
start_period: 300s
Initial root password
# Retrieve the initial root password (valid for 24 hours)
docker exec gitlab cat /etc/gitlab/initial_root_password
# Reset root password
1. Open the Rails console
docker exec -it gitlab gitlab-rails console
2. Find the root user
user = User.find_by_username('root')
3. Set a new password
user.password = 'NewStrongPassword123!'
user.password_confirmation = 'NewStrongPassword123!'
user.save!
4. Exit the console
exit
Re-send Reset Password Instructions
# Open the Rails console
docker exec -it gitlab gitlab-rails console
# Find the user:
user = User.find_by(email: 'user@example.com')
# Send reset instructions:
user.send_reset_password_instructions
# Exit
exit
Prepare Your Certificate
Setup Let’s Encrypt certificate as per How to Setup Let’s Encrypt with DNS-01 Validation on Ubuntu – TRENDS iT
Link your Let’s Encrypt certificate to Gitlab
Add to docker compose:
volumes:
- /etc/letsencrypt/live/example.com/fullchain.pem:/etc/gitlab/ssl/gitlab.example.com.crt:ro
- /etc/letsencrypt/live/example.com/privkey.pem:/etc/gitlab/ssl/gitlab.example.com.key:ro
- /etc/letsencrypt/live/example.com/fullchain.pem:/etc/gitlab/ssl/registry.example.com.crt:ro
- /etc/letsencrypt/live/example.com/privkey.pem:/etc/gitlab/ssl/registry.example.com.key:ro
environment:
GITLAB_OMNIBUS_CONFIG: |
nginx['redirect_http_to_https'] = true
# Optional: Define custom paths if not using default names
letsencrypt['enable'] = false
nginx['ssl_certificate'] = "/etc/gitlab/ssl/gitlab.example.com.crt"
nginx['ssl_certificate_key'] = "/etc/gitlab/ssl/gitlab.example.com.key"
Identify Gitlab IP
# Update CoreNDS
kubectl edit configmap coredns -n kube-system
# Add hosts block inside the Corefile
apiVersion: v1
kind: ConfigMap
metadata:
name: coredns
namespace: kube-system
data:
Corefile: |
.:53 {
errors
health
ready
# Add your custom entry here:
hosts {
192.168.x.x gitlab.example.com
fallthrough
}
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
}
forward . /etc/resolv.conf
cache 30
loop
reload
loadbalance
}
Setup Gitlab.com project
Add Personal access tokens (PAT) on Gitlab.com
Edit profile > Access > Personal access tokens > Generate token: fine-grained token > assign permissions for Push and/or Pull
Project > your project > Code > copy “Clone with HTTPS” link
Setup local Gitlab
Connect to Gitlab.com
Settings > Repository > Mirroring repositories > Add new
Enter “Git repository URL” from your Gitlab.com project above
Enter Username and Password (PAT) > Mirror repository
Setup Folder Structure
git clone https://gitlab.example.com/group/name.git
# set global user email & user name
git config --global user.email "your-gitlab-email@example.com"
git config --global user.name your-gitlab-username
# Stage the files
git add .
# Commit
git commit -m "Initial GitOps structure"
# Push to Gitlab (only folders with contents are pushed)
git push -uf origin main
References
- https://oneuptime.com/blog/post/2026-02-08-how-to-run-gitlab-ce-in-docker-self-hosted/view
- https://medium.com/@BuildWithLal/dockerized-gitlab-how-to-easily-set-up-your-own-gitlab-server-9a925be09c59
- https://medium.com/@BuildWithLal/dockerized-gitlab-ci-setting-up-and-connecting-your-gitlab-runner-b810a02e42f2
- https://www.virtualizationhowto.com/2025/05/how-to-mirror-your-on-premises-gitlab-repo-to-gitlab-cloud-for-resiliency/
- https://medium.com/@paolocarta_it/how-to-structure-your-gitops-repository-with-per-cluster-argocd-instances-b65bcc937322
