GitLab behind a VPN or firewall
Use kanman with a self-managed GitLab that is only reachable inside your company network: a runner inside the network does all repository work and talks to kanman over outbound HTTPS only.
If your GitLab is only reachable inside your company network, for example behind a VPN, kanman’s cloud cannot connect to it. You do not need to open your network for kanman. Instead, you run a self-hosted runner inside the network and turn on Run everything on your runners. The runner then does every repository action with its own GitLab token: cloning, branches, merge requests, comments with the evidence pack, CI results. kanman’s cloud keeps the board, decisions, policies and the audit log and never connects to your GitLab.
The same setup works for GitHub Enterprise Server behind a firewall.
How it fits together
- The runner runs inside your network, on a Linux host or VM with Docker, next to your GitLab.
- It connects outbound over HTTPS to kanman, asks for work and reports back. kanman never connects into your network. No inbound ports, no VPN access for kanman, no firewall exception for incoming traffic.
- It reaches your GitLab with its own token (
GITLAB_TOKEN). The token never leaves the runner. - It calls your model provider with the access you configure on it, for example your Amazon Bedrock, Microsoft Foundry or Google Vertex AI account.
What has to be reachable
From the runner host, outbound HTTPS (port 443) to:
| Host | Purpose |
|---|---|
api.kanman.ai |
The runner’s connection to kanman: registration, work, progress, results |
ughtqskbdmitncmopwvj.supabase.co |
kanman’s storage and callback host: evidence uploads and the results of acceptance checks and scans |
Your GitLab, for example gitlab.corp.example |
Clone, push, merge requests, CI (inside your network) |
| Your model provider | For example bedrock-runtime.eu-central-1.amazonaws.com, your Foundry or Vertex AI endpoint, or api.anthropic.com |
ghcr.io |
Only to pull the runner image (or use your own registry mirror) |
Nothing has to reach the runner from outside.
The runner log names the kanman host it uses when it starts (kanmanHost), together with the proxy and certificate settings it found.
Step 1: Create a GitLab token for the runner
Create a token the runner uses for all repository work. A project access token or group access token for the projects of the team is a good fit; a personal access token of a service account works too.
| Setting | Value |
|---|---|
| Role | Developer or higher in every project the team works in (push branches, open merge requests). Maintainer if kanman should merge into protected branches. |
| Scopes | api, read_repository, write_repository |
| Expiry | Match your rotation policy. When it expires, the runner’s checks report “rejected the token”. |
Step 2: Start the runner inside your network
Create a workspace token under Your settings > API tokens (see Run the self-hosted runner). Then start the runner on a host inside the network:
docker run -d --name kanman-runner \
--restart unless-stopped \
-e KANMAN_API_KEY=km_your_runner_token \
-e RUNNER_NAME=corp-runner-1 \
-e GITLAB_TOKEN=glpat-your-runner-token \
-e GITLAB_API_URL=https://gitlab.corp.example/api/v4 \
-e CLAUDE_CODE_USE_BEDROCK=1 \
-e AWS_REGION=eu-central-1 \
ghcr.io/kanman-ai/executor-host
| Variable | Meaning |
|---|---|
KANMAN_API_KEY |
The workspace API token |
GITLAB_TOKEN |
The token from step 1 |
GITLAB_API_URL |
The API address of your GitLab: its web address plus /api/v4, for example https://gitlab.corp.example/api/v4. Use the same host as the repositories you add in step 5. |
| Model access | See step 3 |
RUNNER_NAME |
Optional. Name shown in Workspace settings > Runners |
For acceptance checks the runner also needs Docker with Compose, for example by mounting the host’s Docker socket (-v /var/run/docker.sock:/var/run/docker.sock). See Acceptance checks on your runner.
Pin the image to a version tag in production and update deliberately.
Internal certificates
If your GitLab uses a certificate signed by your company’s own certificate authority, give the runner that CA certificate. Mount the PEM file and set NODE_EXTRA_CA_CERTS:
-v /etc/pki/company-ca.pem:/certs/company-ca.pem:ro \
-e NODE_EXTRA_CA_CERTS=/certs/company-ca.pem \
The runner adds the certificate to everything it starts: its own connections, git (clone, fetch, push) and the coding agent. It builds one bundle from the system certificates and yours and points git at it, so public hosts such as api.kanman.ai stay trusted.
If you already have a complete bundle (system certificates plus your CA), set SSL_CERT_FILE to it instead.
HTTP proxy
If outbound traffic has to go through a proxy, set the usual variables. The runner, git and the coding agent use them:
-e HTTPS_PROXY=http://proxy.corp.example:3128 \
-e NO_PROXY=gitlab.corp.example,.corp.example \
Put your GitLab (and other internal hosts) into NO_PROXY when they are reached directly. Lower-case variable names (https_proxy, no_proxy) work too.
Step 3: Choose the model access
The runner calls the model provider itself. Recommended for companies: your own cloud account, so model traffic stays under your contract and in your region.
- Amazon Bedrock, Microsoft Foundry or Google Vertex AI for Claude Code, Azure OpenAI for Codex: set the provider variables on the runner and choose Model access from the runner environment for the team. See Model access on self-hosted runners.
- Your own key stored in kanman: the runner receives it for each step of that team.
- An Anthropic or OpenAI key on the runner (
ANTHROPIC_API_KEY,OPENAI_API_KEY). - Your company’s AI gateway inside the network: store it under Workspace settings > Model providers as OpenAI-compatible gateway (only your runners call it, and Test connection runs on your runner), or set its variables on the runner. See Use your company’s AI gateway and AI gateways in the runner environment. Claude Code needs the gateway’s Anthropic-compatible endpoint, Codex its OpenAI Responses API.
Whichever you choose, it covers every step on the runner: the coding agent as well as drafting stories, the independent reviewer, acceptance specs and kanman’s replies in the conversation. Amazon Bedrock through the runner’s IAM role, for example, needs no extra key for drafting and review.
Different models for coding and for the other steps: to keep Claude for coding and send drafting, review and replies to your company’s AI gateway inside the network, set the KANMAN_ASSISTANT_ variables on the runner. See Different models for coding and for the other steps.
To keep the coding agent from contacting anything besides the model provider, also set CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 on the runner.
Step 4: Turn on Run everything on our runners
- Open Workspace settings > Runners.
- Turn on Run everything on our runners.
- Check that your runner shows as Online in the list below.
From now on kanman’s cloud does not call a model provider or a code host for this workspace. See Run everything on your runners for what runs where.
Step 5: Create the team and add the repository by path
kanman’s cloud cannot list the projects of your GitLab, so you add the repository by its path.
- Start the team setup.
- Where do your stories live?: choose the kanman board or Jira (see Tracker choice).
- In Project and repositories, choose GitLab as the code host and fill in Add a repository your runner can reach:
- Host URL: the address you open in your browser, for example
https://gitlab.corp.example - Project path: the full path, for example
platform/backend/api - Default branch: optional. Leave it empty and your runner looks up the project’s default branch.
- Host URL: the address you open in your browser, for example
- Click Add repository.
Your runner checks the repository right away with its own token. The row shows:
| Status | Meaning |
|---|---|
| Checking with your runner… | The runner is checking. This takes a few seconds. |
| Not checked yet | No runner is online. The repository is saved and checked as soon as a runner comes online. |
| Your runner does not check repositories yet | The runner is online but runs an older image. Update it. |
| Your runner reaches it | The runner reached the project, read its default branch and may push and open merge requests. |
You can add more repositories the same way, and later in Team settings > Repositories, where Check again repeats the check.
When the check finds a problem
| Message | What to do |
|---|---|
| Your runner has no GITLAB_TOKEN | Restart the runner with GITLAB_TOKEN (step 1 and 2). |
| GitLab rejected your runner’s token | The token is wrong, expired or revoked. Create a new one and restart the runner. |
| Your runner’s token may not open merge requests | Give the token the scopes api, read_repository and write_repository. |
| Project not found | Check the path, and that the token’s user (or the access token) is a member of the project. |
| The token may read, but not push or open merge requests | Give the token at least the Developer role in the project. |
| The branch does not exist | Enter an existing branch, or leave the field empty for the default branch. |
| Your runner cannot reach the host | Check DNS, VPN routing and the proxy settings (HTTPS_PROXY, NO_PROXY) on the runner host. |
| Your runner does not trust the certificate | Mount your CA certificate and set NODE_EXTRA_CA_CERTS (see Internal certificates). |
| The API answers, but git over HTTPS does not | Check the token’s read_repository and write_repository scopes and that git traffic may pass your proxy. |
| GITLAB_API_URL on your runner names another host | Runs work, but acceptance checks and scans clone from the host in GITLAB_API_URL. Set it to your GitLab’s API address. |
Tracker choice
GitLab issues cannot be the team’s tracker in this mode: the issues live on your GitLab, which kanman’s cloud does not reach. Choose one of these instead:
- The kanman board: stories, columns, comments and history live in kanman. See Without an external tracker.
- Jira (Cloud, or Server and Data Center reachable from kanman’s cloud). See Connect Jira and GitLab.
The code still lives in your GitLab: the runner opens the merge requests there.
What works and what does not
Works, all on your runner:
- Runs: clone, run branch, the coding agent, local verification with your GitLab CI variables, push and the merge request
- Acceptance checks on a fresh checkout (with Docker on the runner)
- The outcome gate’s repository steps: diff, CI pipeline results, commit statuses, the evidence pack as a merge request comment, and merges when your merge policy lets kanman merge
- The independent reviewer and acceptance specs with your model access
- The acceptance manifest check and the merge request that adds a starter manifest
- Maintenance scans, drafting stories from the conversation, team context from repositories
Not available in this mode:
- GitLab issues as the team’s tracker (use the kanman board or Jira)
- Picking repositories from a list in the team setup (add them by path)
- Team context from Confluence, Notion or uploaded files
- Revert proposals for incidents
Related pages
Last updated: January 1, 0001
Open kanman