Install and Register Your Own GitLab Runner
AI generated
CI/CD
.yml
GitLab · Runner · Docker · CI/CD · Magento
Install your own GitLab Runner
and register it: the complete guide

A self-hosted GitLab Runner gives teams full control over the build environment, security, and access paths. This article explains installation on Linux, registration with the Docker executor, tags, security settings, and Magento-specific configuration, step by step and in full.

14 min read Installation · Registration · Docker · Tags · Security GitLab Runner 17+ · Linux · Docker 26+

1. Why a self-hosted GitLab Runner instead of a shared runner

GitLab provides shared runners on gitlab.com that are ready to use immediately, with no installation and no configuration. For many projects that is enough, especially open source projects whose builds do not need sensitive network resources or specialized tools. For professional Magento projects, however, shared runners fall short in three critical areas: security, performance, and access to internal resources.

On security: shared runners execute jobs for every GitLab user. A Magento deployment job needs an SSH key for the production server, Composer auth tokens for private packages, and possibly database credentials for setup upgrade. Using these secrets on a shared runner means they run in an environment that is not exclusively under your own control. A self-hosted runner runs solely for your own project on a host you manage yourself.

On performance: Magento builds with Composer install and DI compilation take several minutes without a cache. A self-hosted runner can persist the Composer cache across jobs, which reduces build times considerably. Shared runners typically start in fresh containers with no persistent cache. In addition, build resources (CPU, RAM) on your own runner can be sized to the actual load instead of depending on the resource budget of a shared system.

2. Prerequisites and choosing a host

A GitLab Runner with the Docker executor needs three things: a Linux server (Debian, Ubuntu, or RHEL-based distributions are officially supported), a current stable version of Docker, and network access to gitlab.com or your own GitLab instance. The runner host does not have to be the same machine as the deployment target; in fact, it is advisable to keep them separate so that a compromised runner has no direct filesystem access to the production server.

Hardware requirements depend on build load. For a single Magento build, at least two CPU cores and four gigabytes of RAM are recommended. If you want to support several concurrent builds, scale accordingly. The persistent Composer cache can reach several gigabytes, so plan enough disk space for Docker images, build caches, and artifacts.

# Runner host requirements - verify before installation
# Run these checks on the target Linux server

# 1. Check OS version
cat /etc/os-release

# 2. Install Docker if not present (Ubuntu/Debian)
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor \
  -o /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] \
  https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" \
  | tee /etc/apt/sources.list.d/docker.list
apt-get update && apt-get install -y docker-ce docker-ce-cli containerd.io

# 3. Verify Docker installation
docker --version
docker run --rm hello-world

# 4. Check network connectivity to GitLab
curl -fsSL https://gitlab.com > /dev/null && echo "GitLab reachable"

3. Runner installation on Linux

Installing the GitLab Runner follows GitLab's official package repository. This is the recommended installation method because updates can then be managed through the package manager. Alternatively, a binary download is available, but it requires manual update maintenance. For production systems, the package repository is preferable because it makes security updates easier.

After installation, the runner service runs as a systemd service and starts automatically after a reboot. The service status can be checked at any time with systemctl status gitlab-runner. The runner's log output is important for troubleshooting and lives in the systemd journal by default, accessible with journalctl -u gitlab-runner -f.

4. Registering the runner with the Docker executor

Registration links the installed runner to a GitLab project or group. This requires a registration token, found in the GitLab project settings under CI/CD → Runners. Since GitLab 16, registration via authentication tokens is preferred over registration tokens; the user interface shows the current method.

The Docker executor is the best choice for most Magento build jobs. Each job starts in a fresh Docker container with the image defined in .gitlab-ci.yml, which guarantees reproducibility. The shell executor runs jobs directly on the host, which is faster but requires dependencies to already be present on the runner host. For deploy jobs that need to establish SSH connections, the shell executor can make more sense, since it does not require privileged Docker mode.

# GitLab Runner registration - Docker executor
# Run on the runner host after installation

