👍 What we like
- ✓Unlimited CI minutes compared to gitlab.com's 400 min/month quota
- ✓Official MCP server with 135 tools for LLM integration
- ✓Stable self-hosted Container Registry since version 17.x
- ✓Clean generic OAuth support for Discord without workarounds
👎 What to watch
- ✕Requires 4-8 GB RAM; 4 GB causes swapping during garbage collection
- ✕Discord avatars not returned directly, requiring a custom sync script
- ✕HTTPS configuration conflicts if embedded Let's Encrypt is not disabled
- ✕HDD storage causes pipelines to run 5x slower than SSD
🏆 Our picks
Affiliate links · same price for youPlanetHoster — VPS for GitLab CE
- ✓4-8 GB guaranteed RAM for a stable GitLab CE
- ✓Fast NVMe storage for the Container Registry
- ✓EU & Canada datacenters, 24/7 support
See all our recommended gear in the shop.
📑 Contents ▾
- 01 The Context
- 02 Why Self-Hosted (vs. gitlab.com)
- 03 Initial Setup — 30 Real Minutes
- · Hardware Prerequisites
- · Omnibus Install
- 06 Discord OAuth — Finally Functional in 2026
- 07 Container Registry — The 2026 Improvement
- 08 CI Runners — Separation of Concerns
- 09 Backups — The Forgotten Part
- 10 The Verdict After 6 Months
- · What Works Great
- · What Broke
- · Alternative to Consider
- 14 Complementary Tools I Use
- 15 FAQ
- · Affiliation Disclosure
TL;DR: Self-hosting GitLab CE 18.x in 2026 remains an excellent choice for 5–50 users if you accept ~4–8 GB RAM at runtime and a 30-minute initial setup. The major upgrades vs. 2024: clean generic OAuth, stable Container Registry, and the official MCP server (135 tools). Concrete pitfalls below.
🖥️ Hardware to host it at home — To run any of these tools 24/7 without a big power bill, a low-power mini PC is enough in most cases. Two common picks: the Beelink Mini S12 Pro (Intel N100, 16 GB) and the Beelink EQ14 (Intel N150, dual 2.5 GbE ports). To choose for your needs: our guide to the best mini PCs for a homelab.
The Context
I have been running GitLab CE 18.x self-hosted for 6 months on an Ubuntu 24.04 VM (192.168.1.50, 4 vCPU, 12 GB RAM, 200 GB SSD). 5 active users, ~40 projects, ~30 GB of cumulative repos, with CI runners separated on another VM. This article summarizes what works, what broke, and what I would do differently.
Why Self-Hosted (vs. gitlab.com)
My concrete reasons in 2026:
- No CI minute quota: On free gitlab.com, it’s 400 min/month. My Astro + Docker pipelines take ~10 min each × 10/day = saturated quickly. Self-hosted = unlimited.
- Privacy: Proprietary code that doesn’t reside anywhere with a third party.
- Included Container Registry: Since GitLab 17.x, self-hosted registry auth is stable. No more need for Harbor alongside.
- Official MCP: Since late 2025, GitLab provides an official MCP server exposing 135 tools to LLMs (create issue, MR, read file, etc.). Huge productivity boost if you code with Claude/GPT/Cursor.
Initial Setup — 30 Real Minutes
Hardware Prerequisites
- Real 2026 Minimum: 4 vCPU / 8 GB RAM (4 GB starts swapping as soon as a GC runs)
- Recommended: 4 vCPU / 12 GB RAM
- Disk: SSD is mandatory. HDD = 5× slower pipelines.
I tested on Hostinger VPS Cloud (KVM 4 vCPU / 8 GB / 200 GB NVMe, ~€7/month — see VPS offers [affiliate link]). It works. But the best option remains a homelab if you can afford it.
Omnibus Install
# Ubuntu 24.04
curl -sS https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.deb.sh | sudo bash
sudo EXTERNAL_URL="https://git.exemple.com" apt install gitlab-ce
30 seconds for package installation, 5 minutes for auto-reconfigure on the first gitlab-ctl reconfigure. That’s it.
Pitfall #1: If you set EXTERNAL_URL=http://... and want to switch to HTTPS later using an external reverse proxy (Caddy / Traefik), you must explicitly disable the embedded Let’s Encrypt in /etc/gitlab/gitlab.rb:
letsencrypt['enable'] = false
nginx['listen_https'] = false
nginx['listen_port'] = 80
external_url 'https://git.exemple.com' # still HTTPS in the URL
Otherwise, the bundled nginx tries to issue a cert on its own → conflict with your external Caddy.
Discord OAuth — Finally Functional in 2026
Since GitLab 17.5, OAuth via oauth2_generic works for Discord without workarounds. In /etc/gitlab/gitlab.rb:
gitlab_rails['omniauth_providers'] = [
{
name: 'oauth2_generic',
label: 'Discord',
app_id: 'DISCORD_APP_ID',
app_secret: 'DISCORD_APP_SECRET',
args: {
client_options: {
site: 'https://discord.com',
authorize_url: '/api/oauth2/authorize',
token_url: '/api/oauth2/token',
user_info_url: '/api/users/@me'
},
user_response_structure: {
root_path: [],
id_path: ['id'],
attributes: {
nickname: 'username',
first_name: 'global_name',
email: 'email',
image: 'avatar'
}
},
authorize_params: {
scope: 'identify email'
},
strategy_class: "OmniAuth::Strategies::OAuth2Generic"
}
}
]
Pitfall #2: Discord does not return a directly usable avatar URL, just a hash. GitLab displays a default Gravatar identicon. Solution: a daily cron job that syncs Discord avatars to GitLab via their admin API. A ~50-line Python script.
Container Registry — The 2026 Improvement
Clean self-hosted registry auth setup finally available since GitLab 17.x:
# /etc/gitlab/gitlab.rb
registry_external_url 'https://registry.git.exemple.com'
registry_nginx['listen_https'] = false
registry_nginx['listen_port'] = 5050
- External Caddy/Traefik vhost that forwards 5050 → 5050 with TLS termination.
Once in place, direct push from CI pipeline:
# .gitlab-ci.yml
docker:build:
stage: build
image: docker:24-cli
services:
- docker:24-dind
script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
Automatic auth via CI variables. No more need for Harbor / DockerHub.
CI Runners — Separation of Concerns
Pitfall #3: Do not put runners on the same host as the GitLab server. This guarantees GitLab will swap during heavy pipelines.
I placed 2 GitLab Runners (concurrent=3 each) on a separate host (Intel N100 mini-PC with 8 GB RAM). Auto-registered via token, Docker executor with a custom Node 20 + pre-installed Astro image to save cache time.
Measurement: Astro + Docker build pipeline = 2–4 min on separate runners vs. 8–12 min if runners are on the GitLab host (the server itself competing for resources).
Backups — The Forgotten Part
# Daily Cron
sudo gitlab-backup create STRATEGY=copy
# → /var/opt/gitlab/backups/TIMESTAMP_NN.X_gitlab_backup.tar
Pitfall #4: The backup does NOT contain /etc/gitlab/gitlab.rb nor /etc/gitlab/gitlab-secrets.json. If you restore without these, your instance cannot decrypt its own secrets. Back up these 2 files separately (encrypted).
I send everything to a self-hosted MinIO on another VM via rclone, 30-day rotation. Additional cost: €0 (homelab).
The Verdict After 6 Months
What Works Great
- Stability: 99.9% uptime over 6 months (1 incident: OOM kill when I pushed a 4 GB repo without Git LFS)
- Performance: 2–4 min pipelines on Node/Docker stack
- Discord OAuth: Zero friction for adding friends / collaborators
- Container Registry: 30 images in production, no issues
What Broke
- Upgrade 17 → 18: 25 min downtime (vs. estimated 5 min) due to a DB schema migration. Read the release notes BEFORE planning the upgrade.
- GitLab Pages: Requires wildcard DNS + wildcard cert. Not easy to set up with external Caddy. I worked around it by using external Cloudflare Pages for static content.
- Memory: GitLab “breathes” between 4 and 8 GB depending on the active Sidekiq worker. Without 12 GB of headroom, it ends up in an OOM kill.
Alternative to Consider
If you are 1–3 people and do little CI: Gitea + Drone or Forgejo use ~200 MB RAM at runtime (vs. 4–8 GB for GitLab). For code-only without heavy pipelines, it’s much lighter.
But as soon as you want Container Registry + OAuth + mature CI + full UI + MCP server: GitLab CE remains superior.
Complementary Tools I Use
- Bitdefender GravityZone on the GitLab host: A serious EDR is non-negotiable when you expose a Git service to the public (GravityZone offers — affiliate link)
- Hostinger VPS Cloud: If you don’t have a homelab, this is the best price/performance ratio in 2026 (see VPS — affiliate link)
- NordVPN: For SSH admin from outside without exposing port 22 (NordVPN — affiliate link)
FAQ
How much does self-hosting really cost? If you already have a homelab: €0 / month (electricity ~€5/month on a mini-PC). On a VPS: €7–15 / month for 4 vCPU / 12 GB.
GitLab EE vs. CE in 2026? CE covers 95% of use cases for <50 users. EE becomes relevant above that, for portfolio management features (crossed epics, value stream analytics, etc.).
Is free GitLab.com enough to start? Yes, until you hit the 400 CI min/month limit. Migrating away from gitlab.com is then trivial (full project export via API).
Is GitHub better? GitHub Enterprise self-hosted = significantly more expensive (~$21/user/month) for a comparable feature set. GitLab CE = $0.
Affiliation Disclosure
This article contains affiliate links. See full disclosure. These links do not alter the content or recommendations — I have been using GitLab CE self-hosted for 6 months and this is my raw feedback.
Article written on May 28, 2026.