Skip to content

Self-Hosted GitLab Runner Setup Guide

This guide explains how to set up a self-hosted GitLab Runner on the VPS to reduce shared runner compute minutes consumption.

Prerequisites

  • VPS access (31.97.159.7)
  • Root or sudo access
  • GitLab project registration token

Step 1: Install GitLab Runner

On Ubuntu/Debian:

Option A: Using Installation Script (Recommended)

# Download the GitLab Runner repository
curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh" | sudo bash

# Install GitLab Runner
sudo apt-get install gitlab-runner

Option B: Manual Installation (If script hangs)

If the installation script hangs at apt-transport-https (common on Ubuntu 24.04+), use manual installation:

# 1. Cancel the stuck process (Ctrl+C) and check for locks
sudo lsof /var/lib/dpkg/lock-frontend
sudo killall apt-get  # if needed

# 2. Remove any failed repository configuration
sudo rm -f /etc/apt/sources.list.d/gitlab-runner.list

# 3. Add GitLab GPG key using modern method
# Try the official GitLab GPG key (works for all GitLab packages)
curl -fsSL "https://packages.gitlab.com/gitlab/gitlab-ce/gpgkey" | sudo gpg --dearmor -o /usr/share/keyrings/gitlab-runner-archive-keyring.gpg

# 4. Add repository to sources with proper keyring reference
echo "deb [signed-by=/usr/share/keyrings/gitlab-runner-archive-keyring.gpg] https://packages.gitlab.com/runner/gitlab-runner/ubuntu/ $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/gitlab-runner.list

# 5. Update package list
sudo apt-get update

# 6. Install GitLab Runner (this will also install helper images)
sudo apt-get install gitlab-runner

Option C: Direct Download (Not Recommended)

The direct .deb download requires helper images that may not be available. Use Option B instead.

If you must use direct download, you'll need to also download helper images:

# Download latest .deb package
curl -LJO "https://gitlab-runner-downloads.s3.amazonaws.com/latest/deb/gitlab-runner_amd64.deb"

# Download helper images package (version must match)
# First, check what version you downloaded:
dpkg -I gitlab-runner_amd64.deb | grep Version

# Then download matching helper images (replace VERSION):
# curl -LJO "https://gitlab-runner-downloads.s3.amazonaws.com/latest/deb/gitlab-runner-helper-images_VERSION_amd64.deb"

# Install both packages
sudo dpkg -i gitlab-runner*.deb

# Fix any dependency issues
sudo apt-get install -f

Note: Option B (repository installation) is recommended as it handles all dependencies automatically.

Troubleshooting Installation Issues

If script hangs at apt-transport-https:

  1. Cancel the process: Press Ctrl+C
  2. Check for package manager locks:
    sudo lsof /var/lib/dpkg/lock-frontend
    sudo lsof /var/lib/apt/lists/lock
    
  3. Remove locks if needed (be careful):
    sudo rm /var/lib/apt/lists/lock
    sudo rm /var/lib/dpkg/lock-frontend
    
  4. Use manual installation (Option B above)

Note: On Ubuntu 24.04 (Noble), apt-transport-https is built into apt and doesn't need separate installation. The script may hang because it's trying to install something unnecessary.

Verify Installation:

gitlab-runner --version

Step 2: Create Runner in GitLab UI

Important: GitLab has deprecated registration tokens. You must create the runner in GitLab UI first, then register it using the authentication token.

Note: The GitLab UI only creates the runner definition. Docker executor settings (image, privileged mode) are configured during registration on the VPS, not in the UI.

  1. Create the runner in GitLab:
  2. Go to your GitLab project
  3. Navigate to SettingsCI/CDRunners
  4. Click "New project runner" button (or "Create project runner")
  5. Fill in the runner details:
    • Tags: self-hosted,vps,docker (comma-separated)
    • These tags will be used to route jobs to this runner
    • Run untagged jobs: ✅ Check this box (optional, allows runner to pick up jobs without tags)
    • Runner description: VPS Self-Hosted Runner (optional)
    • Paused: Leave unchecked (runner should be active)
    • Protected: Leave unchecked (unless you want runner only for protected branches)
    • Lock to current projects: Leave unchecked (unless you want to restrict to this project only)
    • Maximum job timeout: Leave default or set to desired value (minimum 600 seconds)
  6. Click "Create runner"

  7. Copy the authentication token:

  8. After creating the runner, GitLab will display an authentication token (starts with glrt-)
  9. Copy this token immediately - you'll need it to register the runner
  10. You can also find it later in the runner details page by clicking on the runner

Step 3: Register Runner on VPS

Now register the runner on your VPS using the authentication token. This is where you configure the Docker executor settings (image, privileged mode, etc.):

Non-interactive registration (recommended):

sudo gitlab-runner register \
  --non-interactive \
  --url "https://gitlab.com/" \
  --token "glrt-xxxxxxxxxxxxxxxxxxxx" \
  --description "VPS Self-Hosted Runner" \
  --tag-list "self-hosted,vps,docker" \
  --executor "docker" \
  --docker-image "docker:24" \
  --docker-privileged \
  --docker-volumes "/var/run/docker.sock:/var/run/docker.sock" \
  --docker-network-mode "bridge"

