Integration service for self-hosted (on-premise) GitLab with external services (Slack, Notion, etc.)
Note: This project is designed for self-hosted GitLab servers (GitLab CE/EE installed on your own infrastructure), not for GitLab.com (SaaS). It bridges your internal GitLab instance with external collaboration tools.
- Slack → GitLab: Create issues with
/issuecommand - GitLab → Slack: Notifications for issue status changes
- Status Check: Check issue status with
/issue status #123
- Notion integration
Internal Network External Services
┌───────────────────────┐ ┌───────────────────┐
│ │ │ │
│ ┌─────────────────┐ │ Webhook/API │ ┌─────────────┐ │
│ │ GitLab Server │◄─┼───────────────────┼──│ Slack │ │
│ │ (self-hosted) │ │ │ │ │ │
│ └────────┬────────┘ │ │ └──────┬──────┘ │
│ │ │ │ │ │
│ │ Webhook │ │ Slash │ │
│ ▼ │ │ Command │ │
│ ┌─────────────────┐ │ Tunnel/Proxy │ │ │
│ │ Integration │◄─┼───────────────────┼─────────┘ │
│ │ Server │──┼───────────────────┼──────────────────►│
│ │ (FastAPI) │ │ (Cloudflare, │ │
│ └─────────────────┘ │ Tailscale, etc) │ │
│ │ │ │
└───────────────────────┘ └───────────────────┘
Key Points:
- GitLab server runs on internal network (not accessible from internet)
- Integration server bridges internal GitLab with external services
- External access via tunnel (Cloudflare Tunnel, Tailscale, etc.) or reverse proxy
- Supports self-signed SSL certificates commonly used in internal servers
- Python 3.10+
- uv (package manager)
# Clone repository
git clone <repository-url>
cd gitlab-integrations
# Setup environment (creates venv + installs packages + generates .env)
./scripts/setup.sh
# Edit .env file
vi .env- Go to Slack API page
- Click Create New App
- Select From scratch
- Enter App name (e.g.,
GitLab Issue Bot) - Select workspace and click Create App
- Click OAuth & Permissions in the left menu
- In Scopes section, add the following Bot Token Scopes:
| Scope | Purpose |
|---|---|
chat:write |
Send messages to channels |
chat:write.public |
Send messages to public channels bot isn't in |
commands |
Use Slash commands |
- Click Slash Commands in the left menu
- Click Create New Command
- Enter the following:
| Field | Value |
|---|---|
| Command | /issue |
| Request URL | https://<your-domain>/slack/commands |
| Short Description | Create and view GitLab issues |
| Usage Hint | [status #number] |
- Click Save
⚠️ Warning: Request URL must be the Integration Server's externally accessible URL. NOT the GitLab server URL!Example:
- ✅
https://your-app.company.com/slack/commands- ❌
https://gitlab.company.com/slack/commands
⚠️ Without this setting, you'll get "There was a problem connecting" error when submitting Modal.
- Click Interactivity & Shortcuts in the left menu
- Toggle Interactivity to On
- Enter Request URL:
https://<your-domain>/slack/interactions - Click Save Changes
⚠️ Warning: Same as Step 3, enter the Integration Server's external URL. Shortcuts and Select Menus settings are not required.
- Click OAuth & Permissions in the left menu
- Click Install to Workspace
- Confirm permissions and click Allow
- Copy the generated Bot User OAuth Token (starts with
xoxb-)
- Click Basic Information in the left menu
- Copy Signing Secret from App Credentials section
- Right-click the channel to receive notifications in Slack
- Click View channel details
- Copy Channel ID at the bottom (string starting with
C)
- Go to GitLab → Profile icon (top right) → Preferences
- Click Access Tokens in the left menu
- Click Add new token
- Enter the following:
| Field | Value |
|---|---|
| Token name | gitlab-integrations |
| Expiration date | Choose appropriate date |
| Scopes | api (full API access) |
- Click Create personal access token
- Copy the generated token (you won't see it again after leaving this page)
- Go to the GitLab project page you want to integrate
- Project ID is displayed below the project name
- Or check in Settings → General
- Go to GitLab project → Settings → Webhooks
- Click Add new webhook
- Enter the following:
| Field | Value |
|---|---|
| URL | https://<your-domain>/gitlab/webhook |
| Secret token | Same value as GITLAB_WEBHOOK_SECRET in .env |
| Trigger | ✅ Issues events |
| SSL verification | Choose based on environment |
- Click Add webhook
How to generate Secret token
# Method 1: Using openssl openssl rand -hex 32 # Method 2: Using Python python -c "import secrets; print(secrets.token_hex(32))"
Open .env file and enter the following values:
# GitLab settings
GITLAB_URL=https://gitlab.your-company.com # GitLab server URL
GITLAB_TOKEN=glpat-xxxxxxxxxxxxxxxxxxxx # Personal Access Token
GITLAB_PROJECT_ID=123 # Project ID
GITLAB_WEBHOOK_SECRET=your-secret-token # Webhook verification (same as GitLab Webhook setting)
# Slack settings
SLACK_BOT_TOKEN=xoxb-xxxx-xxxx-xxxx # Bot User OAuth Token
SLACK_SIGNING_SECRET=xxxxxxxxxxxxxxxxxxxxxxx # Signing Secret
SLACK_CHANNEL_ID=C0123456789 # Notification channel ID
# Server settings
HOST=0.0.0.0
PORT=8000# Default run (uses HOST, PORT from .env)
./scripts/run.sh
# Run on different port
./scripts/run.sh --port 9000
# Specify host and port
./scripts/run.sh --host 0.0.0.0 --port 9000source .venv/bin/activate
python -m gitlab_integrations.main --port 9000docker-compose up -d
# Check logs
docker-compose logs -fType /issue in Slack → Enter information in modal popup → Click Create
/issue
Modal Fields:
- Title: Issue title (required)
- Description: Detailed description (optional)
- Labels: Select from existing GitLab labels (optional, multi-select)
Note: Labels are dynamically loaded from your GitLab project. Only existing labels will appear in the dropdown.
/issue status 123
/issue status #123
Cause: Slack cannot send request to Integration Server
Check:
-
Verify Slash Commands Request URL
- Slack API Dashboard → Slash Commands → Select
/issue - Confirm Request URL is set to
https://<your-domain>/slack/commands ⚠️ Must be Integration Server URL, not GitLab URL
- Slack API Dashboard → Slash Commands → Select
-
Check server status
curl https://<your-domain>/health # Confirm {"status": "healthy"} response
-
Check server logs
- No requests: URL configuration issue
- 401 error: Signing Secret mismatch
- 502 error: Server not running
Cause: Interactivity not configured
Solution:
- Slack API Dashboard → Interactivity & Shortcuts
- Verify Interactivity toggle is On
- Verify Request URL is set to
https://<your-domain>/slack/interactions - Click Save Changes
Cause: Webhook URL incorrectly configured (pointing to GitLab server itself)
Check:
❌ https://gitlab.company.com/gitlab/webhook (GitLab URL)
✅ https://your-app.domain.com/gitlab/webhook (Integration Server URL)
✅ http://localhost:9000/gitlab/webhook (if on same server)
Cause: Integration Server is not running
Solution:
# Run server
source .venv/bin/activate
python -m gitlab_integrations.main --port 9000Cause: GitLab server uses self-signed certificate
Solution: Already handled with ssl_verify=False in code. Also uncheck Enable SSL verification in GitLab Webhook settings.
Symptom: SSL error when creating issue
SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self-signed certificate'))
Cause: GitLab server uses self-signed certificate
Solution: Verify ssl_verify=False in src/gitlab_integrations/gitlab/api.py
gl = gitlab.Gitlab(
settings.gitlab_url,
private_token=settings.gitlab_token,
ssl_verify=False, # Allow self-signed certificates
)- Verify
GITLAB_TOKENis valid - Verify token has
apiscope - Verify
GITLAB_URLis correct (no trailing/)
Solution:
sudo apt install python3.10-venvCause: Python version compatibility
Solution: Already configured as requires-python = ">=3.10" in pyproject.toml
Summary of easily confused URL settings:
| Setting Location | URL Type | Example |
|---|---|---|
GITLAB_URL in .env |
GitLab server URL | https://gitlab.company.com |
| GitLab Webhook URL | Integration Server URL | http://localhost:9000/gitlab/webhook |
| Slack Slash Commands | Integration Server URL (external) | https://your-app.domain.com/slack/commands |
| Slack Interactivity | Integration Server URL (external) | https://your-app.domain.com/slack/interactions |
Key Point:
- Only
GITLAB_URLin.envis the GitLab server URL - Everything else is the Integration Server URL
./scripts/test.sh
./scripts/test.sh --cov # with coverageruff check --fix .
ruff format .