---
description: |-
  The provider network mirror protocol is implemented by a server intending
  to provide a mirror or read-through caching proxy for OpenTofu providers,
  as an alternative distribution source from the provider's origin provider
  registry.
---

# Provider Network Mirror Protocol

The provider network mirror protocol is an optional protocol which you can
implement to provide an alternative installation source for Terraform providers,
regardless of their origin registries.

OpenTofu uses network mirrors only if you activate them explicitly in
[the CLI configuration's `provider_installation` block](../cli/config/config-file.mdx#provider-installation).
When enabled, a network mirror can serve providers belonging to any registry
hostname, which can allow an organization to serve all of the OpenTofu
providers they intend to use from an internal server, rather than from each
provider's origin registry.

This is _not_ the protocol that should be implemented by a host intending to
serve as an origin registry for OpenTofu Providers. To provide an origin
registry (whose hostname would then be included in the source addresses of the
providers it hosts), implement
[the provider registry protocol](../internals/provider-registry-protocol.mdx)
instead.

## Provider Addresses

Each OpenTofu provider has an associated address which uniquely identifies it
within OpenTofu. A provider address has the syntax `hostname/namespace/type`,
which is described in more detail in
[the Provider Requirements documentation](../language/providers/requirements.mdx).

By default, the `hostname` portion of a provider address serves both as part
of its unique identifier _and_ as the location of the registry to retrieve it
from. However, when you configure OpenTofu to install providers from a network
mirror, the `hostname` serves _only_ as an identifier and no longer as
an installation source. A provider mirror can therefore serve providers
belonging to a variety of different provider registry hostnames, including
providers from the public OpenTofu Registry at `registry.opentofu.org`, from a
single server.

In the relative URL patterns later in this document, the placeholder `:hostname`
refers to the hostname from the address of the provider being requested, not
the hostname where the provider network mirror is deployed.

## Protocol Base URL

Most OpenTofu-native services use
[the remote service discovery protocol](../internals/remote-service-discovery.mdx) so
that the physical location of the endpoints can potentially be separated from
the hostname used in identifiers. The Provider Network Mirror protocol does
_not_ use the service discovery indirection, because a network mirror location
is only a physical location and is never used as part of the identifier of a
dependency in a OpenTofu configuration.

Instead, the provider installation section of the CLI configuration accepts
a base URL directly. The given URL must use the scheme `https:`, and should
end with a trailing slash so that the relative URLs of the individual operation
endpoints will be resolved beneath it.

```hcl
provider_installation {
  network_mirror {
    url = "https://tofu.example.com/providers/"
  }
}
```

OpenTofu uses the base URL only as a stem to resolve the operation endpoint
URLs against, and so it will never access the base URL directly. You can
therefore, if desired, publish human-readable usage documentation for your
network mirror at that URL.

The following sections describe the various operations that a provider
network mirror server must implement to be compatible with OpenTofu CLI's
provider installer. The indicated URLs are all relative to the given base URL,
as described above.

The URLs are shown with the convention that a path portion with a colon `:`
prefix is a placeholder for a dynamically-selected value, while all other
path portions are literal. For example, in `:hostname/:namespace/:type/index.json`,
the first three path portions are placeholders while the third is literally
the string "index.json".

The example requests in the following sections will assume the example mirror
base URL from the above CLI configuration example.

### Authentication

If the CLI configuration includes
[credentials](../cli/config/config-file.mdx#credentials) for the hostname
given in the network mirror base URL, OpenTofu will include those credentials
in its requests for operations described below.

If the given URL uses a non-standard port number (other than 443) then the
credentials must be associated with a hostname that includes the port number,
such as `tofu.example.com:8443`.

OpenTofu does _not_ send credentials when retrieving the archives whose
URLs are given in the "List Available Installation Packages" response below.
If a particular mirror considers the distribution packages themselves to be
sensitive then it must use cryptographically-secure, user-specific, and
time-limited URLs in the metadata response. Strategies for doing so are out
of scope of this protocol documentation.

## List Available Versions

This operation determines which versions are currently available for a
particular provider.

| Method | Path                                    | Produces           |
| ------ | --------------------------------------- | ------------------ |
| `GET`  | `:hostname/:namespace/:type/index.json` | `application/json` |

### Parameters

* `hostname` (required): the hostname portion of the address of the requested
  provider.
* `namespace` (required): the namespace portion of the address of the requested
  provider.
* `type` (required): the type portion of the address of the requested provider.

### Sample Request

```
curl 'https://tofu.example.com/providers/registry.tofu.io/hashicorp/random/index.json'
```

### Sample Response

```json
{
  "versions": {
    "2.0.0": {},
    "2.0.1": {}
  }
}
```

### Response Properties

A successful result is a JSON object containing a single property `versions`,
which must be a JSON object.

Each of the property names of the `versions` object represents an available
version number. The property values must be objects, but no properties are defined for those objects. We recommend leaving those objects empty for forward compatibility.

Return `404 Not Found` to signal that the mirror does not have a provider
with the given address.

## List Available Installation Packages

This operation returns download URLs and associated metadata for the
distribution packages for a particular version of a provider.

Each distribution package is associated with a particular operating system
and architecture. A network mirror may host only a subset of the available
packages for a provider version, if the users of the mirror are known to all
use only a subset of the target platforms that OpenTofu supports.

OpenTofu CLI uses this operation after it has selected the newest available
version matching the configured version constraints, in order to find a zip
archive containing the plugin itself.

| Method | Path                                       | Produces           |
| ------ | ------------------------------------------ | ------------------ |
| `GET`  | `:hostname/:namespace/:type/:version.json` | `application/json` |

### Parameters

* `hostname` (required): the hostname portion of the address of the requested
  provider.
* `namespace` (required): the namespace portion of the address of the requested
  provider.
* `type` (required): the type portion of the address of the requested provider.
* `version` (required): the version selected to download. This will exactly
  match one of the version strings returned from a previous call to
  [List Available Versions](#list-available-versions).

### Sample Request

```
curl 'https://tofu.example.com/providers/registry.tofu.io/hashicorp/random/2.0.0.json'
```

### Sample Response

```json
{
  "archives": {
    "darwin_amd64": {
      "url": "terraform-provider-random_2.0.0_darwin_amd64.zip",
      "hashes": [
        "h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs="
      ]
    },
    "linux_amd64": {
      "url": "terraform-provider-random_2.0.0_linux_amd64.zip",
      "hashes": [
        "h1:lCJCxf/LIowc2IGS9TPjWDyXY4nOmdGdfcwwDQCOURQ="
      ]
    }
  }
}
```

### Response Properties

A successful result is a JSON object with a property called `archives`, which
must be a JSON object.

Each of the property names of the `archives` object is a target platform
identifier, which consists of an operating system and architecture concatenated
with an underscore (`_`).

Each property value in the `archives` object is itself a nested object with
the following properties:

* `url` (required): a string specifying the URL from which OpenTofu should
  download the `.zip` archive containing the requested provider plugin version.

  OpenTofu resolves the URL relative to the URL from which the current
  JSON document was returned, so the examples above containing only a
  filename would cause OpenTofu to construct a URL like:

  ```
  https://tofu.example.com/providers/registry.opentofu.org/hashicorp/random/terraform-provider-random_2.0.0_darwin_amd64.zip
  ```

* `hashes` (optional): a JSON array of strings containing one or more hash
  values for the indicated archive. These hashes use OpenTofu's provider
  package hashing algorithm. At present, the easiest way to populate these
  is to construct a mirror's JSON indices using the `tofu providers mirror`
  command, as described in a later section, which will include the calculated
  hashes of each provider.

  If the response includes at least one hash, OpenTofu will select the hash
  whose algorithm it considers to be strongest and verify that the downloaded
  package matches that hash. If the response does not include a `hashes`
  property then OpenTofu will install the indicated archive with no
  verification.

OpenTofu CLI will only attempt to download versions that it has previously
seen in response to [List Available Versions](#list-available-versions).

## Provider Mirror as a Static Website

The provider mirror protocol is designed so that it can potentially be implemented
by placing files on typical static website hosting services. When using this
strategy, implement the JSON index responses described above as `.json` files
in the appropriate nested subdirectories, and ensure that your system is
configured to serve `.json` files with the `application/json` media type.

As a convenience, OpenTofu CLI includes
[the `tofu providers mirror` subcommand](../cli/commands/providers/mirror.mdx),
which will analyze the current configuration for the providers it requires,
download the packages for those providers from their origin registries, and
place them into a local directory suitable for use as a mirror.

The `tofu providers mirror` subcommand also generates `index.json` and
version-specific `.json` files that can, when placed in a static website hosting
system, produce responses compatible with the provider mirror protocol.

If you wish to create a mirror with providers for a number of different
OpenTofu configurations, run `tofu providers mirror` in each configuration
in turn while providing the same output directory each time. OpenTofu will
then merge together all of the requirements into a single set of JSON indices.
