# Pull from a private registry

A private container image deploys exactly like a public one — Koo just needs credentials to pull it from your registry. Private images are available on every plan.

## Add credentials when you create the service

1. 
2. 
3. 
4.

The two fields go together: enter both or neither. Docker Hub needs your real account username alongside the token; most other registries (GHCR, GitLab) accept any non-empty username.

## Manage credentials on an existing service

Open the service's drawer and go to **Settings** — the **Registry credentials** field under Source shows whether credentials are stored, never the values themselves.

- 
-

Like other service edits, both apply on the next Deploy.

## The API shape

Credentials ride the write-only `imageCredentials` field beside the image source — see the [Services API](/api/services):

```json
{
  "source": { "type": "image", "image": { "ref": "ghcr.io/acme/web:1.4.2" } },
  "imageCredentials": { "username": "acme", "token": "<registry access token>" }
}
```

They are write-only end to end: no read ever returns them — a service read exposes only the boolean `imagePullCredentialsSet`. On a PATCH, omitting the field leaves the stored credentials unchanged, sending a new object rotates them, and sending `null` clears them.

Supplying the same credentials on several services stores them once — one stored secret, not a copy per service.

## The registry host is pinned

When credentials are written, they are pinned to the image's registry host. Pointing the service at an image on a **different** registry host is refused until you re-supply credentials (or remove the stored ones) — a safety guard, so your stored credentials can never be presented to a registry they weren't created for.

## Troubleshooting

A failed pull shows an `image_pull_failed` error on the service's [status](/docs/observability/status), carrying the registry's own reason. The usual causes: an expired or revoked token, the wrong username form for the registry (Docker Hub wants the account name), or a tag that doesn't exist.
