Setting up a private, team-wide PyPI repository

On Wed 29 August 2012 | By Raphaël Barrois | Category : Python | Tags : System ~ Python

When developing Python applications, it may be useful to store some applications in a private repository.

This provides several benefits:

  • Dependencies available even if PyPI and its mirrors are down
  • Storing custom forks of upstream packages
  • Providing private packages in a standardized manner.

For this purpose, three components are required:

  • A private index. This should be served over HTTP, with the index.html file containing links to available packages (see for a typical simple index. It can be protected by basic auth (e.g for private packages)
  • Properly configured local installation tools. The target is to have those tools looking at the private repository alongside PyPI.
  • Proper scripts for private packages, to prevent upload to the public PyPI repository.

Setting up the private index

Many tools exist for this, with two major families:

If your repository contains private packages, you should serve it only over HTTPS, since most Python packaging tools only use basic authentication.

Setting up the local tools

The ~/.pip/pip.conf file holds all pip-related configurations. It mostly supports a extra-index-url option for providing extra repository URLs:

; Low timeout
timeout = 20

; Custom index
extra-index-url = https://<user>:<pass>

It is also possible to completely replace the PyPI index by setting the index-url option instead.


The --extra-index-url can also be provided as a command line option. An alternate PIP configuration file can be used by setting the PIP_CONFIG_FILE env variable.

For distribute/distutils, use the .pypirc configuration file. This is mostly useful to register username/password combinations for private repositories:

index-servers =



Setting this will configure the login/pass to use for python register, upload, ... commands.

Protecting the private packages

I couldn't find any existing package for restricting upload/register/... of a package to a private repository, so I wrote the restricted_pkg package for that.

This package provides a custom setup() function, which performs the following actions:

  • Restrict upload, register and upload_docs command to the private repository, using the stored credentials or prompting if needed
  • Use the private repository along with PyPI for the install and easy_install commands. The private repository may replace PyPI if the --disable-pypi option is provided.

This means that the script for such packages should look like:

from restricted_pkg import setup


The @ in the repository URL indicates that this repository requires auth, but avoids committing a username:password string in the script.