Skip to content


Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time


A multiarchitecture container image for running Python with Gunicorn.

Looking for the containers? Head over to the Github Container Registry!


Multi Architecture Builds

Every tag in this repository supports these architectures:

  • linux/amd64
  • linux/arm64
  • linux/arm/v7

Small Images via Multi Stage Builds

All libraries are compiled in one image before being moved into the final published image. This keeps all of the build tools out of the published container layers.

No Rate Limits

This project uses the Github Container Registry to store images, which have no rate limiting on pulls (unlike Docker Hub).

Rapid Building of New Versions

Within 30 minutes of a new release to gunicorn on PyPI builds will kick off for new containers. This means new versions can be used in hours, not days.

Regular Updates

Containers are rebuilt weekly in order to take on the security patches from upstream containers.

How To

Using the Full Image

The Full Images use the base Python Docker images as their parent. These images are based off of Ubuntu and contain a variety of build tools.

To pull the latest full version:

docker pull

To include it in the dockerfile instead:


Using the Slim Image

The Slim Images use the base Python Slim Docker images as their parent. These images are very similar to the Full images, but without the build tools. These images are much smaller than their counter parts but are more difficult to compile wheels on.

To pull the latest slim version:

docker pull

To include it in the dockerfile instead:


Using the Alpine Image

The Alpine Images use the base Python Alpine Docker images as their parent. These images use Alpine as their operating system, with musl instead of glibc.

In theory these images are smaller than even the slim images, but this amounts to less than 30mb difference. Additional Python libraries tend not to be super well tested on Alpine. These images should be used with care and testing until this ecosystem matures.

To pull the latest alpine version:

docker pull

To include it in the dockerfile instead:


Copy Just the Packages

It's also possible to copy just the Python packages themselves. This is particularly useful when you want to use the precompiled libraries from multiple containers.

FROM python:3.11

