|
| 1 | +# Host a Private Cargo Registry |
| 2 | + |
| 3 | +This guide walks you through setting up Pulp as a private Cargo registry for hosting internal |
| 4 | +crates. This is useful for organizations that need to distribute proprietary or internal-only |
| 5 | +Rust packages. |
| 6 | + |
| 7 | +!!! note |
| 8 | + Package publishing support (`cargo publish`) is not yet available but is planned for an |
| 9 | + upcoming release. In the meantime, content can be uploaded through the Pulp REST API. |
| 10 | + |
| 11 | +## Create a Repository |
| 12 | + |
| 13 | +```bash |
| 14 | +pulp rust repository create --name my-crates |
| 15 | +``` |
| 16 | + |
| 17 | +## Create a Distribution |
| 18 | + |
| 19 | +A distribution makes the repository's content available to Cargo over HTTP. |
| 20 | + |
| 21 | +```bash |
| 22 | +pulp rust distribution create \ |
| 23 | + --name my-crates \ |
| 24 | + --base-path my-crates \ |
| 25 | + --repository my-crates |
| 26 | +``` |
| 27 | + |
| 28 | +Your private registry is now served at `http://<pulp-host>/pulp/cargo/my-crates/`. |
| 29 | + |
| 30 | +## Configure Cargo |
| 31 | + |
| 32 | +Add the private registry to your Cargo configuration. Create or edit `~/.cargo/config.toml`: |
| 33 | + |
| 34 | +```toml |
| 35 | +[registries.my-crates] |
| 36 | +index = "sparse+http://<pulp-host>/pulp/cargo/my-crates/" |
| 37 | +``` |
| 38 | + |
| 39 | +### Using the Private Registry as a Dependency Source |
| 40 | + |
| 41 | +To depend on crates from your private registry, specify the registry in your `Cargo.toml`: |
| 42 | + |
| 43 | +```toml |
| 44 | +[dependencies] |
| 45 | +my-internal-lib = { version = "1.0", registry = "my-crates" } |
| 46 | +``` |
| 47 | + |
| 48 | +### Setting the Default Registry |
| 49 | + |
| 50 | +You can set your private registry as the default for `cargo publish` and other registry commands |
| 51 | +so you don't need to pass `--registry` every time: |
| 52 | + |
| 53 | +```toml |
| 54 | +[registry] |
| 55 | +default = "my-crates" |
| 56 | +``` |
| 57 | + |
| 58 | +This affects commands like `cargo publish`, `cargo yank`, and `cargo owner`. It does **not** |
| 59 | +change where dependencies are resolved from — that is controlled by source replacement (below). |
| 60 | + |
| 61 | +!!! tip |
| 62 | + Setting a default registry is recommended for organizations with private crates. Without it, |
| 63 | + running `cargo publish` without `--registry` will publish to crates.io by default, which could |
| 64 | + accidentally leak proprietary code to the public registry. |
| 65 | + |
| 66 | +### Replacing crates.io Entirely |
| 67 | + |
| 68 | +If you want all crate lookups to go through your private registry (for example, in an air-gapped |
| 69 | +environment), you can replace the default source: |
| 70 | + |
| 71 | +```toml |
| 72 | +[source.crates-io] |
| 73 | +replace-with = "my-crates" |
| 74 | + |
| 75 | +[source.my-crates] |
| 76 | +registry = "sparse+http://<pulp-host>/pulp/cargo/my-crates/" |
| 77 | +``` |
| 78 | + |
| 79 | +This redirects all dependency resolution — including transitive dependencies — through your |
| 80 | +private registry. Any crate not present in the registry will fail to resolve. |
| 81 | + |
| 82 | +## Combining with Pull-Through Caching |
| 83 | + |
| 84 | +If you need both private crates and public crates.io dependencies, we recommend keeping them as |
| 85 | +**separate registries** rather than mixing them into one. This avoids |
| 86 | +[dependency confusion](https://medium.com/@alex.birsan/dependency-confusion-4a5d60fec610) attacks, |
| 87 | +where a malicious package on a public registry could impersonate a private dependency. |
| 88 | + |
| 89 | +```bash |
| 90 | +# Set up a separate pull-through cache for crates.io |
| 91 | +pulp rust remote create --name crates-io --url "sparse+https://index.crates.io/" --policy on_demand |
| 92 | +pulp rust repository create --name crates-io-cache --remote crates-io --retain-repo-versions 1 |
| 93 | +pulp rust distribution create \ |
| 94 | + --name crates-io-cache \ |
| 95 | + --base-path crates-io-cache \ |
| 96 | + --repository crates-io-cache \ |
| 97 | + --remote crates-io |
| 98 | +``` |
| 99 | + |
| 100 | +Then configure Cargo to use both registries, with crates.io going through the cache and private |
| 101 | +crates resolved from your private registry: |
| 102 | + |
| 103 | +```toml |
| 104 | +[registries.my-crates] |
| 105 | +index = "sparse+http://<pulp-host>/pulp/cargo/my-crates/" |
| 106 | + |
| 107 | +[source.crates-io] |
| 108 | +replace-with = "crates-io-cache" |
| 109 | + |
| 110 | +[source.crates-io-cache] |
| 111 | +registry = "sparse+http://<pulp-host>/pulp/cargo/crates-io-cache/" |
| 112 | +``` |
| 113 | + |
| 114 | +```toml |
| 115 | +[dependencies] |
| 116 | +serde = "1.0" # resolved from crates-io-cache |
| 117 | +my-internal-lib = { version = "1.0", registry = "my-crates" } # resolved from private registry |
| 118 | +``` |
| 119 | + |
| 120 | +!!! warning |
| 121 | + Avoid adding a public remote (such as crates.io) to a private registry's distribution. Mixing |
| 122 | + public and private packages in a single registry index creates a risk of dependency confusion |
| 123 | + attacks, where an attacker publishes a crate on the public registry with the same name as one |
| 124 | + of your private crates. |
| 125 | + |
| 126 | +## Further Reading |
| 127 | + |
| 128 | +- [Cargo registries configuration](https://doc.rust-lang.org/cargo/reference/registries.html) -- configuring alternate registries in Cargo |
| 129 | +- [Cargo source replacement](https://doc.rust-lang.org/cargo/reference/source-replacement.html) -- replacing crates.io with an alternate source |
| 130 | +- [Cargo config reference](https://doc.rust-lang.org/cargo/reference/config.html) -- full reference for `.cargo/config.toml` |
| 131 | +- [Specifying dependencies](https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#specifying-dependencies-from-other-registries) -- using dependencies from alternate registries |
0 commit comments