Skip to content

Git Settings

Settings to configure Git authentication, clone behavior, and deployment reporting.

Supported transports

Doco-CD accepts HTTP(S), SSH, native Git (git://host/path), and local filesystem repository URLs.

HTTPS and SSH are recommended for remote repositories.

Native Git (git://) transport

Native Git uses anonymous access. HTTP tokens, SSH keys, and GitHub App credentials are not sent over this transport, even when configured for other repositories. It cannot authenticate access to private repositories, so webhook events for private repositories fail when their clone URL is rewritten to git://. The default TCP port is 9418; use git://host:port/path for a custom port. Native Git connects directly and does not use HTTP_PROXY or TLS verification settings.

Native Git does not protect deployment content

The git:// protocol has no encryption or authentication. An attacker on the network can replace repository content before doco-cd deploys it. Plain http:// has the same transport-integrity risk. Use HTTPS or SSH unless you accept this risk. A private network alone does not provide cryptographic protection. Doco-CD does not automatically downgrade HTTPS or SSH URLs to native Git.

General

Key Type Description Default
GIT_CLONE_DEPTH number Limits commits fetched for shallow clones and fetches. 0 means full clone; git_depth can override it per deployment. Synchronization focuses on the requested ref and broadens or deepens automatically when needed. 0
GIT_CLONE_SUBMODULES boolean Whether Git submodules are initialized and updated after the parent repository is checked out. true
SKIP_TLS_VERIFICATION boolean Skip TLS verification when cloning repositories. false

Submodule URL format

Relative submodule URLs (for example ../other-repo.git) are resolved against the parent repository remote URL.

If you use an older doco-cd version and see an error like exec: "git": executable file not found in $PATH during submodule updates, use absolute submodule URLs (https://... or git@...) as a workaround or update to a newer version.

Authentication

The following settings configure how Doco-CD authenticates with Git providers when cloning or pulling repositories.

Supported authentication methods:

HTTP(S) credentials are scoped to hosts

By default, Doco-CD sends an HTTP(S) credential only to hosts that match an entry in GIT_AUTH_DOMAINS. This includes the global GIT_ACCESS_TOKEN and the global GitHub App. A repository URL can come from a webhook payload, an API or MCP poll trigger, a deployment config, a Compose include, or a submodule. The host scope prevents a credential from going to a host that you did not approve.

If you set a global HTTP(S) credential, you must also set GIT_AUTH_DOMAINS with at least one entry that the credential applies to. Otherwise doco-cd does not start. See Credential Scope for the rules and the migration steps. You can turn off the scope with GIT_AUTH_ALLOW_ANY_HOST, but this is insecure (see Disabling the Scope).

Key Type Description Default
GIT_ACCESS_TOKEN string Access token for cloning repositories (required for private repositories) via HTTP. Requires GIT_AUTH_DOMAINS to set the hosts that receive it (see Credential Scope). See Setup Access Token and Required Token Permissions. Optional for public repositories but recommended
GIT_ACCESS_TOKEN_USER string Username paired with GIT_ACCESS_TOKEN for HTTP(S) clone/fetch. Most providers accept any non-empty value, but some require a specific username for their token (e.g. a GitLab deploy token uses gitlab+deploy-token-1234567). Set it when your provider needs one. oauth2
GIT_ACCESS_TOKEN_FILE string Path to the file containing the Git Access Token (mutually exclusive with GIT_ACCESS_TOKEN).
GIT_AUTH_DOMAINS list YAML list of domain-scoped Git credentials (HTTP token, SSH key, and GitHub App credentials). Supports exact domains and wildcard subdomains like *.example.com (see Domain-scoped authentication). Mutually exclusive with GIT_AUTH_DOMAINS_FILE.
GIT_AUTH_DOMAINS_FILE string Path to a file containing the YAML configuration for GIT_AUTH_DOMAINS (mutually exclusive with GIT_AUTH_DOMAINS).
GIT_AUTH_ALLOW_ANY_HOST bool Insecure. Sends the global GIT_ACCESS_TOKEN or global GitHub App to every HTTP(S) host that no GIT_AUTH_DOMAINS entry matches. Use it only if you accept the risk (see Disabling the Scope). false
SSH_PRIVATE_KEY string The private key used for cloning repositories via SSH. See Setup SSH Key and Domain-scoped Authentication.
SSH_PRIVATE_KEY_FILE string Path to the file containing the SSH private key.
SSH_PRIVATE_KEY_PASSPHRASE string Passphrase for the SSH private key (if the key was generated with a passphrase).
SSH_PRIVATE_KEY_PASSPHRASE_FILE string Path to the file containing the SSH private key passphrase.
SSH_KNOWN_HOSTS_FILE string Optional path to an operator-managed known_hosts file for Git SSH servers. When set, doco-cd never changes this file and rejects unknown or changed host keys.

Credential Scope

Doco-CD selects the HTTP(S) credential for each URL by its host:

  1. Doco-CD finds the GIT_AUTH_DOMAINS entry that matches the host (see Matching Behavior).
  2. If the entry has its own git_access_token or GitHub App, doco-cd uses it.
  3. If the entry has no HTTP(S) credential of its own (only domains, or only an SSH key), doco-cd uses the global GIT_ACCESS_TOKEN or the global GitHub App.
  4. If no entry matches the host, doco-cd sends no HTTP(S) credential. Public repositories still work anonymously. Private repositories fail with an error that names the host. GIT_AUTH_ALLOW_ANY_HOST changes this step.

The port is not part of the match. An entry for git.example.com applies to https://git.example.com:8443/... too.

SSH keys are not affected by these rules. SSH URLs use the matched entry key, then the global SSH_PRIVATE_KEY.

Migrating from Global Credentials

Versions before v0.130.0 sent the global GIT_ACCESS_TOKEN or global GitHub App credentials to every HTTP(S) host, see the Git credential security advisory. By default, doco-cd now refuses to start with an error like this if a global HTTP(S) credential has no scope:

global Git HTTP(S) credentials must be scoped with GIT_AUTH_DOMAINS: GIT_ACCESS_TOKEN is set, but no GIT_AUTH_DOMAINS entry lists the hosts that may receive it. ...

To fix it, add an entry with only domains for each host that the global credential is for:

docker-compose.yml
services:
  doco-cd:
    environment:
      GIT_ACCESS_TOKEN: xxx
      GIT_AUTH_DOMAINS: |
        - domains:
            - github.com

Things to check during the migration:

  • Add every host that you clone from with the global credential. This includes hosts of Compose Git include URLs and submodules.
  • If you use SOURCE_URL_REWRITES, doco-cd selects the credential for the host after the rewrite. Add the rewritten host, not the original host.
  • An entry with its own git_access_token or GitHub App now takes precedence over the global credential for its hosts. Before, the global GIT_ACCESS_TOKEN won over a domain-scoped GitHub App.
  • Every entry must have at least one valid domain. Domains with a scheme, path, port, or a wildcard that is not a leading *. are rejected at startup.
  • If you roll back to an older version, that version ignores the scope and sends the global credential to every HTTP(S) host again.
  • For a self-updating installation, add GIT_AUTH_DOMAINS to the managed Compose file before or together with the version upgrade. Older versions accept an entry with only domains, so you can add it first. If the new version does not start because the scope is missing, doco-cd rolls back and does not retry until a new commit arrives. Push a commit that adds the scope to retry the update.
  • If you run bootstrap.sh from the self-updating example, it forwards GIT_AUTH_DOMAINS and uses github.com if you do not set it.

Limits of the Scope

The scope controls which hosts receive a credential. It does not control which repositories doco-cd deploys from.

  • Doco-CD still clones public repositories from unlisted hosts anonymously.
  • A scoped wildcard such as *.example.com trusts every subdomain. Use exact domains if other people can create subdomains.
  • An attacker who can make a listed host serve content, or who can intercept plain http:// traffic to it, can still get the credential. Use HTTPS.
  • Webhook requests still need a valid WEBHOOK_SECRET. Keep it secret, because anyone with it can trigger deployments of any repository URL.

Disabling the Scope

If you do not want to maintain GIT_AUTH_DOMAINS, you can turn off the scope for the global credential:

docker-compose.yml
services:
  doco-cd:
    environment:
      GIT_ACCESS_TOKEN: xxx
      GIT_AUTH_ALLOW_ANY_HOST: "true"
This brings back the credential leak

With GIT_AUTH_ALLOW_ANY_HOST, doco-cd sends the global GIT_ACCESS_TOKEN or global GitHub App to every HTTP(S) host that no GIT_AUTH_DOMAINS entry matches. Anyone who can choose a repository URL can then get the credential. This includes webhook senders with the WEBHOOK_SECRET, API and MCP clients, and everyone who can change a deployed repository, its Compose include URLs, or its submodules. For a GitHub App, doco-cd sends a short-lived signed App JWT to the API of that host, not the App's private key. The JWT can be used to create installation tokens for the App. Doco-CD logs a warning at every start while this setting is active and a global HTTP(S) credential is configured, including apply-self runs.

Use it only if every source of repository URLs is trusted, and if the credential has the smallest possible permissions (for example a fine-grained token with read-only access to selected repositories).

The setting changes only hosts without a matching entry. GIT_AUTH_DOMAINS entries keep their rules, the redirect protection of the API clients stays active, and commit status reporting still uses the credential of the repository host.

The repository's docker-compose.yml forwards GIT_AUTH_ALLOW_ANY_HOST from .env with a default of false. For a self-updating installation, set the option in the managed Compose service too. bootstrap.sh forwards it only to the one-shot bootstrap container.

SSH Host-Key Verification

Doco-CD supports two host-key trust modes for Git SSH remotes:

  • Operator-managed: Set SSH_KNOWN_HOSTS_FILE to a mounted known_hosts file. Doco-CD treats it as authoritative and read-only. Add both the old and new server keys before a planned rotation, then remove the old key after the rotation.
  • Automatic (default): Leave SSH_KNOWN_HOSTS_FILE unset. Doco-CD obtains a host key on first use and automatically replaces a changed key for the same host and port. This avoids interruption when providers rotate keys, but it trusts the key returned by the network and therefore does not protect against a host-key substitution attack.

Example using a read-only Docker config:

docker-compose.yml
services:
  doco-cd:
    environment:
      SSH_KNOWN_HOSTS_FILE: /run/configs/git_known_hosts
    configs:
      - source: git_known_hosts
        target: /run/configs/git_known_hosts

configs:
  git_known_hosts:
    file: ./known_hosts

Rotating a Mounted Host Key

When a Git server reports a changed key, obtain the new key from a trusted source and add it to the mounted known_hosts file. Doco-CD will then accept the new key on the next connection.

For hosted providers, use the official host-keys. For example GitHub.com or GitLab.com.

Use ssh-keyscan to obtain the host key:

Default SSH port (22)
ssh-keyscan -t ed25519 git.example.com
Custom SSH port (2222)
ssh-keyscan -p 2222 -t ed25519 git.example.com

Required Token Permissions

The token used for HTTP(S) clone/fetch access needs permission to read repository contents. The same requirements apply whether you use the global GIT_ACCESS_TOKEN or a domain-scoped token from GIT_AUTH_DOMAINS.

See below provider-specific setup steps:

You can either use a Personal Access Token (PAT) or a GitHub App.

See the GitHub docs for Personal Access Token (Classic).

  • The minimum required scope is repo

See the GitHub docs for Fine-grained tokens.

  • Repository access
    • Set to Public Repositories (read-only) for only public repositories.
    • Set to All Repositories for all repositories.
  • The minimum required permissions are:
    • Contents -> Read-only
    • Metadata -> Read-only

GitHub Apps are supported natively in Doco-CD.

See the GitHub docs for registering a GitHub Apps.

  • The minimum required permissions are:
    • Repository contents -> Read-only
    • Repository metadata -> Read-only
  1. Go to your user settings.
  2. Click on Applications.
  3. Under Generate New Token:
    1. Fill in the Token Name field.
    2. Set Repository and Organization Access to All
    3. Open Select Permissions and set repository to Read
    4. Click on Generate Token and save the token that is shown on the top of the page.

You can either use a personal access token, a group access token or a project access token for Gitlab.

Which token to use?

Recommended are personal or group access tokens, as they can be used for multiple projects/repositories.

How to create an access token?

See the Gitlab docs for

Token Permissions

  • The role Reporter is sufficient (if asked).
  • The minimum required scope is read_repository.

Domain-scoped Authentication

Use domain-scoped config when you fetch from multiple Git providers/domains and need separate credentials.

Syntax and Format

The domain-scoped authentication configuration is a YAML list where each entry defines credentials for one or more domains.

Entry Structure

Each entry in the list has the following structure:

- domains:                          # (Required) List of domain names or patterns
    - domain1.com
    - domain2.com
    - '*.example.com'
  git_access_token: xxx             # (Optional) HTTP token for git access. If omitted, the global credential is used
  git_access_token_user: oauth2     # (Optional) Username for git_access_token (e.g. gitlab+deploy-token-1234567)
  ssh_private_key: |                # (Optional) SSH private key content
    -----BEGIN OPENSSH PRIVATE KEY-----
    ...
    -----END OPENSSH PRIVATE KEY-----
  ssh_private_key_passphrase: xxx   # (Optional) Passphrase for encrypted SSH key
Available Options
Field Type Required Description
domains list Yes List of host names to apply these credentials to. Supports exact domains and wildcard patterns. Must not contain a scheme, path, or port. An entry with only domains scopes the global HTTP(S) credential to these hosts.
git_access_token string No HTTP(S) access token for authenticating with the Git provider. Cannot be used with ssh_private_key.
git_access_token_user string No Username paired with git_access_token. Defaults to oauth2. Set it when your provider needs a specific username for the token (e.g. a GitLab deploy token uses gitlab+deploy-token-1234567).
ssh_private_key string No SSH private key content (multi-line). Cannot be used with git_access_token.
ssh_private_key_passphrase string No Passphrase for the SSH private key if it was generated with encryption. Only used with ssh_private_key.
github_app_id string No GitHub App ID. Requires github_app_private_key. Cannot be used with git_access_token or ssh_private_key.
github_app_private_key string No GitHub App private key (PEM). Requires github_app_id. Cannot be used with git_access_token or ssh_private_key.
github_app_installation_id number No Optional installation ID override for this domain entry. If omitted, installation is auto-detected by owner/repo.
Authentication Method Selection
  • Use git_access_token for HTTP(S) based Git access
  • Use ssh_private_key (and optionally ssh_private_key_passphrase) for SSH-based Git access
  • Use github_app_id + github_app_private_key for GitHub App based HTTP(S) access
  • Do not mix methods in the same entry

Matching Behavior

  • Exact domain match wins over wildcard entries.
  • If multiple wildcard patterns match, the longest suffix wins (most specific).
  • Wildcards only match subdomains. Example: *.example.com matches git.example.com, but not example.com.
  • If the matched entry has no HTTP(S) credential of its own, doco-cd uses the global GIT_ACCESS_TOKEN or GitHub App for HTTP(S) URLs.
  • If no domain entry matches, doco-cd sends no HTTP(S) credential. For SSH URLs, it uses the global SSH_PRIVATE_KEY if set.
  • Submodule remotes are resolved independently, so each submodule can use credentials for its own domain.

Examples

docker-compose.yml
services:
  app:
    environment:
      GIT_AUTH_DOMAINS: |
        # Example value for GIT_AUTH_DOMAINS
        - domains:
            - github.com
          github_app_id: "123456"
          github_app_private_key: |
            -----BEGIN RSA PRIVATE KEY-----
            ...
            -----END RSA PRIVATE KEY-----
          # Optional: pin a known installation id. If omitted, doco-cd resolves it by owner/repo.
          # github_app_installation_id: 987654321

        - domains:
            - gitlab.com
            - '*.corp.example.com'
          ssh_private_key: |
            -----BEGIN OPENSSH PRIVATE KEY-----
            ...
            -----END OPENSSH PRIVATE KEY-----
          ssh_private_key_passphrase: ""

        - domains:
            - gitlab.example.com
          # GitLab deploy token: git_access_token_user must be the deploy token's username.
          git_access_token: "gldt-xxxxxxxxxxxxxxxxxxxx"
          git_access_token_user: gitlab+deploy-token-1234567

        # No own HTTP credential: these hosts receive the global GIT_ACCESS_TOKEN or GitHub App.
        - domains:
            - git.example.com

You can also store the YAML in a file and load it with GIT_AUTH_DOMAINS_FILE.

git-auth-domains.yaml
# Example value for GIT_AUTH_DOMAINS
- domains:
    - github.com
  github_app_id: "123456"
  github_app_private_key: |
    -----BEGIN RSA PRIVATE KEY-----
    ...
    -----END RSA PRIVATE KEY-----
  # Optional: pin a known installation id. If omitted, doco-cd resolves it by owner/repo.
  # github_app_installation_id: 987654321

- domains:
    - gitlab.com
    - '*.corp.example.com'
  ssh_private_key: |
    -----BEGIN OPENSSH PRIVATE KEY-----
    ...
    -----END OPENSSH PRIVATE KEY-----
  ssh_private_key_passphrase: ""

- domains:
    - gitlab.example.com
  # GitLab deploy token: git_access_token_user must be the deploy token's username.
  git_access_token: "gldt-xxxxxxxxxxxxxxxxxxxx"
  git_access_token_user: gitlab+deploy-token-1234567

# No own HTTP credential: these hosts receive the global GIT_ACCESS_TOKEN or GitHub App.
- domains:
    - git.example.com
docker-compose.yml
services:
  app:
    environment:
      GIT_AUTH_DOMAINS_FILE: /run/secrets/git_auth_domains
    secrets:
      - git_auth_domains

secrets:
  git_auth_domains:
    file: ./git-auth-domains.yaml

GitHub Apps

GitHub Apps are supported natively and can be configured globally (see below) or per domain. Doco-CD will auto-detect the installation by repository owner/name and mint short-lived installation access tokens. The detected installation ID is cached for an hour, and looked up again earlier if the App is reinstalled; set GITHUB_APP_INSTALLATION_ID to skip the lookup entirely.

A global GitHub App needs a GIT_AUTH_DOMAINS entry without its own HTTP(S) credential, for example - domains: [github.com], the same as a global GIT_ACCESS_TOKEN (see Credential Scope). Doco-CD calls the GitHub API with the App credentials only for hosts in that scope. These calls do not follow redirects to another host.

Installation tokens cannot access gists

gist URLs (for example, gist submodules) use a configured access token or anonymous access instead.

Key Type Description Default value
GITHUB_APP_ID string ID of the GitHub App, used to mint installation access tokens for GitHub repositories. Requires GITHUB_APP_PRIVATE_KEY. Mutually exclusive with global GIT_ACCESS_TOKEN.
GITHUB_APP_ID_FILE string Path to the file containing GITHUB_APP_ID (mutually exclusive with GITHUB_APP_ID).
GITHUB_APP_PRIVATE_KEY string GitHub App private key in PEM format. Requires GITHUB_APP_ID.
GITHUB_APP_PRIVATE_KEY_FILE string Path to the file containing GITHUB_APP_PRIVATE_KEY (mutually exclusive with GITHUB_APP_PRIVATE_KEY).
GITHUB_APP_INSTALLATION_ID number Optional installation ID override for global GitHub App auth. If unset, doco-cd resolves installation by owner/repository automatically. 0 (auto-detect)

Commit Status Reporting

Doco-CD can report deployment outcomes to the source Git provider, making the result visible directly on the commit or pull request in the Git web UI. Reporting is disabled by default. Enable it with GIT_COMMIT_STATUS=true.

This closes the GitOps feedback loop: instead of only seeing success or failure in container logs or Apprise notifications, the commit itself is marked with the deployment outcome.

Once pre-deployment checks confirm work is needed, Doco-CD reports each deployment under its existing name, doco-cd/<stack> or doco-cd/<target>/<stack> when a target is configured. Queued reporting is published before waiting for a mutation admission slot.

Deployments excluded by a webhook reference filter or requiring no changes do not receive deployment-specific checks or statuses. When the entire webhook run is skipped, Doco-CD reports a run-level result under doco-cd/<target>/deploy when a target is configured, or doco-cd/deploy otherwise. The same target-aware name is used for Git clone failures and failures before deployment configuration can be resolved, including polling runs. This keeps failures and skipped runs for different targets separate on the same commit.

While a deployment runs, its check or status also shows the current deployment phase, the same one logged by the deployment in progress heartbeat, for example pulling images or waiting for services to start. A phase is only published once it has lasted 3 seconds, so short phases cost no API requests. Phase updates are best-effort: each is sent once without retries, a provider rate limit pauses them for the rest of the deployment, and the final result always replaces them.

The resolved authentication method selects the reporting backend:

  • GitHub App installation authentication uses native check runs.
  • Token-only authentication (classic or fine-grained PAT, or OAuth token) keeps using commit statuses, not native Checks.

Each attempt uses only one backend; configuring an App elsewhere does not change reporting for a repository whose resolved credentials are token-only.

Deployment state GitHub App check run GitHub commit status (token-only)
Waiting for deployment admission queued pending / Queued
Deferred by a sync window queued pending / Deferred by sync window
Admitted and deploying in_progress pending / In Progress
Deployment phase lasting 3s or longer in_progress, titled Deploying: phase pending / In Progress: phase
All deployment stages succeeded completed / success success
Deployment failed completed / failure error / failure
Deployment deadline or readiness timed out completed / timed_out error / failure
Entire webhook run skipped completed / skipped success / Skipped: reason

The check run of a skipped webhook run also lists every stack with its skip reason and details in its summary, such as the webhook filter that did not match.

Successful check runs keep the title Deployed and show a summary of the stack, configuration target (when set), Docker context, deployed reference and commit, deployment mode, trigger, and detected changed services.

The reference and commit describe the revision actually deployed, which can differ from the triggering webhook. Service names reflect detected changes, including image changes; they are not an exhaustive list of recreated services. When no individual names were recorded, such as for a first deployment or a whole-stack recreation, the summary shows Not individually tracked. Unavailable optional metadata is omitted. Token-only GitHub authentication and other providers retain their short commit-status descriptions.

Native timed_out is reserved for an actual deployment deadline or readiness timeout, not errors whose text merely mentions a timeout. A deployment deferred by a sync window resumes its original check run on retry.

Skipped checks and branch protection

GitHub displays the native skipped conclusion separately, but treats it as passing for a required check. The overall Checks passed banner can therefore remain.

Check runs and commit statuses with the same name can have different source-bound branch protection requirements. Review and, if necessary, update required checks manually when switching backends; doco-cd does not change branch protection settings.

Deployment state Commit status Description
Waiting for deployment admission pending Queued
Deferred by a sync window pending Deferred by sync window
Admitted and deploying running In Progress
All deployment stages succeeded success Successful in duration
Deployment failed failed Failure reason
Deployment deadline or readiness timed out failed Failure reason
Entire webhook run skipped skipped Skipped: reason

GitLab has no timed-out state, so timeouts are reported as failed. GitLab cannot move a status that is already pending or running back into the same state, so a later queued or deferred update keeps the existing description. For the same reason, deployment phases are not shown and a running deployment keeps the description In Progress.

Skipped pipelines and merge checks

If doco-cd's status is the only job in a commit's pipeline, a skipped webhook run makes that pipeline skipped. With Pipelines must succeed enabled, also enable Skipped pipelines are considered successful to merge such commits.

Deployment state Commit status Description
Waiting for deployment admission pending Queued
Deferred by a sync window pending Deferred by sync window
Admitted and deploying pending In Progress
Deployment phase lasting 3s or longer pending In Progress: phase
All deployment stages succeeded success Successful in duration
Deployment failed error / failure Failure reason
Deployment deadline or readiness timed out error / failure Failure reason
Entire webhook run skipped skipped on Gitea 1.25+ and Forgejo 16+, else success Skipped: reason

Gitea and Forgejo have no separate queued, running, or timed-out states. Their versions are detected through /api/v1/version and cached for one hour. Older versions store unknown states without validation, which would leave required checks pending, so they keep receiving success for skipped runs.

Deployment state Commit status Description
Waiting for deployment admission pending Queued
Deferred by a sync window pending Deferred by sync window
Admitted and deploying pending In Progress
Deployment phase lasting 3s or longer pending In Progress: phase
All deployment stages succeeded succeeded Successful in duration
Deployment failed error / failed Failure reason
Deployment deadline or readiness timed out error / failed Failure reason
Entire webhook run skipped notApplicable Skipped: reason

Azure DevOps has no separate queued, running, timed-out, or skipped states. Skipped webhook runs use notApplicable, its closest equivalent.

When doco-cd updates itself, the instance that finishes the handover completes the original reporting backend and target, even if the update disables GIT_COMMIT_STATUS. The finishing instance must still have credentials with the required permissions.

Key Type Description Default
GIT_COMMIT_STATUS boolean Enable deployment reporting. Resolved GitHub App installation authentication uses native Checks and requires Checks: Read and write; token-only GitHub authentication and other providers use commit statuses with the permissions below. App reporting reuses the installation token minted for git operations; no separate token is needed. false
GIT_SCM_PROVIDER string Override automatic SCM provider detection. Accepted values: auto, github, gitlab, gitea, forgejo, azuredevops. Set to auto to detect the provider from the repository URL. Required when your self-hosted instance hostname does not reveal the product (e.g. git.mycompany.com running GitLab must set gitlab). auto
GIT_SCM_API_URL string Optional override for the SCM API base URL used by commit status and native GitHub Checks requests (must be http:// or https://). Use this for self-hosted instances when the API endpoint cannot be inferred from the clone URL (for example when SSH and HTTPS use different hosts/ports: https://gitea.example.com:8443).

Required Token Permissions

Token-based reporting needs permission to write commit statuses through the provider API, whether credentials come from the global GIT_ACCESS_TOKEN or a domain-scoped token in GIT_AUTH_DOMAINS.

Doco-CD uses the credential that is scoped to the repository host for reporting. If no credential is scoped to that host, doco-cd logs a warning and does not report. Reporting requests do not follow redirects to another host, so the credential cannot go to a different server.

If an access token is also used to clone Git repositories over HTTP(S) (see Authentication), add the permission below in addition to the existing clone permissions required by your provider (see Required Token Permissions above).

Token type Required permission
Classic PAT / OAuth token repo:status is the minimum recommended scope. repo also works, but grants broader repository access than necessary.
Fine-grained PAT Repository permission Commit statuses: Read and write (token-only reporting remains on commit statuses)
GitHub App installation token Repository permission Checks: Read and write; keep Commit statuses: Read and write for older pending self-update handovers

GitHub Apps reuse their installation token

When the repository's resolved authentication is a GitHub App installation, doco-cd reuses its short-lived git clone/fetch token to create and update check runs. Grant the App the Checks: Read and write repository permission in addition to its existing clone permissions; no additional PAT is required.

For an existing App previously using Commit statuses: Read and write, enable the additional Checks: Read and write permission in the App settings and approve the updated permissions for its installation. Keep Commit statuses: Read and write during pending self-update handovers from older versions: journals without a check-run target must still finish their legacy commit statuses, even with newer App configuration.

Token type Required permission
Personal, project, or group access token api scope

Why GitLab needs api instead of write_repository

Doco-CD posts commit statuses through the GitLab REST API. The write_repository scope covers Git-over-HTTP push access, but does not grant general REST API write access.

Token type Required permission
API access token Must be allowed to write repository API endpoints. On Forgejo scoped tokens, use write:repository. Some Gitea versions expose different token controls, so ensure the token can create commit statuses for the target repository.

Doco-CD also reads /api/v1/version with the same token to detect support for the native skipped state. If the version cannot be read, skipped runs are reported as success.

Token type Required permission
Personal Access Token (PAT) Token must allow Git status writes on the target repo (for example Code (Read & write) in the PAT scopes).

Provider Auto-Detection

When GIT_SCM_PROVIDER is not set, doco-cd detects the provider from the repository URL:

Hostname pattern Detected provider
github.com GitHub
gitlab.com GitLab
dev.azure.com, ssh.dev.azure.com, *.visualstudio.com Azure DevOps
Anything else Gitea / Forgejo

Self-hosted instances

Set GIT_SCM_PROVIDER explicitly when running a self-hosted SCM/Git provider instance and the auto-detection cannot determine the correct provider.

  • GitHub Enterprise Server: set GIT_SCM_PROVIDER=github
  • Self-hosted GitLab: set GIT_SCM_PROVIDER=gitlab
  • Self-hosted Gitea / Forgejo: set GIT_SCM_PROVIDER=gitea or GIT_SCM_PROVIDER=forgejo

Self-Hosted Instances and API URL

Doco-CD derives the SCM API base URL from the clone URL by converting its scheme to https://. This works correctly for most setups, but two scenarios require an explicit override via GIT_SCM_API_URL:

SSH clone URL with a non-standard SSH port

When the clone URL is an SSH URL with a custom port (e.g. ssh://git@gitea.example.com:2222/org/repo.git), doco-cd strips the port before building the API URL so the API call targets https://gitea.example.com/... correctly. If for any reason this stripping doesn't produce the right host or port (e.g. the HTTPS endpoint is on a non-standard port), set the API base URL explicitly:

GIT_SCM_API_URL: "https://gitea.example.com:8443"

SSH and HTTPS served from different hostnames or ports

Some self-hosted setups route SSH clones through a dedicated hostname or port (e.g. git.internal:2222) while the HTTPS API is on a different address (e.g. https://git.example.com). In that case the auto-derived URL will be wrong regardless of port stripping:

GIT_SCM_API_URL: "https://git.example.com"

For commit status reporting, configure GIT_SCM_API_URL as an http:// or https:// URL pointing to the root of the SCM instance (no path, no trailing slash). Provider-specific API paths (e.g. /api/v1, /api/v4) are appended automatically.

This override also applies to native GitHub Checks requests. For GitHub Enterprise Server, a root URL automatically gains /api/v3; an explicit API prefix such as https://ghe.example.com/api/v3 is used as-is. Set GIT_SCM_PROVIDER=github as described above.

Example

docker-compose.yml
services:
  app:
    environment:
      GIT_ACCESS_TOKEN: xxx         # token must be allowed to write commit statuses
      GIT_AUTH_DOMAINS: |           # hosts that receive GIT_ACCESS_TOKEN
        - domains: [github.com]
      GIT_COMMIT_STATUS: "true"
      # GIT_SCM_PROVIDER: gitlab   # uncomment for self-hosted GitLab at a custom domain
      # GIT_SCM_API_URL: https://git.example.com  # optional explicit API base URL override