Close modal

Blog Post

Using a private pypi repository with pypiserver (and alternatives)

Wed 23 May 2018

Some options:

  • Create your own PyPi server
  • Use Dumb PyPi to generate and farm out the context to a simple web server.
  • Some other options such as PyPiCloud which falls in between the two above.

Using PyPiServer

Depending on your workflow, and how frequently and many packages are updated, PyPi server may be the most suitable, it does require an application server (python/bottle) to function, but does not require the whole thing to be rebuilt and pushed as the static version, and can handle authentication for actions (configurable).

For this case, to make things even easier, we will use the PyPiServer docker image to get going even faster, if you do not use Docker then the full installation can be achieved, or use of the static solutions mentioned.


On your Docker host extract or checkout the docker project for PyPiServer.

$ mkdir /srv/pypi
$ printf "USER:$(openssl passwd -crypt PASSWORD)\n" >> .htpasswd
$ docker run -t -i --rm \
    -h \
    -v /srv/pypi:/srv/pypi:rw \
    -p <some_external_port>:80 \
    --name pypi \

You should now have a pypi server accessible on localhost:. Use a reverse proxy or the like to expose this if you prefer, and access

Uploading to your server

The standard layour for any package to upload to PyPi looks like:

  • my_package
  • setup.cfg

The setup.cfg file is rather simple and looks like so:

description-file =

As for, it will look like:

from distutils.core import setup
  name = 'my_package',
  packages = ['my_package'], # this must be the same as the name above
  install_requires=[],  # list any dependencies that must be installed to use this
  version = '0.0.1',
  description = 'My useful python library',
  author = 'Your Name Here',
  author_email = '',
  url = '', # Where the repo is
  download_url = '', # Archive you can curl
  keywords = ['utilities'], # any useful keywords
  classifiers = []

Obviously will expose the classes like:

from some_utility import Widget

Also, that is assuming looks like :

class Widget:
    def __init__(self):

One more thing, edit your ~/.pypirc :::ini [server-login] repository: username: USER password: PASSWORD

Now we can upload!

$ python3 sdist upload -r
Using pip to install

There are a couple of ways to do this:

Command line options

When you invoke pip, you can specify the private server as per below:

$ pip3 install my_package--trusted-host --index-url

Edit your ~/.bashrc or ~/.zshrc etc

PIP config

Edit ~/.pip/pip.conf

extra-index-url =

That's it, fire it up and you should see it go. You can also install packages that are on the regular pypi even if you have specified your private server, however I imagine conflicting names would install first from the private repo.

Using Dumb PyPi, etc

I could not get Dumb PyPi to work due to an import error with pip.wheel (not sure if a versioning issue, so I will not cover it in detail.

The layout of the python package is the same as the above when using the PyPiServer, as well as the client side installation using pip.

So the generation of the static html and upload to a webserver (and subsequent location of web content) will be what is different, depending on your needs.


Using a custom/private PyPi to distribute your python packages is fairly straight forward. It is cleaner and more elegant than using things such as git submodules and allows the packages to be delivered to almost any python installation.

Comments !