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.
Table of Contents
- 1. Why a self-hosted GitLab Runner instead of a shared runner
- 2. Prerequisites and choosing a host
- 3. Runner installation on Linux
- 4. Registering the runner with the Docker executor
- 5. Understanding and adjusting config.toml
- 6. Runner tags and job assignment
- 7. Security policies for the runner
- 8. Magento-specific runner configuration
- 9. Runner maintenance and updates
- 10. Summary
- 11. FAQ
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?
2Docker vs. shell executor?
3How many runners do I need?
4Register a runner for multiple projects?
5Prevent unwanted jobs?
6Update the runner?
7Job exceeds runner timeout?
8Debug a misbehaving runner?
9Persist the Composer cache between jobs?
10Locked vs. unlocked runner?
Quick reference: runner configuration for Magento
- Executor:
dockerfor isolated builds,shellfor direct server access - Tags: always assign them, this prevents jobs from landing on the wrong runners
- Concurrency: limit to 2 to 4 in
config.tomlfor 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.