DEV Community

Cover image for GitLab SE behind Cloudflare Zero Trust: Private CI Runner
Iuri Covaliov
Iuri Covaliov

Posted on

GitLab SE behind Cloudflare Zero Trust: Private CI Runner

Introduction

In the previous labs, we deployed a self‑hosted GitLab instance behind Cloudflare Zero Trust to protect access to the web interface and repositories. That setup works well for human users, but CI systems introduce a different kind of traffic.

GitLab runners interact with GitLab non‑interactively: they fetch repositories, call APIs, and upload job results automatically. When the public GitLab domain is protected by Cloudflare Access, these interactions can be redirected to authentication flows that CI jobs cannot complete.

This lab explores a practical solution: running CI jobs on a GitLab Runner inside the private network, allowing CI traffic to bypass the Zero Trust authentication layer entirely.

The core idea is simple:

Humans access GitLab through Cloudflare Zero Trust. CI jobs interact with GitLab entirely inside the private network.

Goal

Extend the existing GitLab deployment by introducing a private GitLab Runner VM that executes CI jobs without relying on the public Cloudflare‑protected endpoint.

By the end of this lab:

  • GitLab remains accessible through Cloudflare Zero Trust
  • CI jobs run on a runner VM in the same private network
  • repository checkout uses an internal GitLab endpoint
  • pipelines run successfully without hitting Cloudflare authentication

Constraints / assumptions

This lab intentionally keeps the environment simple and reproducible.

  • GitLab is already running behind Cloudflare Zero Trust
  • GitLab and the runner VM share the same private network
  • infrastructure is provisioned using Vagrant
  • the runner uses the Docker executor
  • the goal is architecture clarity, not production‑grade scaling

The environment is intentionally local. The focus of the lab is network design and CI architecture, not cloud infrastructure configuration.

High‑level design

The architecture introduces two separate access paths to GitLab.

Human access

Developers reach GitLab through the public domain protected by Cloudflare Zero Trust.

Developer → Cloudflare Zero Trust → GitLab public domain

CI execution

GitLab communicates with the runner entirely inside the private network.

GitLab VM → internal NGINX listener → GitLab Runner VM

The runner registers using the internal endpoint and uses the same address for repository checkout through the clone_url setting.

This ensures CI jobs never follow the public access path and therefore never encounter Cloudflare authentication redirects.

Phase 1 --- Make it work

The first phase focuses on simply getting a pipeline to run on the private runner.

Two architectural adjustments are required.

Expose an internal GitLab entrypoint

The previous lab disabled GitLab's bundled NGINX because external traffic was handled by the Cloudflare tunnel and reverse proxy.

However, CI jobs require a stable HTTP endpoint that supports Git operations. Using Puma directly is unreliable for this purpose, and the public domain leads to Cloudflare authentication redirects.

To solve this, the GitLab VM exposes an internal NGINX listener bound to the private IP.

Example:

http://<GITLAB_PRIVATE_IP>{=html}:8081

This endpoint is used for:

  • runner registration
  • GitLab API calls
  • repository checkout

Provision a runner VM

A second VM is created inside the same private network and configured with:

  • Docker
  • GitLab Runner
  • a Docker executor
  • explicit runner tags

During registration, the runner configuration sets:

url → internal GitLab endpoint
clone_url → internal GitLab endpoint

The clone_url parameter ensures repository checkout uses the internal address instead of the public GitLab domain.

Validate with a smoke pipeline

A minimal CI project confirms that the runner works correctly by verifying:

  • runner identity
  • container execution
  • GitLab reachability
  • successful repository checkout

Once the pipeline succeeds, the private CI path is confirmed to work correctly.

Phase 2 --- Reduce trust / Harden access

Once the runner works, the next step is reducing permissions that are not actually required.

Disable privileged Docker mode

Privileged containers grant very broad capabilities to CI jobs, including access to host‑level resources.

The smoke pipeline only runs basic commands inside a container, so privileged mode is unnecessary.

Disabling it reduces the attack surface of the runner host.

Restrict job scheduling with tags

The runner is configured with explicit tags and untagged jobs are disabled.

Pipelines must explicitly reference these tags to run on the runner.

This prevents unrelated projects or misconfigured jobs from executing there accidentally.

Lessons learned

Running GitLab behind Cloudflare Zero Trust introduces an important architectural distinction.

Interactive users and automated CI jobs have very different requirements.

Human users can complete authentication flows through Cloudflare Access. CI systems cannot.

Instead of weakening the Zero Trust configuration, a better approach is introducing a dedicated internal access path for CI systems.

This lab demonstrates that pattern clearly:

  • public access remains protected
  • CI traffic stays inside the private network
  • repository checkout uses a stable internal endpoint

Another key lesson is that CI runners should start permissive enough to work, but once pipelines are validated, unnecessary privileges should be removed.

Where to go next

This lab opens the door to several useful extensions.

Possible follow‑up experiments include:

  • GitLab behind Cloudflare --- Runner VM (multiple runners and scheduling policies)
  • GitLab behind Cloudflare --- S3 storage VM for caches, artifacts, and pages
  • GitLab behind Cloudflare --- Automation with Ansible
  • GitLab behind Cloudflare --- Full CI/CD example\ (build → checks → unit tests → reports → packaging → containerization → deployment)

Each of these steps moves the lab environment closer to a realistic CI/CD platform while keeping the architecture transparent and reproducible.

Repository

The full lab --- including Vagrant configuration, provisioning scripts, diagrams, and the reproducible runbook --- is available in the repository linked below.

👉 https://github.com/ic-devops-lab/devops-labs/tree/main/GitLabSEBehindCloudflare03Runner


Published Labs in This Series

Each lab explores a boundary in infrastructure design and gradually shifts trust from network assumptions toward identity and workload isolation.

Top comments (0)