gitlab-runner register \
  --non-interactive \
  --url "https://gitlab.com/" \
  --token "$RUNNER_AUTHENTICATION_TOKEN" \
  --executor "docker" \
  --docker-image "php:8.4-cli" \
  --description "magento-build-runner" \
  --tag-list "magento,php84,docker" \
  --run-untagged "false" \
  --locked "false" \
  --docker-volumes "/cache/composer:/root/.composer:rw" \
  --docker-volumes "/cache/npm:/root/.npm:rw" \
  --docker-pull-policy "if-not-present"

# Verify registration was successful
gitlab-runner verify

# Check runner status
gitlab-runner status

5. Understanding and adjusting config.toml

The configuration file /etc/gitlab-runner/config.toml holds all runner settings and can be adjusted manually after registration. Changes are picked up automatically by the runner process, no restart required. Key settings: concurrent at the global level determines the maximum number of simultaneous jobs across all runner instances. limit per runner restricts the number of simultaneous jobs for that specific runner.

For deployment runners, limit = 1 is recommended to prevent race conditions when deploying to the same server concurrently. For build runners, a higher value can be set to support parallel builds. Docker volume mounts for caches should be persistent and live outside the container filesystem so they survive between job runs.

6. Runner tags and job assignment

Runner tags are the routing system between GitLab jobs and runner instances. A job with tags: [magento, production] only runs on runners that have both tags. Without tags, a job runs on any runner configured to accept run-untagged jobs. For production environments, run-untagged should be set to false so that no unwanted jobs land on the runner.

A sensible tag scheme for Magento projects separates build runners from deploy runners. The build runner gets tags such as magento and php84. The deploy runner, which has SSH access to the production server, gets a separate tag such as magento-deployer. This separation ensures that a compromised build job does not automatically gain access to deploy secrets.

7. Security policies for the runner

The runner host is part of a team's security-critical infrastructure. It has access to SSH keys, Composer auth tokens, and possibly database credentials. That is why the runner host must meet the same security requirements as servers in the production environment: regular system updates, minimal open ports, SSH access only via key authentication, and no direct root login.

In the Docker executor, jobs must never run in privileged containers unless it is explicitly necessary and well justified. privileged = false in config.toml prevents jobs from talking to the host's Docker daemon or claiming kernel capabilities. Secrets should never be passed as Docker environment variables if they could show up in container logs; the masked flag on GitLab CI/CD variables is mandatory for all sensitive values.

# config.toml - secure runner configuration for Magento
# Location: /etc/gitlab-runner/config.toml

concurrent = 4
check_interval = 0
shutdown_timeout = 0

[session_server]
  session_timeout = 1800

[[runners]]
  name = "magento-build"
  url = "https://gitlab.com/"
  token = "[REGISTERED_TOKEN]"
  executor = "docker"
  # Restrict to tagged jobs only - no untagged job pickup
  run_untagged = false
  # Allow only one concurrent deploy per runner instance
  limit = 1

  [runners.docker]
    tls_verify = false
    image = "php:8.4-cli"
    # Never run privileged containers
    privileged = false
    disable_entrypoint_overwrite = false
    oom_kill_disable = false
    disable_cache = false
    # Mount persistent caches outside container filesystem
    volumes = [
      "/cache/composer:/root/.composer:rw",
      "/cache/npm:/root/.npm:rw",
      "/tmp/gitlab-runner-build:/build:rw"
    ]
    pull_policy = "if-not-present"
    shm_size = 0

8. Magento-specific runner configuration

For Magento builds, a few configuration points reduce build time considerably. The persistent Composer cache is the most important: when /root/.composer is preserved between jobs, Composer packages are loaded from cache on the second build instead of being downloaded again. For a typical Magento project with many dependencies, this can reduce the Composer install step from several minutes to seconds.

DI compilation (setup:di:compile) is computationally intensive. On a runner with enough CPU cores it runs quickly; on a single-core system it can take over ten minutes. If DI compilation is too slow, either use a more powerful runner or cache the generated code via the GitLab CI cache, keyed on the Composer lock hash. Frontend builds with Tailwind CSS also benefit from a persistent npm cache.

9. Runner maintenance and updates

The GitLab Runner needs to be updated regularly. GitLab recommends keeping the runner within the same major version as the GitLab server. If you run GitLab 17.x, you should use a runner on version 17.x. Updates via the package manager are simple and low risk: apt-get update && apt-get install gitlab-runner brings the runner up to the current version.

