Safeguard
Software Supply Chain•

How do you run a private mirror or proxy for crates.io?

Cargo can swap crates.io for a mirror or vendored copy through source replacement. Learn the config, the rules and what a mirror does and does not protect.

Safeguard Security Team
5 min read

Cargo supports mirroring through source replacement. You point the crates-io source at a registry that serves identical crates, either a mirror you host or a vendored local copy, using a config file. A mirror gives you availability and control. It does not vet what the original registry publishes.

What is source replacement?

The Cargo Book defines a source as a provider of crates. Source replacement redirects Cargo's communication with a registry, or with git dependencies, to another data source such as a server mirroring the original registry or an exact local copy. Two documented strategies: vendoring, where custom sources represent crates on the local filesystem, and mirroring, where a source is replaced by an equivalent that acts as a cache for crates.io itself.

There is one firm rule: Cargo assumes the source code is exactly the same from both sources. A replacement source may not contain crates absent from the original. That is why the book says source replacement is not appropriate for patching a dependency or for a private registry. Patching uses the patch key, and a private registry uses the registries feature, where you name an alternate registry and depend on crates from it explicitly.

What does the configuration look like?

In .cargo/config.toml, you define a source and tell crates-io to be replaced with it:

[source.crates-io]
replace-with = "internal-mirror"

[source.internal-mirror]
registry = "sparse+https://crates.example.internal/index/"

A registry source works like crates.io itself: an index following the registry index specification, plus a configuration file saying where to download crates. It may use the git protocol or the sparse HTTP protocol, written with a sparse plus prefix. The registry URL above is a placeholder you replace with your own.

When commands need to contact the registry directly, such as publishing, the book says to pass the registry option to avoid ambiguity about which registry and token to use.

What are the vendoring options?

Two local forms exist:

  • Local registry sources: a subset of another registry, available on the filesystem, made of crate files and an index. They are typically synced with a Cargo.lock, and managed with the cargo-local-registry subcommand.
  • Directory sources: unpacked crates, managed with the cargo vendor subcommand, which suits checking everything into source control. Each crate has a checksum metadata file, but the book states plainly that it protects against accidental modifications, is not a security mechanism, and does not protect against malicious changes.

That last point matters in review. A vendored directory in your repository is only as trustworthy as the review of changes to it.

Why mirror at all?

Reasons that hold up: builds survive an outage or a yanked crate, CI avoids rate limits, you control egress from build machines, and you gain a place to log and monitor what is fetched. The Cargo FAQ explains why to keep Cargo.lock in version control: it describes the state of the world at the time of a successful build, so builds repeat. A mirror plus a committed lockfile means CI fetches known versions from a known host.

What a mirror cannot do: judge crate quality, notice a malicious publish, or stop you from locking a bad version. Review and scanning remain your job.

Constructed example

A build team sets up a sparse mirror inside its network. Developers get a shared config file in the repository that replaces crates-io. CI runs with the lockfile enforced, and network egress from build runners is limited to the mirror. A new crate version appears upstream. It reaches CI only after a developer updates the lockfile in a pull request, which triggers a dependency scan and review.

What to do

  1. Decide the goal: availability, egress control, or an auditable fetch log.
  2. Pick the mirror form: a sparse registry server, a local registry, or vendored directories.
  3. Write the source replacement into a config file shared by developers and CI.
  4. Commit Cargo.lock for binaries and run CI with the lockfile enforced.
  5. Restrict build runner network access to the mirror host.
  6. Keep private crates in a named alternate registry, not in the mirror.
  7. Review any change to vendored directories as code.
  8. Scan the lockfile for vulnerable and suspicious crates on every pull request.

Safeguard can scan a Rust project's dependency inventory in pull requests and report vulnerable crates. It works alongside a mirror and does not host one.

Quick check

Can a mirror hold crates that are not on crates.io?

No. Cargo assumes the replacement is exactly the same as the original, so extra crates are not allowed. Use an alternate registry for private crates.

Does the vendor checksum file protect against tampering?

No. The Cargo Book says it guards against accidental modification and is not a security mechanism, so review vendored changes.

Sources

Last reviewed: 18 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.