Replace glrt-xxxxxxxxxxxxxxxxxxxx with your actual authentication token from GitLab.

Key configuration options: - --executor "docker": Use Docker executor (required for Docker builds) - --docker-image "docker:24": Default Docker image for jobs - --docker-privileged: Enable privileged mode (required for Docker-in-Docker) - --docker-volumes: Mount Docker socket for Docker-in-Docker support

Alternative: Interactive registration

If you prefer interactive mode:

sudo gitlab-runner register

When prompted: - GitLab URL: https://gitlab.com/ - Authentication token: (paste the glrt- token from GitLab UI) - Description: VPS Self-Hosted Runner - Tags: self-hosted,vps,docker (comma-separated) - Executor: docker - Default Docker image: docker:24 - Privileged mode: true (required for Docker-in-Docker) - Docker volumes: /var/run/docker.sock:/var/run/docker.sock

Step 4: Configure Runner

Edit the runner configuration:

sudo nano /etc/gitlab-runner/config.toml

Ensure the configuration includes:

concurrent = 2  # Adjust based on VPS resources (2-4 recommended)
check_interval = 0

[session_server]
  session_timeout = 1800

[[runners]]
  name = "VPS Self-Hosted Runner"
  url = "https://gitlab.com/"
  token = "YOUR_RUNNER_TOKEN"
  executor = "docker"
  [runners.docker]
    tls_verify = false
    image = "docker:24"
    privileged = true
    disable_entrypoint_overwrite = false
    oom_kill_disable = false
    disable_cache = false
    volumes = ["/cache", "/var/run/docker.sock:/var/run/docker.sock"]
    shm_size = 0
    # Note: Docker-in-Docker service is configured in CI YAML (.gitlab-ci/services.yml)
    # Do NOT add services configuration here - it will conflict with CI YAML
  [runners.cache]
    [runners.cache.s3]
    [runners.cache.gcs]
    [runners.cache.azure]

Important: The services configuration ensures Docker-in-Docker (dind) starts with the correct environment variables that your CI jobs expect (DOCKER_HOST=tcp://docker:2376).

Step 5: Start and Enable Runner

# Start the runner
sudo gitlab-runner start

# Enable auto-start on boot
sudo systemctl enable gitlab-runner

# Check status
sudo gitlab-runner status

Step 6: Verify Runner is Active

  1. Go to GitLab project → SettingsCI/CDRunners
  2. You should see your runner listed with a green circle (active)
  3. The runner should show tags: self-hosted, vps, docker

Step 7: Test the Runner

Trigger a pipeline and verify: - Build jobs are picked up by the self-hosted runner - Jobs complete successfully - Check runner logs: sudo gitlab-runner --debug run

Troubleshooting

Runner not picking up jobs:

  • Verify tags match in .gitlab-ci/services.yml (tags: [self-hosted])
  • Check runner is active in GitLab UI (should show green status)
  • Verify runner has sufficient resources
  • Ensure runner is not paused in GitLab UI

Registration token errors:

  • Error: "Creating runners with runner registration tokens is disabled"
  • Solution: Use the new authentication token method (create runner in UI first, then register with glrt- token)
  • Registration tokens are deprecated as of GitLab 16.0 and will be removed in GitLab 18.0

Docker-in-Docker issues:

Error: "FATAL: No HOST or PORT found" or "Health check error"

This usually means there's a conflict between service configuration in config.toml and the CI YAML. Fix by:

  1. Remove any service configuration from /etc/gitlab-runner/config.toml:
  2. The Docker-in-Docker service is already configured in .gitlab-ci/services.yml
  3. Having it in both places causes conflicts
  4. Remove any [[runners.docker.services]] sections from config.toml

  5. Clean up any leftover Docker containers:

    # Stop and remove any leftover runner containers
    docker ps -a | grep runner | awk '{print $1}' | xargs -r docker rm -f
    

  6. Ensure privileged mode is enabled in config.toml:

    [runners.docker]
      privileged = true
    

  7. Restart the runner:

    sudo gitlab-runner restart
    

  8. Verify Docker socket is accessible:

    ls -la /var/run/docker.sock
    

  9. Check runner logs:

    sudo journalctl -u gitlab-runner -f
    

Note: The CI YAML (.gitlab-ci/services.yml) already defines the docker:24-dind service with the correct environment variables. The runner just needs privileged = true to support it.

Resource constraints:

  • Adjust concurrent in config.toml based on VPS CPU/RAM
  • Monitor VPS resources during builds: htop or docker stats

Monitoring

View Runner Logs:

sudo journalctl -u gitlab-runner -f

Check Runner Status:

sudo gitlab-runner verify

List Registered Runners:

sudo gitlab-runner list

Expected Results

After setup: - Build jobs (docker-build-*) will run on self-hosted runner - Deployment jobs (deploy-qual, deploy-prod) will run on self-hosted runner - Lightweight jobs (validation, security scans) remain on shared runners - 70-85% reduction in shared runner compute minutes

Notes

  • The runner uses VPS resources but doesn't consume shared compute minutes
  • Ensure VPS has sufficient resources (CPU, RAM, disk) for concurrent builds
  • Monitor VPS performance and adjust concurrent setting as needed
  • Keep GitLab Runner updated: sudo apt-get update && sudo apt-get upgrade gitlab-runner