— 4 min read


While pypip.in is available under the MIT license on GitHub, it’s not explained how to really use it properly.

You can gather how to set-up the Python source of the project and get the Twisted process running, this is totally reliant on using the img.shields.io.

I decided to write this article explaining how to install your own copy of the shields nodejs code, pypipin itself and even cover off supervisord and Varnish too.

shields & nodejs


First of all you’ll need to get the latest source code copy of nodejs from the nodejs download page.

Extract it.

tar -xvzf node-<VERSION>.tar.gz
cd node-<VERSION>

You’ll need to install the build tools, if you don’t have them already.

sudo apt-get install build-essential

And then make and install node.

make && sudo make install


Redis is used to temporarily store PyPI responses.

sudo apt-get install redis-server


You’ll need to install git for the next step.

sudo apt-get install git-core

And get a copy of the shields repository.

git clone git@github.com:badges/shields.git

Once it’s checked out, you’ll need to install it’s requirements.

cd shields && npm install

You can confirm this works by running the shields server.

node server 8080


Clone the shields repository, the same way you did for shields above.

git clone git@github.com:badges/pypipins.git

To do this properly, you’ll need to make sure you have virtualenv for Python.

sudo apt-get install python-dev
wget -O - https://bootstrap.pypa.io/get-pip.py | sudo python
sudo pip install virtualenv

Next, you’ll need to create a virtual environment.

virtualenv /path/to/where/you/want/it/

Then you can active it.

. /path/to/your/virtualenv/bin/activate

And install the dev requirements from the pypipins directory.

pip install -r /path/to/pypipins/clone/requirements-dev.txt

You’ll need to edit shields.py, commenting out the img.shields.io host and uncommon the local one.


# SHIELD_URL = "https://img.shields.io/badge/%s-%s-%s.%s"
SHIELD_URL = "http://localhost:9000/badge/%s-%s-%s.%s"  # pypip.in uses a local version of img.shields.io

Once this is done, you can test the pypipins server.

/path/to/your/virtualenv/bin/python /path/to/pypipins/clone/shields/shields.py


Always install supervisor from apt, rather than from pip.

sudo apt-get install supervisor

Then cd to where conf.d config files are stored for supervisor.

cd /etc/supervisor/conf.d/

In here, you’ll need to create a configuration for the shields nodejs server and also for pypipins server.


command=node server 9000

command=/path/to/virtualenv/bin/python /path/to/pypipin/clone/shields/shields.py

Once this is done, you’ll need to load them in to supervisor itself.

sudo supervisorctl
add shields
add pypipin

Now supervisor will automatically start both processes and keep them alive.


The final step is to put Varnish in front of the system to cache images for you. The shields server has the ability to use redis for caching but, I’d rather do this with a proper HTTP cache rather than use redis.

sudo apt-get install varnish

Tell Varnish to run on port 80.


DAEMON_OPTS="-a :80 \
             -T localhost:6082 \
             -f /etc/varnish/default.vcl \
             -S /etc/varnish/secret \
             -s malloc,256m"

This will run the Varnish HTTP server on port 80 and keep it’s admin interface hidden from the world, binding it to port 6082 on the lo interface.

The final step is to tell Varnish about the pypipins server.


backend default {
    .host = "";
    .port = "8888";

sub vcl_recv {
    if (req.request != "GET") {

    if (req.request == "GET") {
        remove req.http.cookie;
        remove req.http.authenticate;
        remove req.http.Etag;
        remove req.http.If-None-Match;

sub vcl_fetch {
    if (beresp.status >= 300) {

    set beresp.ttl = 1h;
    set beresp.grace = 6h;
    unset beresp.http.Set-Cookie;
    unset beresp.http.Etag;
    unset beresp.http.Cache-Control;
    set beresp.http.Cache-Control = "no-cache";
    return (deliver);

sub vcl_deliver {
      if (obj.hits > 0) {
            set resp.http.X-Cache = "HIT";
            set resp.http.X-Cache-Hits = obj.hits;
      } else {
            set resp.http.X-Cache = "MISS";

All done, restart Varnish.

sudo /etc/init.d/varnish restart

You’ll be able to go to http://yourserver.tld/download/<PACKAGE>/badge.svg and everything should be working as expected.

Notes on PyPy

I personally use PyPy for running the pypipins server because, it’s a long running process and PyPy speeds it up wonderfully.

If you’re using Debian 7, the latest version of PyPy as of writing is 2.3.1 and requires libffi6, if you’re using one of the prebuilt binaries. libffi6 is only available in Jessie which is currently in testing.

You can either use an older version of PyPy or, backport libffi6 from Jessie.


deb ftp://ftp.debian.org/debian/ jessie main

Package: *
Pin: release a=wheezy
Pin-Priority: 900

Package: libffi*
Pin: release a=jessie
Pin-Priority: 910

This will keep all packages pinned to wheezy except libffi+wildcard, which will be pulled from Jessie.

You can then simply install libffi6 from Jessie.

sudo apt-get update
sudo apt-get -u install libffi6/jessie


If you want to use SSL with your shields, you’ll need to install nginx in front of Varnish.

So instead of running Varnish on port 80, as shown above. Put it on a different port, install and use nginx as you would for any other website and simply proxy all requests back to Varnish.


Anarchist. Pessimist. Bipolar. Hacker. Hyperpolyglot. Musician. Ex-(semi-)pro gamer. They/Them.

View Source