Host a Private Cargo Registry¶
This guide walks you through setting up Pulp as a private Cargo registry for hosting internal crates. This is useful for organizations that need to distribute proprietary or internal-only Rust packages.
Create a Repository¶
pulp rust repository create --name my-crates
Create a Distribution¶
A distribution makes the repository's content available to Cargo over HTTP. Set --allow-uploads
to enable publishing crates via cargo publish.
pulp rust distribution create \
--name my-crates \
--base-path my-crates \
--repository my-crates \
--allow-uploads
Your private registry is now served at http://<pulp-host>/pulp/cargo/my-crates/.
Configure Cargo¶
Add the private registry to your Cargo configuration. Create or edit ~/.cargo/config.toml:
[registries.my-crates]
index = "sparse+http://<pulp-host>/pulp/cargo/my-crates/"
Authentication¶
State-changing operations (publishing, yanking, and unyanking) require an authorization token.
Configure the token for your registry in ~/.cargo/credentials.toml:
[registries.my-crates]
token = "i_understand_that_pulp_rust_does_not_support_proper_auth_yet"
Alternatively, you can pass the token on the command line:
cargo publish --registry my-crates --token "i_understand_that_pulp_rust_does_not_support_proper_auth_yet"
Warning
This is a temporary stub token. Proper token-based authentication is planned for a future release. The stub token exists to ensure that the authentication workflow is exercised and that state-changing operations are not completely open.
Read-only operations (downloading crates, browsing the index) do not require a token.
Publish a Crate¶
Once the registry is configured and a distribution with --allow-uploads exists, you can publish
crates using standard Cargo tooling:
cargo publish --registry my-crates
This uploads the crate to Pulp, which creates the artifact, content metadata, and a new repository version. The crate is immediately available for download through the distribution.
Publishing the same crate version twice is rejected — crate versions are immutable, consistent with crates.io behavior.
Yank and Unyank¶
Yanking marks a crate version as unavailable for new dependency resolution, while still allowing existing projects that already depend on it to continue downloading it. This matches the crates.io yank semantics.
# Yank a version
cargo yank --registry my-crates --version 1.0.0 my-crate
# Unyank a version
cargo yank --registry my-crates --version 1.0.0 --undo my-crate
Using the Private Registry as a Dependency Source¶
To depend on crates from your private registry, specify the registry in your Cargo.toml:
[dependencies]
my-internal-lib = { version = "1.0", registry = "my-crates" }
Setting the Default Registry¶
You can set your private registry as the default for cargo publish and other registry commands
so you don't need to pass --registry every time:
[registry]
default = "my-crates"
This affects commands like cargo publish, cargo yank, and cargo owner. It does not
change where dependencies are resolved from — that is controlled by source replacement (below).
Tip
Setting a default registry is recommended for organizations with private crates. Without it,
running cargo publish without --registry will publish to crates.io by default, which could
accidentally leak proprietary code to the public registry.
Replacing crates.io Entirely¶
If you want all crate lookups to go through your private registry (for example, in an air-gapped environment), you can replace the default source:
[source.crates-io]
replace-with = "my-crates"
[source.my-crates]
registry = "sparse+http://<pulp-host>/pulp/cargo/my-crates/"
This redirects all dependency resolution — including transitive dependencies — through your private registry. Any crate not present in the registry will fail to resolve.
Combining with Pull-Through Caching¶
If you need both private crates and public crates.io dependencies, use separate distributions and
separate repositories -- one for publishing and one for pull-through caching. Pulp enforces that
a distribution cannot have both allow_uploads and a remote set at the same time.
Warning
The two distributions should also use separate repositories. Mixing public and private content in a single repository creates a risk of dependency confusion attacks, where a crate from the public registry conflicts with a private crate of the same name and version.
# Set up a separate pull-through cache for crates.io
pulp rust remote create --name crates-io --url "sparse+https://index.crates.io/" --policy on_demand
pulp rust repository create --name crates-io-cache --remote crates-io --retain-repo-versions 1
pulp rust distribution create \
--name crates-io-cache \
--base-path crates-io-cache \
--repository crates-io-cache \
--remote crates-io
Then configure Cargo to use both registries, with crates.io going through the cache and private crates resolved from your private registry:
[registries.my-crates]
index = "sparse+http://<pulp-host>/pulp/cargo/my-crates/"
[source.crates-io]
replace-with = "crates-io-cache"
[source.crates-io-cache]
registry = "sparse+http://<pulp-host>/pulp/cargo/crates-io-cache/"
[dependencies]
serde = "1.0" # resolved from crates-io-cache
my-internal-lib = { version = "1.0", registry = "my-crates" } # resolved from private registry
Crate Name Handling¶
Crate names in the Cargo spec are case-insensitive, and hyphens and underscores are treated as
equivalent (e.g. my-crate and my_crate refer to the same package). Pulp enforces this:
publishing my-crate when my_crate already exists in the same repository is rejected as a
duplicate. Yank and unyank operations use the same matching.
Separate Registries
Keep private registries and public pull-through caches as separate distributions (and preferably separate repositories). This makes it easy to audit which registries have upstream access and reduces the risk of accidental misconfiguration. For additional isolation or access control, they could be kept on entirely separate domains.
Further Reading¶
- Cargo registries configuration -- configuring alternate registries in Cargo
- Cargo source replacement -- replacing crates.io with an alternate source
- Cargo config reference -- full reference for
.cargo/config.toml - Specifying dependencies -- using dependencies from alternate registries