Setting a Private PyPI Server With NGINX

In this post, we will set up a private PyPI server using the pypiserver Docker image, which will be wrapped by NGINX for caching and performance.

Maroun Maroun
Mar 2 · 4 min read
Photo by Spencer Judd on Unsplash

What is PyPI?

Docker Setup

Docker installation

PyPI Server Setup

# replace with your name
mkdir /home/maroun/pypi-server
mkdir nginx nginx_cache
mkdir nginx/conf.d

Starting the Server

docker-compose up -d
$ curl localhost:8080
<!DOCTYPE html>
<html lang="en">
<meta charset="utf-8">
<title>Welcome to pypiserver!</title>
Welcome to pypiserver!
This is a PyPI compatible package index serving 11 packages.
To use this server with <code>pip</code>, run the following command:
<code>pip install --index-url http://pypi-server:8080/simple/ PACKAGE [PACKAGE2...]</code>
To use this server with <code>easy_install</code>, run the following command:
<code>easy_install --index-url http://pypi-server:8080/simple/ PACKAGE [PACKAGE2...]</code>
The complete list of all packages can be found <a href="/packages/">here</a> or via the <a href="/simple/">simple</a> index.
This instance is running version 1.4.2 of the <a href="">pypiserver</a> software.

Downloading Packages

pip install --index-url http://<IP>:8080 my_package --trusted-host <IP>

Authenticating Requests

sudo yum install -y httpd-tools
mkdir authentication
# create .htpasswd file and force SHA encryption
htpasswd -sc .htpasswd pypi-user
Docker compose YML
pypi-server understands the following options:

-p, --port PORT
Listen on port PORT (default: 8080).

-i, --interface INTERFACE
Listen on interface INTERFACE (default:, any interface).

-a, --authenticate (update|download|list), ...
Comma-separated list of (case-insensitive) actions to authenticate.
Requires to have set the password (-P option).
To password-protect package downloads (in addition to uploads) while
leaving listings public, use:
-P foo/htpasswd.txt -a update,download
To allow unauthorized access, use:
-P . -a .
Note that when uploads are not protected, the `register` command
is not necessary, but `~/.pypirc` still need username and password fields,
even if bogus.
By default, only 'update' is password-protected.


Geek Culture

Proud to geek out.

Sign up for Geek Culture Hits

By Geek Culture

Subscribe to receive top 10 most read stories of Geek Culture — delivered straight into your inbox, once a week. Take a look.

By signing up, you will create a Medium account if you don’t already have one. Review our Privacy Policy for more information about our privacy practices.

Check your inbox
Medium sent you an email at to complete your subscription.

Geek Culture

A new tech publication by Start it up (

Maroun Maroun

Written by

Software engineer | Music geek | Beer lover

Geek Culture

A new tech publication by Start it up (

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store