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
Geek Culture
4 min readMar 2, 2021

--

Photo by Spencer Judd on Unsplash

What is PyPI?

The official docs:

The Python Package Index (PyPI) is a repository of software for the Python programming language.

PyPI is the official 3rd party software repository for the Python language.

To install packages from the PyPI repository, you will need a package installer. The most common and recommended one is pip.

PyPI is public, anyone can access it and download any package listed there. However, sometimes you want to create your own private repository, mainly for security reasons.

Docker Setup

To set up a PyPI server, you will need a server — it can be your own machine, your friend’s, or a machine in the cloud (AWS, GCP, …). In this tutorial, I assume that you already have a server that will host your private repository.

Since we’ll use Docker to run the server, we need to install Docker:

Docker installation

PyPI Server Setup

Let’s create a new directory for our PyPI configurations.

Create docker-compose.yml:

Note that we are currently allowing unauthorized access by specifying the -P . -a . command.

Now, we should configure our NGINX server. From within pypi-server, create the following directories:

Now, add pypi.conf the conf.d with the following content:l

We are listening on port 80 (default port), and passing all requests to “pypi-server:8080”, where our PyPI server is running.

By default, Compose sets up a single network for our application. Each container for a service joins the default network and is both reachable by other containers on that network, and discoverable by them at a hostname identical to the container name. That’s why we can use the pypi-server host in the configuration above.

Finally, let’s add (the default) nginx.conf in the nginx directory, which includes our custom configuration above (line 27):

nginx.conf

Starting the Server

By now, we should be able to run the following from the pypi-server directory:

Accessing the home route from the server:

Downloading Packages

Using pip, you can now download packages from your own private repository!

Publishing packages to our newly created server can be done using Twine. Go ahead and check its documentation for further information.

Authenticating Requests

While we are now working with our private repository, anyone who has access to our server can interact with the repository. To protect it, we can use htpasswd. Install the httpd-tools:

Now, create a folder for authentication:

and create a username:

you will be prompted to insert a password. Once done, .htpasswd will create an entry for the new user, with a hashed password:

We should next update our Docker compose file:

Docker compose YML

Note that we changed the command to require authentication for the update, download, and list commands. You can check the manual of the pypi-server command:

Accessing the PyPI server will now require authentication.

Summary

Sometimes you don’t want to host your packages in a public repository. Creating a custom PyPI server is a good idea for increasing security and not exposing your packages to everyone.

Using NGINX, we introduced a caching mechanism, and we can easily configure a load-balancer when needed.

--

--