How it works
At a high level, the integration is a webhook plus a short-lived, read-only clone credential:You authorize LocalOps on GitLab
You grant LocalOps access as a specific GitLab user. LocalOps stores an OAuth token and can then see exactly the
projects that user is a member of.
You create a service from a project and branch
Your projects and branches show up as options when you create a LocalOps service. You pick which branch each
environment tracks.
LocalOps registers a webhook on the project
One webhook per project, listening for push and merge request events. LocalOps creates, reconciles, and
removes it for you.
A push or merge request arrives
LocalOps verifies the webhook signature, checks that the pusher is a member of your LocalOps organization, and
matches the branch against your services.
LocalOps clones and deploys
It mints a read-only deploy token that lives only for that build, clones your code, builds it, and deploys to the
target environment — then revokes the token.
GitLab gets the result back
Deployment status is posted onto the commit, and merge requests get a comment linking to their preview environment.
LocalOps Cloud (SaaS) with gitlab.com
Before you start
You need:- A LocalOps account, signed in as a member of your organization.
- A gitlab.com user account that is a member of the projects you want to deploy.
- That user must have at least the Maintainer role on each project you intend to deploy. See What role does my GitLab user need? below.
Steps to connect
1
Sign in to LocalOps
2
Navigate to the `Code repos` section
3
Click on `Connect GitLab`
4
Authorize the LocalOps application
You’ll be redirected to gitlab.com and asked to authorize the LocalOps application with the
api scope. Review
and click Authorize.5
Confirm the connection
You’ll land back on the Code repos page with your GitLab account listed as an active connection.
Notes
- The connection is tied to the GitLab user who authorized it, not to a group. LocalOps sees exactly the projects that user is a member of — nothing more.
- The connection is shared across your whole LocalOps organization. Any member of your org can create services from the connected projects.
- You can connect more than one GitLab account to the same LocalOps organization. Each is listed separately.
- If you re-authorize with a GitLab account that’s already connected, LocalOps refreshes the existing connection instead of creating a duplicate.
Using gitlab.com is not a requirement of LocalOps Cloud. If you’re on LocalOps Cloud but your code is on a
self-managed GitLab that is reachable from the public internet, you can still connect it — you’ll register an OAuth
application on your GitLab as described below, using the LocalOps Cloud redirect URI. Contact support for the exact
redirect URI for your region.
LocalOps Private Instance with self-managed GitLab
If you run LocalOps as a private instance (for example, inside your own VPC), you connect it to your own GitLab by registering an OAuth application on your GitLab and handing LocalOps three values: the GitLab URL, the Application ID, and the Secret.Step 1 — Register an OAuth application on your GitLab
Choose the scope that matches how widely you want the integration available:
Fill in:
Replace
<your-localops-host> with the origin your users reach LocalOps at (the same value as your instance’s
APP_ORIGIN). The path must be exactly /api/v1/callbacks/gitlab/oauth.
Click Save application, then copy the Application ID and Secret. GitLab shows the Secret only once.
Why the
api scope? LocalOps needs to write to your projects — register a webhook, mint a short-lived
read-only deploy token for each clone, post merge request comments, and set commit statuses. GitLab’s read_api and
read_repository scopes cannot do any of those. api is the narrowest OAuth scope GitLab offers that covers them.
The effective blast radius is bounded by the role of the user who authorizes, not by the scope — so connect using
a purpose-made service account rather than an instance administrator.Step 2 — Hand the credentials to your LocalOps administrator
Give the GitLab URL, Application ID, and Secret from Step 1 to whoever administers your LocalOps instance. They set these three values on the instance:Step 3 — Connect from LocalOps
Once your administrator has configured the instance, connecting is a single click — the GitLab URL and application credentials are already known, so there’s nothing to type in.1
Sign in to LocalOps
2
Navigate to the `Code repos` section
3
Click on `Connect GitLab`
4
Authorize the LocalOps application
You’ll be redirected to your GitLab to authorize, then returned to LocalOps with your account listed as an active
connection.
Network and TLS requirements
Connectivity has to work in three directions. Getting one of these wrong is the most common cause of a failed setup.
TLS: LocalOps registers webhooks with SSL verification enabled, and validates your GitLab’s certificate on outbound
API calls. Both endpoints must present a certificate signed by a CA the other side trusts. Self-signed certificates that
aren’t in the trust store will cause silent webhook delivery failures and API errors.
Clock sync: Webhook signatures are rejected if the delivery timestamp is more than 5 minutes off from LocalOps’
clock. Keep both hosts on NTP.
GitLab version: Any actively supported GitLab release works. GitLab 19.0 and later signs webhook deliveries with
an HMAC signature, which LocalOps prefers and verifies automatically. Older versions fall back to a shared-secret token
check — also supported, but weaker. No configuration change is needed either way; LocalOps detects and uses the stronger
method as soon as your instance supports it.
What role does my GitLab user need?
This applies to both setups. The GitLab user who authorizes the connection is the identity LocalOps acts as, so that user’s role determines what LocalOps can do. Minimum:Maintainer on every project you want to deploy. Owner also works.
Here’s why, operation by operation:
Only projects where the user is a Maintainer or Owner can be fully deployed. A project where the user is only a
Developer will show up in the list, but webhook registration and clone-credential creation will fail.
Recommended: use a dedicated service account
Rather than connecting a person’s account, create a GitLab service account (GitLab Premium/Ultimate) or a dedicated bot user, and add it as a Maintainer to only the projects LocalOps should deploy. This gives you:- Least privilege — LocalOps can’t see projects you didn’t grant.
- No breakage when a team member leaves or rotates their credentials.
- Clean attribution — LocalOps-created webhooks, tokens, and MR comments are clearly identifiable.
One more step: enable auto-deploy for your team
Auto-deploy on push only triggers if the person who pushed is a member of your LocalOps organization, identified through their GitLab account. LocalOps matches the pusher by their GitLab user ID against LocalOps members who have linked GitLab as a sign-in method. If there’s no match, the push is received and logged, but no deployment starts. So, for each team member whose pushes should trigger deploys:- They must be a member of your LocalOps organization.
- They must sign in to LocalOps with GitLab, or link GitLab to their existing LocalOps account under account settings.
What LocalOps creates in your GitLab projects
Everything below is created automatically and cleaned up automatically. You don’t need to configure any of it. A webhook, on each project that has at least one LocalOps service:- URL:
https://<your-localops-host>/api/v1/webhooks/gitlab/<connection-id> - Events: Push and Merge request
- SSL verification: enabled
- Signed with a per-connection secret that LocalOps verifies on every delivery
- Name:
localops-deploy-<deployment-id> - Scope:
read_repositoryonly — read-only, and cannot write, delete, or read anything but that project’s code - Expires: 48 hours after creation
- Revoked as soon as the deployment reaches a final state
Disconnecting
Go to Code repos, open the connection, and click Disconnect. The stored tokens and credentials are deleted from LocalOps immediately, and the action is recorded in your audit log. Two things to be aware of:- Revoke authorization on GitLab too. Disconnecting in LocalOps deletes LocalOps’ copy of the tokens but does not revoke the grant on GitLab’s side. To fully revoke, go to your GitLab User Settings → Applications → Authorized applications and remove LocalOps.
- Webhooks are not removed by disconnecting. LocalOps needs the connection’s credentials to delete a webhook, and
disconnecting removes them first. Any remaining LocalOps webhooks on your projects will simply fail to deliver. To
clean them up, either delete the LocalOps services using those projects before disconnecting, or remove the hooks
manually under Project → Settings → Webhooks (they’ll have a URL containing
/api/v1/webhooks/gitlab/). Any outstanding deploy tokens expire on their own within 48 hours.
Troubleshooting
“Failed to exchange OAuth code with GitLab” The redirect URI on your GitLab OAuth application doesn’t match, or the Application ID / Secret is wrong. Confirm the redirect URI is exactlyhttps://<your-localops-host>/api/v1/callbacks/gitlab/oauth — scheme, host, and path all have
to match character for character.
“Invalid or expired state. Please try connecting GitLab again.”
The authorization took too long, or you opened the authorize link in a different browser session. Start over from
Connect GitLab.
A project is missing from the list
LocalOps only sees projects where the connected GitLab user is a member. Group-level visibility isn’t enough — add
the user (or your service account) as a member of the project, at Maintainer level.
Service creation fails on webhook registration
The connected user isn’t a Maintainer or Owner on that project. Raise the role and retry.
“GitLab connection token expired. Please reconnect GitLab.”
LocalOps refreshes access tokens automatically, but the refresh token itself was revoked or expired — usually because
someone removed the authorization on GitLab, or the OAuth application’s secret was rotated. Reconnect the account.
Pushes don’t trigger a deployment
Check, in order:
- Auto-deploy is enabled on the service.
- The push was to the branch the service is configured to track.
- The person who pushed has linked their GitLab account to LocalOps and is a member of your LocalOps organization (see above).
- The webhook is delivering — Project → Settings → Webhooks → Edit → Recent events. A
401means a signature mismatch (check clock sync); a timeout or TLS error means GitLab can’t reach LocalOps.