Regular maintenance tasks include cleaning up old Docker images and containers on the runner host, monitoring the disk usage of the Composer cache, and checking the runner logs for errors or unusual patterns. A runner that regularly hits timeout errors points to resource or network problems that should be addressed early.

Mironsoft

GitLab Runner, CI/CD infrastructure, and Magento deployment pipelines

Need a secure GitLab Runner setup for Magento?

We help set up self-hosted GitLab Runners correctly, configure them securely, and optimize them for Magento builds and deployments, including cache configuration, tag scheme, and security policies.

Runner setup

Set up installation, registration, Docker executor, and tag scheme

Security

Configure security policies, network isolation, and secret handling

Performance

Optimize Composer cache, npm cache, and build parallelization

10. Summary

A self-hosted GitLab Runner gives Magento teams control over the build environment, security, performance, and access paths that shared runners cannot offer. Installation is straightforward and follows the official package repository. The Docker executor is the best choice for build jobs because it guarantees reproducibility through container isolation. Registration links the runner to the GitLab project and allows fine-grained control via tags and concurrency limits.

Security is not optional: the runner host must be treated like a production-critical server. No privileged Docker mode without an explicit reason, no shared runners for deploy jobs holding production secrets, and the masked flag for all sensitive variables. Persistent caches for Composer and npm measurably reduce build times. Regular updates and monitoring keep the runner reliable.

Setting up a GitLab Runner: the essentials at a glance

Installation

Use the official GitLab package repository. Pre-install Docker. Runner runs as a systemd service and starts automatically after a reboot.

Choosing an executor

Docker for build jobs (reproducibility through containers). Shell for deploy jobs (direct SSH access without privileged Docker).

Tags and routing

Separate build runners from deploy runners. run-untagged = false on deploy runners. Magento-specific tags for clear job assignment.

Security

privileged = false. Treat the runner host like a production server. Masked flag for all secrets. Persist the Composer cache outside the container.

11. FAQ: Installing and registering a GitLab Runner

1Runner on the same server as Magento?
Technically possible, not recommended. A separate host keeps the attack surface isolated. The runner user must have no write access to the Magento directory.
2Docker vs. shell executor?
Docker: fresh container per job, reproducible. Shell: runs directly on the host, faster, but dependencies must already be present.
3How many runners do I need?
At least one for build, a separate one for deploy (because of SSH access to production). An optional third one for quality gates.
4Register a runner for multiple projects?
Use a group runner. It is registered in the group's runner settings and is available to all projects in the group. Saves maintenance effort.
5Prevent unwanted jobs?
Set run-untagged = false and assign specific tags. Jobs without matching tags are ignored.
6Update the runner?
apt-get update && apt-get install gitlab-runner when installed through the official repository. Running jobs are only interrupted after completion.
7Job exceeds runner timeout?
Job is aborted, appears as failed. The timeout key in .gitlab-ci.yml can override the timeout per job.
8Debug a misbehaving runner?
journalctl -u gitlab-runner -f for live logs. gitlab-runner verify for connection checks. Pipeline logs for job-specific runner output.
9Persist the Composer cache between jobs?
Volume mount in config.toml: /cache/composer:/root/.composer:rw. Keeps the cache persistent on the runner host. Considerably reduces Composer install times.
10Locked vs. unlocked runner?
Locked: usable only in the project it was registered for. Unlocked: can be assigned to other projects. For production: locked runners are recommended.

Quick reference: runner configuration for Magento

  • Executor: docker for isolated builds, shell for direct server access
  • Tags: always assign them, this prevents jobs from landing on the wrong runners
  • Concurrency: limit to 2 to 4 in config.toml for stable builds
  • Cache directory: outside the job working directory, mounted persistently
  • Security: privileged = false, no root access for the CI user
  • Updates: update the GitLab Runner regularly, ideally via cron or Ansible
  • Monitoring: enable the Prometheus endpoint, watch runner status in Grafana

A cleanly configured self-hosted runner is the foundation for fast, reproducible, and secure deployments. It pays for itself after just a few projects through eliminated wait times for shared runner slots and full control over the execution environment.