Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Guide for how to create a (minimal) private PyPI repo, just using Apache with directory autoindex, and pip with an extra index URL.

How to set up and use a private PyPI repo

Accompanying blog post:

Splitting a Python codebase into dependencies for fun and profit

Based on:

Create a local PyPi repository using only mod_rewrite

See also:

Local PyPI Options

Setting up a private, team-wide PyPI repository

For a more advanced private PyPI, see:

devpi: PyPI server and packaging/testing/release tool

Create root directory for private PyPI


(On remote server)

mkdir /path/to/
mkdir /path/to/

Create self-signed SSL certificate

sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout /etc/apache2/ssl/ \
-out /etc/apache2/ssl/

Set up Apache vhost

sudo htpasswd -c /etc/apache2/passwords_pypi pypi
sudo vi /etc/apache2/sites-available/

(Add these lines)

<VirtualHost *:80>

    RewriteEngine On
    RewriteCond %{HTTPS} off
    RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}

<VirtualHost *:443>
    DocumentRoot /data/www/

    SSLEngine On
    SSLCertificateFile /etc/apache2/ssl/
    SSLCertificateKeyFile /etc/apache2/ssl/

    <Directory /data/www/>
        AllowOverride None
        Options +Indexes
        IndexOptions SuppressColumnSorting
        IndexIgnore ..
        Order deny,allow
        Allow from all

        AuthType Basic
        AuthName "My Server"
        AuthBasicProvider file
        AuthUserFile /etc/apache2/passwords_pypi
        Require valid-user

    LogLevel warn
    ErrorLog /var/log/apache2/pypi-error.log
    CustomLog /var/log/apache2/pypi-access.log combined

cd /etc/apache2/sites-enabled
sudo ln -s ../sites-available/
sudo apache2ctl graceful

Create directory for new library in private PyPI

mkdir /path/to/

Update library's code

(On local machine)

cd /path/to/foobar-utils

(Add these lines)

__version__ = '0.1.0'

foobar = 'Hey foo, I am a bar!'


(Add these lines)

import os

import setuptools

module_path = os.path.join(os.path.dirname(__file__), '')
version_line = [line for line in open(module_path)
                if line.startswith('__version__')][0]

__version__ = version_line.split('__version__ = ')[-1][1:][:-2]


    author="Mister foo",

    description="Utils for handling Foo and Bar.",



        'Development Status :: 2 - Pre-Alpha',
        'Environment :: Web Environment',
        'Intended Audience :: Developers',
        'Operating System :: OS Independent',
        'Programming Language :: Python',
        'Programming Language :: Python :: 2',
        'Programming Language :: Python :: 2.7',
        'Programming Language :: Python :: 3',
        'Programming Language :: Python :: 3.3',

vi README.rst

(Add these lines)


Utils for handling Foo and Bar.

Upload new version of library code to private PyPI

python bdist_wheel --universal
scp dist/foobar_utils-0.1.0-py2.py3-none-any.whl \

Configure pip to use private PyPI

vi ~/.pip/pip.conf

(Add these lines)

; Extra index to private pypi dependencies
extra-index-url =
trusted-host =

Use private library in a project's requirements.txt

cd /path/to/projectfoo
virtualenv .
source bin/activate
vi requirements.txt

(Add these lines)


pip install -r requirements.txt

brettswift commented Aug 17, 2017 edited

any idea how to use this without the user dot files? That kinda sucks when you want to have other people set up on your team right away. Obviously these packages will be sourced from the same spot. I'm new to python - just wondering if it can go into a config file in the project, just no luck finding this on google yet.

Also supplying them with environment variables, so we can do continuous delivery of our modules from a CI server, would be good info :)

looks like this is a preferred way of deploying

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment