> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gcore.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Create a Container Registry

export const MethodSection = ({children}) => children ?? null;

export const MethodSwitch = ({children}) => {
  const tabs = React.Children.toArray(children).map(c => {
    if (!c || !c.props) return null;
    if (c.props.id) return c;
    const inner = c.props.children;
    if (inner && inner.props && inner.props.id) return inner;
    return null;
  }).filter(Boolean);
  const firstId = tabs.length > 0 ? tabs[0].props.id : "";
  const [active, setActive] = React.useState(firstId);
  React.useEffect(() => {
    try {
      const saved = localStorage.getItem("gcore_docs_method");
      if (saved && tabs.find(t => t.props.id === saved)) {
        setActive(saved);
      }
    } catch (_) {}
  }, []);
  React.useEffect(() => {
    try {
      document.querySelectorAll("h2[id], h3[id]").forEach(heading => {
        const visible = heading.offsetParent !== null;
        document.querySelectorAll(`a[href="#${heading.id}"]`).forEach(link => {
          if (link.closest("h1,h2,h3,h4,h5,h6")) return;
          const li = link.closest("li");
          if (li) li.style.display = visible ? "" : "none";
        });
      });
    } catch (_) {}
    window.dispatchEvent(new Event("scroll"));
  }, [active]);
  const handleClick = id => {
    setActive(id);
    try {
      localStorage.setItem("gcore_docs_method", id);
    } catch (_) {}
  };
  return <div>
      <div className="not-prose flex gap-0 border-b border-zinc-200 dark:border-zinc-800 mb-8 mt-2" role="tablist">
        {tabs.map(tab => {
    const isActive = active === tab.props.id;
    return <button key={tab.props.id} role="tab" aria-selected={isActive} onClick={() => handleClick(tab.props.id)} className={["px-4 py-2 text-sm font-medium border-b-2 -mb-px transition-colors cursor-pointer", isActive ? "border-primary text-primary" : "border-transparent text-zinc-500 hover:text-zinc-800 dark:hover:text-zinc-200"].join(" ")}>
              {tab.props.label}
            </button>;
  })}
      </div>

      {tabs.map(tab => <div key={tab.props.id} style={{
    display: active === tab.props.id ? "" : "none"
  }}>
          {tab.props.children}
        </div>)}
    </div>;
};

