> ## Documentation Index
> Fetch the complete documentation index at: https://docs.coderabbit.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Self-managed GitLab

> Learn how to integrate CodeRabbit with your self-managed GitLab instance through automated or manual onboarding, including OAuth setup, user configuration, and webhook installation.

<Info>
  For an overview of how CodeRabbit integrates with Git platforms, see [Add
  CodeRabbit to your repository](/platforms).
</Info>

<Warning>
  **Version Requirements**

  CodeRabbit supports GitLab `16.x` and above. Version `15.x` may experience unexpected issues such as review comments not being posted or the sign-up process not working at all. We recommend upgrading your GitLab instance to obtain the intended experience.
</Warning>

## Getting Started

To integrate your self-managed GitLab with CodeRabbit, we require specific information for the initial setup within your domain. Once this setup is complete, you can log in directly using the OAuth2 flow.

<Steps>
  <Step title="Visit CodeRabbit login page">
    Navigate to the [CodeRabbit login page](https://app.coderabbit.ai/login?free-trial) and select **Self-Hosted GitLab**.

    <img src="https://mintcdn.com/coderabbit/69LGK0BhaHIxrC15/images/platforms/assets/images/login-self-hosted-gitlab-34542f78a7edb731c7dc0d07e9145088.png?fit=max&auto=format&n=69LGK0BhaHIxrC15&q=85&s=efb7e3419898b356f71955db36aefa07" alt="CodeRabbit login" width="1920" height="1080" data-path="images/platforms/assets/images/login-self-hosted-gitlab-34542f78a7edb731c7dc0d07e9145088.png" />
  </Step>

  <Step title="Enter your GitLab instance URL">
    Enter the URL of your self-managed GitLab instance and click **Submit**. We'll check our database for an existing record of your organization and start the login process if found.

    <img src="https://mintcdn.com/coderabbit/69LGK0BhaHIxrC15/images/platforms/assets/images/self-hosted-gitlab-host-url-cd6401db765c1fb24f1faf9c5880fbe9.png?fit=max&auto=format&n=69LGK0BhaHIxrC15&q=85&s=1338db0d89adebe3062e9269de8b2135" alt="Self-hosted Gitlab enterprise connection page" width="1444" height="1065" data-path="images/platforms/assets/images/self-hosted-gitlab-host-url-cd6401db765c1fb24f1faf9c5880fbe9.png" />

    If your self-managed GitLab instance is not found, we'll initiate the onboarding process.
  </Step>

  <Step title="Choose onboarding method">
    You can choose between automated or manual onboarding based on your security
    preferences and administrative access.
  </Step>
</Steps>

## Onboarding Options

### Automated Onboarding (Recommended)

<img src="https://mintcdn.com/coderabbit/69LGK0BhaHIxrC15/images/platforms/assets/images/automated-onboarding-def5b25271299f245653c9912d5335cf.png?fit=max&auto=format&n=69LGK0BhaHIxrC15&q=85&s=3d4c963af77f75bed1f3e931b6470015" alt="Self-managed GitLab connection page" width="1002" height="1108" data-path="images/platforms/assets/images/automated-onboarding-def5b25271299f245653c9912d5335cf.png" />

<Info>
  **Why do we need the Admin Access Token?**

  The admin access token is required to set up a new CodeRabbit bot user within your self-managed instance. The token is needed only once during the initial setup process. Once generated, you can set its minimum expiration period. This is the standard approach used by other products in this category.

  Note: This does not automatically install the CodeRabbit app across all projects. You will add CodeRabbit manually to the projects you wish to integrate.
</Info>

### Manual Onboarding

For the manual onboarding process, you need to create the [CodeRabbit user](#creating-coderabbit-user) and the [OAuth2 GitLab application](#creating-oauth2-application).

<img src="https://mintcdn.com/coderabbit/69LGK0BhaHIxrC15/images/platforms/assets/images/manual-onboarding-cbcc14b5298275dad4d9484ae7bb0201.png?fit=max&auto=format&n=69LGK0BhaHIxrC15&q=85&s=b5a5ac5a2e3909e17d0c10bee0f41d11" alt="Self-managed GitLab connection page" width="1420" height="1214" data-path="images/platforms/assets/images/manual-onboarding-cbcc14b5298275dad4d9484ae7bb0201.png" />

#### Creating CodeRabbit User

This feature will work with any user from your organization, but we strongly recommend creating a dedicated user called **CodeRabbitAI**. This ensures clarity about which user is used for our application and allows for better fine-grained access control.

<Info>
  To interact with CodeRabbit in merge request comments, use `@coderabbitai` — or the username of the user you create here, if it differs.
</Info>

<Steps>
  <Step title="Create the user">
    Log in with an instance admin account and follow the steps provided in the
    [GitLab
    documentation](https://docs.gitlab.com/ee/user/profile/account/create_accounts.html#create-users-in-admin-area)
    to create a new user.
  </Step>

  <Step title="Retrieve user information">
    After the user is created, retrieve the **User ID** from that user's profile.
  </Step>

  <Step title="Generate access token">
    Generate an [**access token**](#generating-personal-access-token) for this
    user. The access token is used to post reviews on merge requests.
  </Step>
</Steps>

<Tip>
  **Recommendations for the CodeRabbit user:** - Use **"CodeRabbitAI"** as the
  username for easy identification - Use the CodeRabbit
  [logo](https://www.coderabbit.ai/brand) as the profile picture for easy
  recognition - Ensure the user has appropriate permissions for the repositories
  you want to integrate
</Tip>

<Note>
  If you prefer, you can create a Group Access Token which will create a
  dedicated user on your behalf. For more information, see [Group Access
  Token](/platforms/gitlab-com#group-access-token).
</Note>

#### Creating OAuth2 Application

For self-managed GitLab, we recommend creating an instance-wide application unless you want the reviews to be limited to a single group or user.

Follow the steps outlined in the [GitLab documentation](https://docs.gitlab.com/ee/integration/oauth_provider.html#create-an-instance-wide-application) for creating the application.

<Check>
  **OAuth2 Application Requirements:**

  * **Scopes:** `api read_user email openid`
  * **Callback URL:** `https://app.coderabbit.ai/login`
</Check>

#### Generating Personal Access Token

GitLab offers an option to generate a personal access token for adding a new user and setting up the application in the self-managed instance.

<Steps>
  <Step title="Login to your instance">
    Login to your self-hosted instance. For [automated
    onboarding](#automated-onboarding-recommended), ensure you have admin rights.
  </Step>

  <Step title="Access user settings">
    On the left sidebar, select your avatar, then select **Edit profile**.
  </Step>

  <Step title="Navigate to Access Tokens">
    On the left sidebar, select **Access Tokens**.
  </Step>

  <Step title="Create new token">Select **Add new token**.</Step>

  <Step title="Configure token settings">
    * Enter a name and expiry date for the token
    * We need this for the initial setup, so the minimum expiry time is sufficient
    * If you do not enter an expiry date, it defaults to 365 days from the current date
    * Select the required scopes: `api`, `read_api`, `read_user`
  </Step>

  <Step title="Generate and save token">
    Select **Create personal access token** and note down the token as it will
    only be displayed once.
  </Step>
</Steps>

<img src="https://mintcdn.com/coderabbit/69LGK0BhaHIxrC15/images/platforms/assets/images/admin-access-token-af3409806464ede4a0ca595ae6d55cb5.png?fit=max&auto=format&n=69LGK0BhaHIxrC15&q=85&s=95ef3f37a1091943d0f6d473be7fffb9" alt="GitLab personal access token configuration page" width="1816" height="941" data-path="images/platforms/assets/images/admin-access-token-af3409806464ede4a0ca595ae6d55cb5.png" />

### **Paste the details and click submit**

* Submit the form.
* We will handle the setup process for you.
* On subsequent visits, your setup will be automatically detected, allowing for direct login. <img src="https://mintcdn.com/coderabbit/69LGK0BhaHIxrC15/images/platforms/assets/images/self-hosted-page-2a7e05c97d521f766915edb8223b2dd9.png?fit=max&auto=format&n=69LGK0BhaHIxrC15&q=85&s=e147d511e70db01cb5713195ba422522" alt="CodeRabbit authentication options page" width="1794" height="1190" data-path="images/platforms/assets/images/self-hosted-page-2a7e05c97d521f766915edb8223b2dd9.png" />

### **Allow list CodeRabbit IP address**

Use this CodeRabbit IP if your instance requires IP allow listing.

<CodeGroup>
  ```text IPs to allow list theme={null}
  35.222.179.152/32, 34.170.211.100/32, 136.113.208.247/32
  ```
</CodeGroup>

### Manual webhook installation

Use this flow when you need to install the webhook manually or rotate the shared webhook secret. The **Webhook Secret** page is available for both GitLab.com and self-managed GitLab.

<Steps>
  <Step title="Open Webhook Secret settings">
    In the CodeRabbit app, open **Account** and select **Webhook Secret** from the sidebar.
  </Step>

  <Step title="Copy the webhook URL">
    Use the **Webhook URL** field on that page to copy the exact endpoint that your GitLab instance should call.
  </Step>

  <Step title="Save or change the webhook secret">
    Enter the secret that GitLab should send with webhook deliveries and save it in CodeRabbit.
  </Step>

  <Step title="Configure the GitLab webhook">
    When creating or editing the webhook in GitLab, use the copied webhook URL and enable these settings:

    * **Merge request events**
    * **Comments**
    * **Issues events**
    * **SSL verification** enabled
  </Step>
</Steps>

<Info>
  If you change an existing webhook secret, CodeRabbit attempts to update existing CodeRabbit-managed GitLab project and group webhooks automatically. If a webhook was created manually, or if an automatic refresh fails, update the secret directly in GitLab.
</Info>

### Bulk webhook installation

For administrators managing many GitLab projects, you can use a script to bulk-install webhooks across all projects.

<Steps>
  <Step title="Login to CodeRabbit UI">
    Login to CodeRabbit UI through your GitLab self-managed instance.
  </Step>

  <Step title="Copy the webhook URL and secret">
    Follow the [Manual webhook installation](#manual-webhook-installation) steps above to get your webhook URL and save a webhook secret in CodeRabbit.
  </Step>

  <Step title="Run script to install webhooks">
    Use a script to install webhooks across your GitLab projects or groups. Below is a sample script that requires:

    * Your GitLab host URL
    * The webhook URL you copied in the previous step
    * The webhook secret you saved in the previous step
    * A GitLab access token with API permissions

    <Accordion title="gitlab-webhook.sh script">
      ```bash theme={null}
      #!/usr/bin/env bash

      ## gitlab-webhook.sh

      # Add a webhook to one project, or every project in a subgroup tree

      set -euo pipefail

      usage() {
        cat <<EOF
      Usage:
        $0 -h <gitlab-host> -u <webhook-url> -s <webhook-secret> \\
           [-t <access-token>] [-A <auth-header>] [-p <project> | -g <group>] [-v]

      Required:
        -h  GitLab host (e.g. gitlab.example.com)
        -u  Webhook endpoint URL to receive POSTs
        -s  Webhook secret token (used for signature verification)

      Authentication (one of):
        -t  Access token (PAT, project, group or OAuth). If omitted, \$GITLAB_TOKEN is used
        -A  Auth header to use. Default detects:
              PAT → "PRIVATE-TOKEN"
              anything else → "Authorization: Bearer"

      Scope (choose one):
        -p  Project ID or full path (e.g. 42 or group/app)
        -g  Group ID or full path, recurse through all subgroups & projects

      Options:
        -v  Verbose output (show individual project IDs in final summary)
      EOF
        exit 1
      }

      HOST="" HOOK_URL="" HOOK_SECRET=""
      TOKEN="${GITLAB_TOKEN:-}" AUTH_HEADER=""
      PROJECT="" GROUP="" VERBOSE=false

      while getopts "h:u:s:t:A:p:g:v" opt; do
        case "$opt" in
          h) HOST=$OPTARG ;;
          u) HOOK_URL=$OPTARG ;;
          s) HOOK_SECRET=$OPTARG ;;
          t) TOKEN=$OPTARG ;;
          A) AUTH_HEADER=$OPTARG ;;
          p) PROJECT=$OPTARG ;;
          g) GROUP=$OPTARG ;;
          v) VERBOSE=true ;;
          *) usage ;;
        esac
      done

      # Mandatory checks

      [[ -z $HOST || -z $HOOK_URL || -z $HOOK_SECRET ]] && usage
      [[ -n $PROJECT && -n $GROUP ]] && usage
      [[ -z $PROJECT && -z $GROUP ]] && usage

      # Token handling

      if [[ -z $TOKEN ]]; then
        echo "[ERROR] No access token provided. Use -t or set \$GITLAB_TOKEN" >&2
        exit 1
      fi

      # Choose header if not forced

      if [[ -z $AUTH_HEADER ]]; then
        if [[ $TOKEN == glpat-* || $TOKEN == "PAT-"* ]]; then
          AUTH_HEADER="PRIVATE-TOKEN"
        else
          AUTH_HEADER="Authorization: Bearer"
        fi
      fi

      API="https://${HOST}/api/v4"
      CURL_BASE=(curl -sSf --header "${AUTH_HEADER}: ${TOKEN}")

      # Track processed projects to avoid duplicates

      declare -A PROCESSED_PROJECTS
      WEBHOOK_PROJECTS=()
      EXISTING_WEBHOOK_PROJECTS=()
      TOTAL_PROJECTS_FOUND=0
      PROJECTS_PROCESSED=0

      url_encode() {
        local string="$1"
        printf '%s' "$string" | sed 's/\//%2F/g; s/ /%20/g; s/@/%40/g; s/:/%3A/g; s/#/%23/g; s/?/%3F/g; s/&/%26/g; s/=/%3D/g; s/+/%2B/g'
      }

      fetch_paginated() {
        local url=$1
        local page=1
        local per_page=100

        while true; do
          local paginated_url
          if [[ "$url" == *"?"* ]]; then
            paginated_url="${url}&per_page=${per_page}&page=${page}"
          else
            paginated_url="${url}?per_page=${per_page}&page=${page}"
          fi

          local response
          response=$("${CURL_BASE[@]}" "$paginated_url" 2>/dev/null) || {
            echo "[ERROR] Failed to fetch page $page from $url" >&2
            return 1
          }

          if [[ "$response" == "[]" || "$response" == "null" ]]; then
            break
          fi

          local page_results
          page_results=$(echo "$response" | jq -r '.[].id' 2>/dev/null) || {
            echo "[ERROR] Failed to parse JSON response from page $page" >&2
            return 1
          }

          if [[ -z "$page_results" ]]; then
            break
          fi

          local page_count
          page_count=$(echo "$page_results" | wc -l)
          TOTAL_PROJECTS_FOUND=$((TOTAL_PROJECTS_FOUND + page_count))
          echo "[PROGRESS] Found $page_count projects on page $page (total: $TOTAL_PROJECTS_FOUND)" >&2

          echo "$page_results"

          local item_count
          item_count=$(echo "$response" | jq '. | length' 2>/dev/null) || 0
          if [[ "$item_count" -lt "$per_page" ]]; then
            break
          fi

          ((page++))
        done
      }

      create_hook() {
        local pid=$1

        if [[ -n "${PROCESSED_PROJECTS[$pid]:-}" ]]; then
          return 0
        fi

        PROCESSED_PROJECTS[$pid]=1
        PROJECTS_PROCESSED=$((PROJECTS_PROCESSED + 1))

        local encoded_pid
        if [[ $pid =~ ^[0-9]+$ ]]; then
          encoded_pid=$pid
        else
          encoded_pid=$(url_encode "$pid")
        fi

        local existing_webhooks
        existing_webhooks=$("${CURL_BASE[@]}" "${API}/projects/${encoded_pid}/hooks" 2>/dev/null) || {
          echo "[ERROR] Failed to fetch existing webhooks for project $pid" >&2
          return 1
        }

        if echo "$existing_webhooks" | jq -e --arg url "$HOOK_URL" '.[] | select(.url == $url)' >/dev/null 2>&1; then
          [[ "$VERBOSE" == "true" ]] && echo "[INFO] Webhook already exists for project: $pid" >&2
          EXISTING_WEBHOOK_PROJECTS+=("$pid")
          return 0
        fi

        [[ "$VERBOSE" == "true" ]] && echo "[INFO] Adding webhook to project: $pid" >&2

        "${CURL_BASE[@]}" --request POST \
          --data-urlencode "url=${HOOK_URL}" \
          --data "token=${HOOK_SECRET}" \
          --data "push_events=true" \
          --data "note_events=true" \
          --data "issues_events=true" \
          --data "merge_requests_events=true" \
          --data "enable_ssl_verification=true" \
          "${API}/projects/${encoded_pid}/hooks" \
          > /dev/null

        WEBHOOK_PROJECTS+=("$pid")
      }

      traverse_group() {
        local gid=$1
        local encoded_gid
        if [[ $gid =~ ^[0-9]+$ ]]; then
          encoded_gid=$gid
        else
          encoded_gid=$(url_encode "$gid")
        fi

        while IFS= read -r pid; do
          [[ -n "$pid" ]] && create_hook "$pid"
        done < <(
          fetch_paginated "${API}/groups/${encoded_gid}/projects?include_subgroups=true"
        )

        while IFS= read -r sg; do
          [[ -n "$sg" ]] && traverse_group "$sg"
        done < <(
          fetch_paginated "${API}/groups/${encoded_gid}/subgroups"
        )
      }

      echo "[INFO] Starting webhook processing..." >&2

      if [[ -n $PROJECT ]]; then
        echo "[INFO] Processing single project: $PROJECT" >&2
        create_hook "$PROJECT"
      else
        echo "[INFO] Processing group and subgroups: $GROUP" >&2
        traverse_group "$GROUP"
      fi

      echo "[INFO] Finished processing all projects" >&2

      total_projects=$((${#WEBHOOK_PROJECTS[@]} + ${#EXISTING_WEBHOOK_PROJECTS[@]}))

      if [[ $total_projects -eq 0 ]]; then
        echo "[INFO] No projects were processed"
      else
        if [[ ${#WEBHOOK_PROJECTS[@]} -gt 0 ]]; then
          if [[ "$VERBOSE" == "true" ]]; then
            echo "[INFO] Webhooks installed successfully on ${#WEBHOOK_PROJECTS[@]} project(s):"
            for pid in "${WEBHOOK_PROJECTS[@]}"; do
              echo "  - Project ID: $pid"
            done
          else
            echo "[INFO] Webhooks installed successfully on ${#WEBHOOK_PROJECTS[@]} project(s)"
          fi
        fi

        if [[ ${#EXISTING_WEBHOOK_PROJECTS[@]} -gt 0 ]]; then
          if [[ "$VERBOSE" == "true" ]]; then
            echo "[INFO] Webhooks already existed on ${#EXISTING_WEBHOOK_PROJECTS[@]} project(s):"
            for pid in "${EXISTING_WEBHOOK_PROJECTS[@]}"; do
              echo "  - Project ID: $pid"
            done
          else
            echo "[INFO] Webhooks already existed on ${#EXISTING_WEBHOOK_PROJECTS[@]} project(s)"
          fi
        fi

        echo "[INFO] Total projects processed: $total_projects"
      fi

      ```
    </Accordion>

    ```bash theme={null}
    # Make sure the script is executable:
    chmod +x gitlab-webhook.sh
    ```

    #### Example: Install webhook on a single project

    ```bash theme={null}
    export GITLAB_TOKEN="glpat-xxxxx"
    ./gitlab-webhook.sh \
      -h "gitlab.example.com" \
      -u "https://coderabbit.ai/gitlabHandler" \
      -s "your-webhook-secret" \
      -p 42
    ```

    #### Example: Install webhooks on all projects in a group (including subgroups)

    ```bash theme={null}
    export GITLAB_TOKEN="glpat-xxxxx"
    ./gitlab-webhook.sh \
      -h "gitlab.example.com" \
      -u "https://coderabbit.ai/gitlabHandler" \
      -s "your-webhook-secret" \
      -g "mygroup/mysubgroup"
    ```
  </Step>
</Steps>

## SSH repository access

By default, CodeRabbit clones your GitLab projects over HTTPS. If HTTPS is not available or your organization prefers SSH for repository access, you can configure SSH clone credentials in the CodeRabbit web app.

### Prerequisites

* An SSH key pair generated **without a passphrase**. CodeRabbit cannot use passphrase-protected keys.
* The public key must be registered on the GitLab account used by CodeRabbit under **Edit profile → SSH Keys**. GitLab will deny SSH access if the public key is not registered!

  See the [GitLab documentation on SSH keys](https://docs.gitlab.com/ee/user/ssh.html).

### Configure SSH clone credentials

<Steps>
  <Step title="Log in to CodeRabbit">
    Navigate to [app.coderabbit.ai](https://app.coderabbit.ai) and log in with your self-managed GitLab account.
  </Step>

  <Step title="Open account settings">
    In the left navigation menu, click **Account** at the bottom.
  </Step>

  <Step title="Navigate to SSH Clone Credentials">
    In the left navigation of the Account page, under **Developer settings**, click **SSH Clone Credentials**.
  </Step>

  <Step title="Enter your SSH credentials">
    Fill in the fields as required for your setup:

    | Field               | Required    | Description                                                                                                          |
    | ------------------- | ----------- | -------------------------------------------------------------------------------------------------------------------- |
    | **SSH Private Key** | Yes         | The private key used to authenticate with your GitLab instance. Must be generated **without a passphrase**.          |
    | **SSH Public Key**  | Recommended | The corresponding public key. Providing it allows CodeRabbit to verify the key pair.                                 |
    | **SSH Port**        | Optional    | Custom SSH port if your GitLab instance does not use the default port `22`.                                          |
    | **known\_hosts**    | Optional    | Contents of a `known_hosts` file for your GitLab host. Helps prevent man-in-the-middle warnings on first connection. |

    For most setups, providing the **SSH Private Key** and **SSH Public Key** is sufficient.

    <Info>
      To avoid common copy-paste problems, use `pbcopy` (macOS) or `xclip` (Linux) to copy each key file to your clipboard, then paste directly into the corresponding field.
    </Info>
  </Step>

  <Step title="Save your credentials">
    Click **Save** to apply the SSH clone credentials. CodeRabbit will attempt SSH cloning using these credentials for your self-managed GitLab repositories. If SSH credentials cannot be decrypted or are invalid, cloning falls back to HTTPS.

    <Info>
      After the initial setup, you can return to this page to update individual fields without re-entering all credentials.
    </Info>
  </Step>
</Steps>

## What's next

<CardGroup cols={1}>
  <Card title="Platform overview" href="/platforms/overview" icon="layers" horizontal>
    Overview of all Git platforms supported by CodeRabbit and how to get started.
  </Card>

  <Card title="Quickstart" href="/getting-started/quickstart" icon="rocket" horizontal>
    Open your first merge request and see CodeRabbit post a review in minutes.
  </Card>
</CardGroup>