COPY /usr/local/lib/python3.11/site-packages/* /usr/local/lib/python3.11/site-packages/

Add Your App

By default the startup script checks for the following packages and uses the first one it can find-

  • /app/app/
  • /app/

If you are using pip to install dependencies your dockerfile could look like this-


COPY requirements /requirements
RUN pip install --no-cache-dir -r /requirements
COPY ./app app

PreStart Script

When the container is launched it will run the script at /app/ before starting the gunicorn service. This is an ideal place to put things like database migrations.

Environmental Variables


The port that the application inside of the container will listen on. This is different from the host port that gets mapped to the container.


The number of workers to launch. A good starting point is 4 processes per core (defaults to 4).


The gunicorn log level. Must be one of the following:

  • critical
  • error
  • warning
  • info
  • debug
  • trace


The python module that gunicorn will import. This value is used to generate the APP_MODULE value.


The python variable containing the ASGI application inside of the module that gunicorn imports. This value is used to generate the APP_MODULE value.


The python module and variable that is passed to gunicorn. When used the VARIABLE_NAME and MODULE_NAME environmental variables are ignored.


Where to find the prestart script.


When this is set to the string true gunicorn is launched in reload mode. If any files change gunicorn will reload the modules again, allowing for quick debugging. This comes at a performance cost, however, and should not be enabled on production machines.


This variable can be used to pass extra flags to the gunicorn command on launch. It's value is added directly to the command that is called, and has to be formatted appropriately for the command line.

Python Versions

This project actively supports these Python versions:

  • 3.11
  • 3.10
  • 3.9
  • 3.8
  • 3.7

Image Variants

Like the upstream Python containers themselves a variety of image variants are supported.


The default container type, and if you're not sure what container to use start here. It has a variety of libraries and build tools installed, making it easy to extend.


This container is similar to Full but with far less libraries and tools installed by default. If yo're looking for the tiniest possible image with the most stability this is your best bet.


This container is provided for those who wish to use Alpine. Alpine works a bit differently than the other image types, as it uses musl instead of glibc and many libaries are not well tested under musl at this time.


Every tag in this repository supports these architectures:

  • linux/amd64
  • linux/arm64
  • linux/arm/v7


If you get use out of these containers please consider sponsoring me using Github!

Github Sponsorship


  • Recommended Image:
  • Slim Image:

Tags are based on the package version, python version, and the upstream container the container is based on.

gunicorn Version Python Version Full Container Slim Container Alpine Container
latest 3.11 py3.11-latest py3.11-slim-latest py3.11-alpine-latest
latest 3.10 py3.10-latest py3.10-slim-latest py3.10-alpine-latest
latest 3.9 py3.9-latest py3.9-slim-latest py3.9-alpine-latest
latest 3.8 py3.8-latest py3.8-slim-latest py3.8-alpine-latest
latest 3.7 py3.7-latest py3.7-slim-latest py3.7-alpine-latest
21.2.0 3.11 py3.11-21.2.0 py3.11-slim-21.2.0 py3.11-alpine-21.2.0
21.2.0 3.10 py3.10-21.2.0 py3.10-slim-21.2.0 py3.10-alpine-21.2.0
21.2.0 3.9 py3.9-21.2.0 py3.9-slim-21.2.0 py3.9-alpine-21.2.0
21.2.0 3.8 py3.8-21.2.0 py3.8-slim-21.2.0 py3.8-alpine-21.2.0
21.2.0 3.7 py3.7-21.2.0 py3.7-slim-21.2.0 py3.7-alpine-21.2.0
21.1.0 3.11 py3.11-21.1.0 py3.11-slim-21.1.0 py3.11-alpine-21.1.0
21.1.0 3.10 py3.10-21.1.0 py3.10-slim-21.1.0 py3.10-alpine-21.1.0
21.1.0 3.9 py3.9-21.1.0 py3.9-slim-21.1.0 py3.9-alpine-21.1.0
21.1.0 3.8 py3.8-21.1.0 py3.8-slim-21.1.0 py3.8-alpine-21.1.0
21.1.0 3.7 py3.7-21.1.0 py3.7-slim-21.1.0 py3.7-alpine-21.1.0
21.0.1 3.11 py3.11-21.0.1 py3.11-slim-21.0.1 py3.11-alpine-21.0.1
21.0.1 3.10 py3.10-21.0.1 py3.10-slim-21.0.1 py3.10-alpine-21.0.1
21.0.1 3.9 py3.9-21.0.1 py3.9-slim-21.0.1 py3.9-alpine-21.0.1
21.0.1 3.8 py3.8-21.0.1 py3.8-slim-21.0.1 py3.8-alpine-21.0.1
21.0.1 3.7 py3.7-21.0.1 py3.7-slim-21.0.1 py3.7-alpine-21.0.1
21.0.0 3.11 py3.11-21.0.0 py3.11-slim-21.0.0 py3.11-alpine-21.0.0
21.0.0 3.10 py3.10-21.0.0 py3.10-slim-21.0.0 py3.10-alpine-21.0.0
21.0.0 3.9 py3.9-21.0.0 py3.9-slim-21.0.0 py3.9-alpine-21.0.0
21.0.0 3.8 py3.8-21.0.0 py3.8-slim-21.0.0 py3.8-alpine-21.0.0
21.0.0 3.7 py3.7-21.0.0 py3.7-slim-21.0.0 py3.7-alpine-21.0.0
20.1.0 3.11 py3.11-20.1.0 py3.11-slim-20.1.0 py3.11-alpine-20.1.0
20.1.0 3.10 py3.10-20.1.0 py3.10-slim-20.1.0 py3.10-alpine-20.1.0
20.1.0 3.9 py3.9-20.1.0 py3.9-slim-20.1.0 py3.9-alpine-20.1.0
20.1.0 3.8 py3.8-20.1.0 py3.8-slim-20.1.0 py3.8-alpine-20.1.0
20.1.0 3.7 py3.7-20.1.0 py3.7-slim-20.1.0 py3.7-alpine-20.1.0

Older Tags

Older tags are left for historic purposes but do not receive updates. A full list of tags can be found on the package's registry page.