<MethodSwitch>
  <MethodSection id="portal" label="Customer Portal">
    <p>Container Registry stores OCI-compatible artifacts — Docker images, Helm charts, and other container content — in a centralized location for use across Gcore products.</p>

    <p>Creating and managing Container Registry requires the [Project Administrator](/cloud/getting-started/projects/users/user-roles-and-rights#project-administrator) or [Client Administrator](/cloud/getting-started/projects/users/user-roles-and-rights#client-administrator) role.</p>

    ## Step 1. Add a registry to the Customer Portal

    <p>Create a registry to store OCI-compatible artifacts:</p>

    <Steps>
      <Step title="Navigate to Container Registry">
        In the [Gcore Customer Portal](https://portal.gcore.com), navigate to **Cloud** and click **Container Registry** in the left menu.
      </Step>

      <Step title="Start registry creation">
        Click **Create Container Registry**.

        <Frame>
          <img src="https://mintcdn.com/gcore/oxS_nLcLtEBfgfBM/images/docs/cloud/container-registry/create-container-registry/container-registry-page-create.png?fit=max&auto=format&n=oxS_nLcLtEBfgfBM&q=85&s=73be66e483cbdccd86abf91f800b2e71" alt="Container Registry list page with Create Container Registry button" width="1103" height="397" data-path="images/docs/cloud/container-registry/create-container-registry/container-registry-page-create.png" />
        </Frame>
      </Step>

      <Step title="Select a region">
        Container Registry is available in Luxembourg-2, Sines-3, Chicago, and Singapore. To use the registry with other Gcore services, select the same region where those services are created.
      </Step>

      <Step title="Enter a registry name">
        In the **Container Registry name** field, enter a name.

        <Tip>
          A registry name must consist of lowercase Latin characters and can include hyphens.
        </Tip>
      </Step>

      <Step title="Set the storage limit">
        In the **Storage limit** field, enter the maximum storage in GiB. This limit applies to all content in the registry — images, artifacts, and image versions.
      </Step>

      <Step title="Create the registry">
        Click **Create Registry**.

        <Frame>
          <img src="https://mintcdn.com/gcore/oxS_nLcLtEBfgfBM/images/docs/cloud/container-registry/create-container-registry/create-registry.png?fit=max&auto=format&n=oxS_nLcLtEBfgfBM&q=85&s=b31d9cdb90491dc33aa44291cc7331dc" alt="Create Container Registry page with region selection, name, and storage limit fields" width="1087" height="608" data-path="images/docs/cloud/container-registry/create-container-registry/create-registry.png" />
        </Frame>
      </Step>
    </Steps>

    <p>The registry appears on the **Container Registry** page.</p>

    ## Step 2. Create a user

    <p>Pushing and pulling images requires authentication with a registry user account.</p>

    <Steps>
      <Step title="Open the registry">
        Click the registry name to open it.
      </Step>

      <Step title="Add a user">
        On the **Users** tab, click **Add users**.

        <Frame>
          <img src="https://mintcdn.com/gcore/oxS_nLcLtEBfgfBM/images/docs/cloud/container-registry/create-container-registry/users-tab-empty.png?fit=max&auto=format&n=oxS_nLcLtEBfgfBM&q=85&s=4d63f554d1f30902ad384f00bb4d88d9" alt="Users tab with no users and Add users button" width="1333" height="660" data-path="images/docs/cloud/container-registry/create-container-registry/users-tab-empty.png" />
        </Frame>
      </Step>

      <Step title="Configure the user">
        * **Username**: enter a username of up to 16 characters using lowercase letters and numbers only.
        * **Permissions**: select **Pull images** for pull-only access, or **Push and pull images** for full access.
        * **Set activity duration**: enable this toggle to set an expiration date for the credentials. When disabled, credentials do not expire.

        <Frame>
          <img src="https://mintcdn.com/gcore/oxS_nLcLtEBfgfBM/images/docs/cloud/container-registry/create-container-registry/add-user.png?fit=max&auto=format&n=oxS_nLcLtEBfgfBM&q=85&s=71174c42116e21de5dc3cb53d15cb13e" alt="Add users dialog with Username, Permissions, and Set activity duration fields" width="1060" height="428" data-path="images/docs/cloud/container-registry/create-container-registry/add-user.png" />
        </Frame>
      </Step>

      <Step title="Save the user">
        Click **Save**.
      </Step>

      <Step title="Save the password">
        Copy and save the password from the **Password** dialog — it cannot be retrieved after closing. To regain access, regenerate the password.

        <Frame>
          <img src="https://mintcdn.com/gcore/oxS_nLcLtEBfgfBM/images/docs/cloud/container-registry/create-container-registry/save-password.png?fit=max&auto=format&n=oxS_nLcLtEBfgfBM&q=85&s=46250963695f1ffc6d34eb8baf9447ce" alt="Password dialog showing the full username and generated password" width="1021" height="412" data-path="images/docs/cloud/container-registry/create-container-registry/save-password.png" />
        </Frame>
      </Step>
    </Steps>

    <p>Log in as the created user to push and pull images from the Container Registry.</p>

    ## Step 3. Push an image to the container registry

    <p>Click **Push commands** or **Pull commands** in the top right of the registry page to view sample commands for that registry.</p>

    <Frame>
      <img src="https://mintcdn.com/gcore/oxS_nLcLtEBfgfBM/images/docs/cloud/container-registry/create-container-registry/push-pull-commands.png?fit=max&auto=format&n=oxS_nLcLtEBfgfBM&q=85&s=940a323b04d7cddc9aba5d0757659a9b" alt="Registry page with Pull commands and Push commands buttons in the top right" width="1102" height="649" data-path="images/docs/cloud/container-registry/create-container-registry/push-pull-commands.png" />
    </Frame>

    <p>To push a Docker image to the registry:</p>

    <Steps>
      <Step title="Log in to the registry">
        Run `docker login registry.luxembourg-2.cloud.gcore.dev`. At the prompts, enter the full username shown in the **Password** dialog and the user password. The "Login succeeded" message confirms authentication.
      </Step>

      <Step title="Tag the image (optional)">
        `docker tag source_image:tag target_repository:target_tag`
      </Step>

      <Step title="Push the image">
        `docker push <registry-endpoint/image-name>`
      </Step>
    </Steps>

    <p>The image appears on the **Images** tab of the registry.</p>

    <Frame>
      <img src="https://mintcdn.com/gcore/oxS_nLcLtEBfgfBM/images/docs/cloud/container-registry/create-container-registry/images-tab.png?fit=max&auto=format&n=oxS_nLcLtEBfgfBM&q=85&s=4f10381e2a8e734bedc1b7e76983b5d3" alt="Registry Images tab showing pushed images" width="1083" height="671" data-path="images/docs/cloud/container-registry/create-container-registry/images-tab.png" />
    </Frame>

    ## Step 4 (Optional). Pull the image from the container registry

    <p>To pull an image from the registry:</p>

    ```sh theme={null}
    docker pull <registry-endpoint/image-name>
    ```
  </MethodSection>

  <MethodSection id="api" label="REST API">
    Use the Gcore API to create a container registry, add users with configurable access and credential expiration, and obtain the credentials needed to authenticate with Docker.

    <Info>
      An [API token](/account-settings/api-tokens) is required, along with a [project ID](/api-reference/cloud/projects/list-projects) and a [region ID](/api-reference/cloud/regions/list-regions).
    </Info>

    Set the following environment variables before running the examples:

    ```bash theme={null}
    export GCORE_API_KEY="{YOUR_API_KEY}"
    export GCORE_CLOUD_PROJECT_ID="{YOUR_PROJECT_ID}"
    export GCORE_CLOUD_REGION_ID="{YOUR_REGION_ID}"
    export REGISTRY_NAME="{YOUR_REGISTRY_NAME}"
    ```

    ## Quickstart

    The scripts below create a registry, add a user with push and pull permissions, and print the `docker login` command with the generated credentials.

    <Tabs>
      <Tab title="Python SDK">
        ```python theme={null}
        import os
        from gcore import Gcore

        client = Gcore()

        # Step 1. Create a registry.
        registry = client.cloud.registries.create(
            name=os.environ["REGISTRY_NAME"],
            storage_limit=10,
        )
        print(f"Registry ID:  {registry.id}")
        print(f"Registry URL: {registry.url}")

        # Step 2. Create a user with push and pull permissions.
        user = client.cloud.registries.users.create(
            registry_id=registry.id,
            name="myuser",
            duration=-1,  # -1 = indefinite access
        )
        print(f"Docker username: {user.name}")
        print(f"Docker password: {user.secret}")  # shown once — save it now

        # Step 3. Print the docker login command.
        domain = registry.url.split("/")[0]
        print(f"\ndocker login {domain}")
        print(f"  Username: {user.name}")
        print(f"  Password: {user.secret}")
        ```
      </Tab>

      <Tab title="Go SDK">
        ```go theme={null}
        package main

        import (
        	"context"
        	"fmt"
        	"log"
        	"os"
        	"strings"

        	"github.com/G-Core/gcore-go"
        	"github.com/G-Core/gcore-go/cloud"
        )

        func main() {
        	client := gcore.NewClient()
        	ctx := context.Background()

        	// Step 1. Create a registry.
        	registry, err := client.Cloud.Registries.New(ctx, cloud.RegistryNewParams{
        		Name:         os.Getenv("REGISTRY_NAME"),
        		StorageLimit: gcore.Int(10),
        	})
        	if err != nil {
        		log.Fatal(err)
        	}
        	fmt.Printf("Registry ID:  %d\n", registry.ID)
        	fmt.Printf("Registry URL: %s\n", registry.URL)

        	// Step 2. Create a user with push and pull permissions.
        	user, err := client.Cloud.Registries.Users.New(ctx, registry.ID, cloud.RegistryUserNewParams{
        		Name:     "myuser",
        		Duration: -1, // -1 = indefinite access
        	})
        	if err != nil {
        		log.Fatal(err)
        	}
        	fmt.Printf("Docker username: %s\n", user.Name)
        	fmt.Printf("Docker password: %s\n", user.Secret) // shown once — save it now

        	// Step 3. Print the docker login command.
        	domain := strings.SplitN(registry.URL, "/", 2)[0]
        	fmt.Printf("\ndocker login %s\n", domain)
        	fmt.Printf("  Username: %s\n", user.Name)
        	fmt.Printf("  Password: %s\n", user.Secret)
        }
        ```
      </Tab>
    </Tabs>

    After running the script, use the printed credentials to log in to Docker. The registry URL printed by the script is the prefix for `docker push` — append the image name and tag to it.

    ## Step-by-step

    <p>Each step below explains what the call does, which parameters matter, and what the response looks like.</p>

    <Accordion title="Show all steps">
      ### Step 1. Create a registry

      This call creates a new registry and returns its ID and endpoint URL.

      | Parameter       | Description                                                               |
      | --------------- | ------------------------------------------------------------------------- |
      | `name`          | Registry name: lowercase letters, numbers, and hyphens; max 24 characters |
      | `storage_limit` | Maximum storage in GiB                                                    |

      <Tabs>
        <Tab title="Python SDK">
          ```python theme={null}
          import os
          from gcore import Gcore

          client = Gcore()

          registry = client.cloud.registries.create(
              name=os.environ["REGISTRY_NAME"],
              storage_limit=10,
          )
          print(f"ID:  {registry.id}")
          print(f"URL: {registry.url}")
          ```
        </Tab>

        <Tab title="Go SDK">
          ```go theme={null}
          registry, err := client.Cloud.Registries.New(ctx, cloud.RegistryNewParams{
              Name:         os.Getenv("REGISTRY_NAME"),
              StorageLimit: gcore.Int(10),
          })
          if err != nil {
              log.Fatal(err)
          }
          fmt.Printf("ID:  %d\n", registry.ID)
          fmt.Printf("URL: %s\n", registry.URL)
          ```
        </Tab>

        <Tab title="curl">
          ```bash theme={null}
          curl -s -X POST \
            "https://api.gcore.com/cloud/v1/registries/$GCORE_CLOUD_PROJECT_ID/$GCORE_CLOUD_REGION_ID" \
            -H "Authorization: APIKey $GCORE_API_KEY" \
            -H "Content-Type: application/json" \
            -d "{\"name\": \"$REGISTRY_NAME\", \"storage_limit\": 10}"
          ```

          Response:

          ```json theme={null}
          {
            "id": 607,
            "name": "my-registry",
            "storage_limit": 10,
            "storage_used": 0,
            "url": "registry.luxembourg-2.cloud.gcore.dev/1000503-1186668-76-my-registry/",
            "repo_count": 0,
            "created_at": "2026-05-30T21:35:34Z",
            "updated_at": "2026-05-30T21:35:34Z"
          }
          ```
        </Tab>
      </Tabs>

      The registry is ready immediately — no task polling needed. Save the `id` (needed for user creation) and the `url` (needed for docker login and push).

      ### Step 2. Create a registry user

      This call creates a user whose credentials are used for `docker login`. The `secret` (password) is returned only in this response — it cannot be retrieved later.

      | Parameter   | Description                                                      |
      | ----------- | ---------------------------------------------------------------- |
      | `name`      | Username: lowercase letters and numbers only, max 16 characters  |
      | `duration`  | Credential lifetime in days; `-1` for indefinite access          |
      | `read_only` | Optional; set to `true` to restrict the user to pull-only access |

      <Tabs>
        <Tab title="Python SDK">
          ```python theme={null}
          user = client.cloud.registries.users.create(
              registry_id=registry.id,
              name="myuser",
              duration=-1,
          )
          print(f"Docker username: {user.name}")
          print(f"Docker password: {user.secret}")  # shown once — save it
          ```
        </Tab>

        <Tab title="Go SDK">
          ```go theme={null}
          user, err := client.Cloud.Registries.Users.New(ctx, registry.ID, cloud.RegistryUserNewParams{
              Name:     "myuser",
              Duration: -1,
          })
          if err != nil {
              log.Fatal(err)
          }
          fmt.Println("Docker username:", user.Name)
          fmt.Println("Docker password:", user.Secret) // shown once — save it
          ```
        </Tab>

        <Tab title="curl">
          ```bash theme={null}
          REGISTRY_ID=607   # from Step 1

          curl -s -X POST \
            "https://api.gcore.com/cloud/v1/registries/$GCORE_CLOUD_PROJECT_ID/$GCORE_CLOUD_REGION_ID/$REGISTRY_ID/users" \
            -H "Authorization: APIKey $GCORE_API_KEY" \
            -H "Content-Type: application/json" \
            -d '{"name": "myuser", "duration": -1}'
          ```

          Response:

          ```json theme={null}
          {
            "id": 730,
            "name": "r_1000503-1186668-76-my-registry+myuser",
            "secret": "CahTrlsfIQe36OZqGMzJlDG42hVOhzPI",
            "duration": -1,
            "expires_at": "1969-12-31T23:59:59Z",
            "read_only": false,
            "created_at": "2026-05-30T21:39:41Z"
          }
          ```
        </Tab>
      </Tabs>

      The `name` field in the response is the full Docker login username — it includes the client ID, project ID, region ID, registry name, and the username you specified. Use this full string as the Docker username. The `expires_at` value `1969-12-31T23:59:59Z` indicates indefinite access.

      ### Step 3. Log in and push an image

      Use the credentials from Step 2 to authenticate with Docker, then push an image.

      ```bash theme={null}
      # Extract the domain from the registry URL (the part before the first slash).
      DOMAIN="registry.luxembourg-2.cloud.gcore.dev"   # region-specific
      REGISTRY_URL="registry.luxembourg-2.cloud.gcore.dev/1000503-1186668-76-my-registry/"

      docker login "$DOMAIN"
      # Username: r_1000503-1186668-76-my-registry+myuser
      # Password: (secret from Step 2)

      # Tag and push a local image.
      docker tag nginx:latest "${REGISTRY_URL}nginx:latest"
      docker push "${REGISTRY_URL}nginx:latest"
      ```

      The pushed image appears on the **Images** tab in the Customer Portal.

      ### Step 4. Pull an image

      To pull an image, authenticate with the same credentials and use the full registry path.

      ```bash theme={null}
      docker pull "${REGISTRY_URL}nginx:latest"
      ```
    </Accordion>

    ## Clean up

    Deleting the registry permanently removes all images and repositories stored in it.

    <Tabs>
      <Tab title="Python SDK">
        ```python theme={null}
        import os
        from gcore import Gcore

        client = Gcore()

        client.cloud.registries.delete(registry_id=int(os.environ["REGISTRY_ID"]))
        print("Registry deleted.")
        ```
      </Tab>

      <Tab title="Go SDK">
        ```go theme={null}
        registryID, _ := strconv.ParseInt(os.Getenv("REGISTRY_ID"), 10, 64)

        err := client.Cloud.Registries.Delete(ctx, registryID, cloud.RegistryDeleteParams{})
        if err != nil {
            log.Fatal(err)
        }
        fmt.Println("Registry deleted.")
        ```
      </Tab>

      <Tab title="curl">
        ```bash theme={null}
        REGISTRY_ID=607

        curl -s -X DELETE \
          "https://api.gcore.com/cloud/v1/registries/$GCORE_CLOUD_PROJECT_ID/$GCORE_CLOUD_REGION_ID/$REGISTRY_ID" \
          -H "Authorization: APIKey $GCORE_API_KEY"
        ```
      </Tab>
    </Tabs>
  </MethodSection>
</MethodSwitch>
