Skip to content

GitLab Container Registry

GitLab's registry is built into every GitLab instance, but unlike most registries the registry hostname and port may differ from the GitLab web UI host (registry.gitlab.com for SaaS; commonly gitlab.example.com:5050 for self-managed). The registry trusts JWTs signed by the matching GitLab instance, so the auth token type matters as much as its scope.

Auth options

Token typeWhen to useScope
Personal access token (PAT)Per-user, broad scoperead_registry (and read_repository if you want HG metadata)
Project access tokenBound to one project; rotated easilyread_registry
Group access token (Premium+)One token, many projectsread_registry
Deploy tokenStable, no user attached, project-scopedCheck read_registry when creating
CI job token ($CI_JOB_TOKEN)Inside a pipeline only — not for HarborGuard's stored connectionn/a

The username depends on the token type — see "Common pitfalls" below.

Add the registry

  1. Registries → Connect Registry.
  2. Registry URL:
    • SaaS: registry.gitlab.com
    • Self-managed: typically gitlab.example.com:5050 (check your instance's Admin Area → Settings → Packages and Registries)
  3. The wizard tags GitLab Detected when the URL contains gitlab.com or :5050.
  4. Cloud: enter the username + token.
  5. Save.

For self-managed instances using a self-signed certificate, deploy a sensor inside the network rather than connecting cloud-side.

Required permissions

TokenUsername fieldNotes
PATYour GitLab usernameToken scope: read_registry
Project / group access tokenThe token's bot username (shown when created)Token scope: read_registry
Deploy tokenThe deploy token's username (set at creation, not your GitLab login)Permission: read_registry

Push-event sync

GitLab supports project-level webhooks for container registry events (Premium and above; Free in newer versions of self-managed).

  1. Project → Settings → Webhooks.
  2. URL: https://<your-harborguard-host>/api/webhooks/gitlab.
  3. Trigger: Container Registry events.
  4. Set the registry's schedule to on_push.

For a group with many projects, configure the webhook at the group level if your tier supports it.

Common pitfalls

  • Wrong host. The registry hostname is rarely the same as the GitLab web URL on self-managed instances. It's printed when you docker login; check there if unsure.
  • Port :5050. Self-managed installs almost always expose the registry on :5050. Forgetting the port produces a misleading "connection refused" — the GitLab web UI on :443 won't speak /v2/.
  • Deploy token username ≠ GitLab login. Deploy tokens have their own username, set at creation time. Using your personal login with the token's password produces 401s.
  • Self-signed TLS. Cloud-mode connections to a self-managed instance with a private CA will fail. Either install a sensor or expose the registry behind a publicly trusted cert.
  • Per-project visibility. A PAT only sees registries for projects the user can read. Switching from a personal PAT to a group access token after onboarding fixes most "I created a project, but it never appeared" issues.

Troubleshooting

SymptomLikely cause
401 immediately on testWrong username (deploy token vs PAT mix-up)
404 on /v2/URL points at the GitLab UI, not the registry; missing :5050
TLS error in cloud modeSelf-signed cert on a self-managed instance
Push webhook fires but no scanSchedule still daily; switch to on_push
"Insufficient scope" on tokenToken has read_repository but not read_registry

On this page