Repository Mirroring
Vetrix supports two mirroring modes:
- Pull mirror — Vetrix periodically fetches from a remote source. The local repo stays in sync with an upstream (e.g., a GitHub repo).
- Push mirror — After every push to Vetrix, changes are forwarded to a remote destination.
Pull mirrors
Creating a pull mirror
curl -X POST https://<vetrix-host>/api/v1/repos/<owner>/<repo>/mirrors \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"direction": "pull",
"remote_url": "https://github.com/upstream/repo.git",
"interval_minutes": 60,
"credentials": {
"username": "git",
"password": "<github-pat>"
}
}'
Vetrix will fetch all branches and tags from the remote on the configured interval.
Force-syncing now
curl -X POST https://<vetrix-host>/api/v1/repos/<owner>/<repo>/mirrors/<mirror-id>/sync \
-H "Authorization: Bearer <token>"
Conflict behaviour
Pull mirrors use --force when updating refs. Local changes to mirrored branches will be overwritten on the next sync. If you need to modify mirrored content, disable the mirror first.
Push mirrors
Creating a push mirror
curl -X POST https://<vetrix-host>/api/v1/repos/<owner>/<repo>/mirrors \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"direction": "push",
"remote_url": "https://gitlab.com/org/repo.git",
"credentials": {
"username": "oauth2",
"password": "<gitlab-pat>"
}
}'
Push mirrors trigger immediately after each push event. They are best-effort: if the remote is unreachable, Vetrix retries up to 3 times with exponential back-off, then marks the mirror as error.
SSH credentials
For SSH remotes, use ssh:// URLs and provide an SSH private key instead of a username/password:
curl -X POST https://<vetrix-host>/api/v1/repos/<owner>/<repo>/mirrors \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"direction": "pull",
"remote_url": "ssh://git@github.com/upstream/repo.git",
"interval_minutes": 30,
"credentials": {
"ssh_private_key": "-----BEGIN OPENSSH PRIVATE KEY-----\n..."
}
}'
Private keys are encrypted at rest using the instance encryption key (MIRROR_ENC_KEY environment variable). The raw key is never stored.
Listing mirrors
curl https://<vetrix-host>/api/v1/repos/<owner>/<repo>/mirrors \
-H "Authorization: Bearer <token>"
Response:
[
{
"id": "01HZ...",
"direction": "pull",
"remote_url": "https://github.com/upstream/repo.git",
"interval_minutes": 60,
"status": "ok",
"last_sync_at": "2026-04-11T12:00:00Z",
"last_error": null
}
]
Mirror status values
| Status | Meaning |
|---|---|
pending |
Waiting for first sync |
syncing |
Sync in progress |
ok |
Last sync completed successfully |
error |
Last sync failed; last_error contains the message |
Deleting a mirror
curl -X DELETE https://<vetrix-host>/api/v1/repos/<owner>/<repo>/mirrors/<mirror-id> \
-H "Authorization: Bearer <token>"
Deleting a mirror stops future syncs but does not alter the repository content.
API reference
| Method | Path | Description |
|---|---|---|
| GET | /api/v1/repos/:owner/:repo/mirrors |
List mirrors |
| POST | /api/v1/repos/:owner/:repo/mirrors |
Create mirror |
| GET | /api/v1/repos/:owner/:repo/mirrors/:id |
Get mirror |
| PATCH | /api/v1/repos/:owner/:repo/mirrors/:id |
Update mirror |
| DELETE | /api/v1/repos/:owner/:repo/mirrors/:id |
Delete mirror |
| POST | /api/v1/repos/:owner/:repo/mirrors/:id/sync |
Force sync now |
Permissions
Creating and managing mirrors requires maintain role or higher on the repository, or admin privileges.
Admin configuration
Admins can set the global mirror sync scheduler interval and disable mirroring entirely. See ../admin-docs/admin/mirrors.md for instance-level mirror settings.