On this page

Private Container Registries

When you deploy a service from a pre-built Docker image, Guara Cloud can pull from any private container registry — Docker Hub private repos, GitHub Container Registry, Google Container Registry, Quay.io, GitLab, self-hosted Harbor, and any V2-compatible registry.

You attach the credentials directly to the service. There is no global “registry credentials” tab and no need to bake tokens into your image or pass them through environment variables.

Where to find it

There are two entry points, depending on whether you’re creating a new service or editing an existing one:

  • Service create wizard. When you choose Docker Image as the build method and provide a private image reference, a collapsed Private Registry Credentials section appears below the image reference field.
  • Service Settings tab. Open the service, go to Settings, and find the Private Registry section. If credentials are already set, the section is expanded with the current values; otherwise it shows a single ”+ Add private registry credentials” button.

Both surfaces share the same form and validation flow.

Adding credentials

  1. Registry URL. The registry hostname or full URL (e.g., gcr.io, ghcr.io, quay.io, docker.io, or your self-hosted host).

  2. Username. The username for basic auth, or the token username for token-based auth (commonly oauth2accesstoken for GCR, _json_key_base64 for GCR JSON keys, etc.).

  3. Password. The password or token. The plaintext value never leaves the request — see the security section below.

  4. Test Connection. Click the button. The platform performs a real preflight against your registry.

  5. Save. Once the test passes, the Save button is enabled.

Test Connection

The Test Connection button runs a real preflight against the registry — it doesn’t just check that the URL parses. The flow:

  1. Probe the registry’s V2 API endpoint (GET /v2/) to confirm it speaks the OCI protocol.
  2. Exchange auth tokens if the registry challenges with WWW-Authenticate: Bearer realm=....
  3. Send a HEAD request for the manifest of the image reference you provided to confirm it actually exists in this registry under these credentials.

The whole preflight has an 8-second wall-clock timeout. Failures map to friendly codes:

CodeMeaning
invalid_urlThe URL is malformed or the host is unreachable.
auth_failedThe username or password were rejected by the registry.
manifest_not_foundThe image reference does not exist in this registry.
timeoutThe registry took longer than 8 seconds to respond.
ssrf_blockedThe registry hostname resolves to a blocked address (loopback, RFC 1918, etc.).
network_errorSome other network failure (DNS, TLS, etc.).

Test Connection is rate-limited to 5 attempts per minute per user. If you hit the limit, the dashboard shows a soft message and you can try again shortly.

Save without verifying

If the test fails but you’re confident the credentials are correct (for example, the registry is briefly down for maintenance), check Save without verifying to skip the preflight requirement and persist the credentials anyway.

Updating and removing

  • Edit. Click the field group to reveal the form. Username and password are masked; you can replace them or leave them as-is. Re-test before saving.
  • Remove. Click Remove credentials. The service falls back to anonymous pulls. If your image is private, the next deploy will fail until credentials are added back.

Security

  • Passwords are encrypted at rest with AES-256-GCM, using a per-project key derived via HKDF from the platform’s master key. Each project has its own derived key — no shared secret across projects.
  • The plaintext password is held only in memory during the request that creates or updates credentials, the preflight HTTP call, and the encrypt-and-persist transaction. It is never logged, cached, or written to disk.
  • The registry preflight is bound by SSRF protection — the same blocklist that protects HTTP cron worker destinations. Loopback, RFC 1918, link-local, carrier-grade NAT, IPv4-mapped IPv6, and the unspecified address are all blocked.
  • Every save is recorded in your Audit Logs under service.create or service.update, with metadata indicating whether the preflight passed or was overridden.

Supported registries

Anything that speaks the OCI Distribution Spec V2 works. Common examples:

RegistryURL exampleUsername notes
Docker Hub (private repo)docker.ioYour Docker Hub username
GitHub Container Registryghcr.ioYour GitHub username; password = personal access token
GitLab Container Registryregistry.gitlab.comYour GitLab username; password = personal access token
Google Container Registrygcr.iooauth2accesstoken or _json_key_base64
Quay.ioquay.ioYour Quay username
Self-hosted Harborharbor.example.comThe robot account or user