> ## Documentation Index
> Fetch the complete documentation index at: https://gcore.com/docs/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">
    Container Registry provides a centralized location for all OCI-compatible artifacts, such as container images and Helm charts, making it easy to view and manage them in one place.

    Use the following steps to add a new registry. For instructions on how to manage an existing registry, check out our [dedicated guide](/cloud/container-registry/manage-container-registries).

    To create and manage the Container Registry, you need to have 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) permissions.

    ## Step 1. Add a registry to the customer portal

    Start by creating a registry to which you will push OCI-compatible artifacts:

    1\. In the Gcore Customer Portal, navigate to **Cloud** > **Container Registries**.

    2\. Click **Create Container Registry**.

    <Frame>
      <img src="https://mintcdn.com/gcore/QIEAnezmG8Bl8nMk/images/docs/cloud/container-registry/create-container-registry/container-registry-page-create.png?fit=max&auto=format&n=QIEAnezmG8Bl8nMk&q=85&s=67519171e492e9d3e9a8198bb80f797d" alt="Container registry page in the Customer Portal" width="4244" height="1520" data-path="images/docs/cloud/container-registry/create-container-registry/container-registry-page-create.png" />
    </Frame>

    3\. Choose the region for the registry location. If you plan to store and manage images for other Gcore services, select the same region where those services are created.

    4\. Specify the registry name.

    <Tip>
      **Tip**

      A registry name should consist of lowercase Latin characters, which can be separated by dashes.
    </Tip>

    5\. Indicate the storage limit. It defines the amount of data that can be stored within the registry, including Docker images, artifacts, and image versions.

    6\. Click **Create Registry**.

    <Frame>
      <img src="https://mintcdn.com/gcore/QIEAnezmG8Bl8nMk/images/docs/cloud/container-registry/create-container-registry/create-registry.png?fit=max&auto=format&n=QIEAnezmG8Bl8nMk&q=85&s=c47efbbb803a97ae289977fd59aee878" alt="Create Container registry dialog in the Customer Portal" width="1099" height="626" data-path="images/docs/cloud/container-registry/create-container-registry/create-registry.png" />
    </Frame>

    The registry will appear along with the other registries on the **Container Registries** page.

    ## Step 2. Create a user

    To push and pull images from the registry, you need to authenticate as a particular user who has the required permissions for such operations.

    To add a new user to the registry:

    1\. Click the registry name to open it.

    2\. Open the **Users** tab and click **Add users**.

    <Frame>
      <img src="https://mintcdn.com/gcore/QIEAnezmG8Bl8nMk/images/docs/cloud/container-registry/create-container-registry/users-tab-empty.png?fit=max&auto=format&n=QIEAnezmG8Bl8nMk&q=85&s=ba4558d1ccac77899e3a02ce9a43eae0" alt="Users tab with no users created" width="4036" height="1244" data-path="images/docs/cloud/container-registry/create-container-registry/users-tab-empty.png" />
    </Frame>

    3\. Configure the user and its access:

    * **Username** : Enter a username. It should consist of lowercase Latin characters, which can be separated by dashes.

    * **Permissions** : Allow a user to either push or pull images to the registry or do both operations.

    * **Set activity duration** : enable this toggle to set the expiration date for user credentials. If you leave the toggle disabled, the user will retain indefinite access to the registry.

    4\. Click **Save**.

    <Frame>
      <img src="https://mintcdn.com/gcore/QIEAnezmG8Bl8nMk/images/docs/cloud/container-registry/create-container-registry/add-user.png?fit=max&auto=format&n=QIEAnezmG8Bl8nMk&q=85&s=27e26fe730a6d2fc42129e3fe5be9ec7" alt="Add users dialog" width="934" height="360" data-path="images/docs/cloud/container-registry/create-container-registry/add-user.png" />
    </Frame>

    5\. Copy and save the generated user password because you won't be able to check it again. If you forget the password, you'll have to regenerate it.

    <Frame>
      <img src="https://mintcdn.com/gcore/QIEAnezmG8Bl8nMk/images/docs/cloud/container-registry/create-container-registry/save-password.png?fit=max&auto=format&n=QIEAnezmG8Bl8nMk&q=85&s=6231a25446a1778f53a73ec5914e9dfd" alt="A dialog with a username and password" width="1849" height="610" data-path="images/docs/cloud/container-registry/create-container-registry/save-password.png" />
    </Frame>

    You can now log in as the created user and push or pull images from the Container Registry, as described in the following steps.

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

    When you open a registry, you can view the sample push and pull commands by clicking the relevant buttons.

    <Frame>
      <img src="https://mintcdn.com/gcore/QIEAnezmG8Bl8nMk/images/docs/cloud/container-registry/create-container-registry/push-pull-commands.png?fit=max&auto=format&n=QIEAnezmG8Bl8nMk&q=85&s=37d98d8760bc145b97693bf35ae6381d" alt="Registry overview page with highlighted push and pull buttons" width="3936" height="904" data-path="images/docs/cloud/container-registry/create-container-registry/push-pull-commands.png" />
    </Frame>

    To push a Docker image to the registry:

    1\. Log in to the registry: docker login `<your-registry-endpoint>`. For example, `docker login registry.luxembourg-2./10-01-test/`.

    2\. Enter the username of the user created in [Step](/cloud/container-registry/create-container-registry#step-2-create-a-user).

    3\. Enter the user password.

    4\. After you enter the credentials, you should see the "Login succeeded" message.

    5\. (Optional) Tag your image: `docker tag source_image:tag target_repository:target_tag`.

    6\. Push an image to the registry: `docker push <your-registry-endpoint/your-Docker-image>`.

    The image will appear in the Container Registry on the **Images** tab.

    <Frame>
      <img src="https://mintcdn.com/gcore/QIEAnezmG8Bl8nMk/images/docs/cloud/container-registry/create-container-registry/images-tab.png?fit=max&auto=format&n=QIEAnezmG8Bl8nMk&q=85&s=718a6dde5151ab693389cbbfd4fa3edd" alt="Registry overview page with highlighted images tab" width="4180" height="2220" data-path="images/docs/cloud/container-registry/create-container-registry/images-tab.png" />
    </Frame>

    For instructions on how to view and manage images, check out the [Manage Container Registries](/cloud/container-registry/manage-container-registries) guide.

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

    If you want to test how to pull the image and verify that everything works as expected, use the following command:

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

    The image will be pulled locally.
  </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).

      The full list of registry parameters is in the [create registry](/api-reference/cloud#tag/Registry/operation/RegistriesHandler.post) endpoint spec.

      ### 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 of the registry in the Customer Portal. For instructions on managing images, check out the [Manage Container Registries](/cloud/container-registry/manage-container-registries) guide.

      ### 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>
