Self-hosted service
tiangolo/uwsgi-nginx-docker avatar
tiangolo/uwsgi-nginx-docker

uwsgi-nginx-docker: a deprecated base image and what replaces it

Docker image with uWSGI and Nginx for applications in Python (as Flask) in a single container.

661 stars273 forksPythonApache-2.0

At a glance

What is it?
The tiangolo/uwsgi-nginx Docker image bundles Nginx and uWSGI so a Python web application runs in one container, and the README now opens with a deprecation notice. The maintainer says most people running Kubernetes do not need it, points at a single process Gunicorn image instead, and notes that uWSGI itself is in maintenance mode.
Who is it for?
Adopt uwsgi-nginx only if you are keeping an existing WSGI application running unchanged while you plan a move, because the image still works and the README says as much. Do not adopt it for anything new, since the image is deprecated, uWSGI is in maintenance mode, and the maintainer states plainly that no new Python versions will be supported.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 25 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The README now opens with a deprecation notice

The first line of the README is a DEPRECATED banner, and the text under it says the Docker image is now deprecated. That single word changes what this article is for, and it is worth being direct about it rather than writing a review that pretends the image is a live recommendation.

The image itself is a Docker image with uWSGI and Nginx for web applications in Python, as the README puts it, with Flask as the example, in a single container. The repository description says the same thing. It was created as the base image for tiangolo/uwsgi-nginx-flask, and the README notes it could be used as a base image for any other WSGI-based Python web application, such as Django.

The reason for the deprecation is given in the same document, and it is an architectural argument rather than a bug report. If you have a cluster of machines with Kubernetes, Docker Swarm Mode, Nomad or something similar to manage distributed containers, you should handle replication at the cluster level instead of using a process manager in each container that starts multiple worker processes, which is exactly what this image does.

Two further facts close the case. The README links to the uWSGI documentation stating that uWSGI is now in maintenance mode and that it is probably better to migrate to a different tool. And the maintainer says they have not used the image in years and have little bandwidth to keep it up to date, with most of their time going to FastAPI.

The replacement: one process, and let the cluster scale it

The README does not just say the image is deprecated, it shows you what to do instead. The suggestion for a Kubernetes style deployment is to build a Docker image from scratch, install your dependencies and run a single process.

The example configuration is a Gunicorn config file:

Python
# Gunicorn config variables
loglevel = "info"
errorlog = "-"  # stderr
accesslog = "-"  # stdout
worker_tmp_dir = "/dev/shm"
graceful_timeout = 120
timeout = 120
keepalive = 5
threads = 3

And the Dockerfile that goes with it:

Dockerfile
FROM python:3.12

WORKDIR /code

COPY ./requirements.txt /code/requirements.txt

RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt

COPY ./app /code/app

CMD ["gunicorn", "--conf", "app/gunicorn_conf.py", "--bind", "0.0.0.0:80", "app.main:app"]

Two details in that Dockerfile are worth copying rather than skimming. The requirements are installed with pip install --no-cache-dir, which keeps the image layer free of the pip cache, and the container command runs gunicorn with a config file and a bind address rather than with inline flags, so the settings live in a file you can diff.

The argument is the classic one against process managers in containers: the platform that already schedules and restarts containers should be the thing that scales them, and a container that forks sixteen workers is a container whose resource usage the scheduler cannot reason about. The README points at the FastAPI documentation on containers for the same reasoning applied to other frameworks.

Tags, date pins and the python versions that went away

The supported tags section lists three live tags with a link to each Dockerfile: python3.12 which is also latest, python3.11 and python3.10, each pointing at a file under docker-images in the repository. So the image is built per Python version from a separate Dockerfile rather than from a single one.

Below that, a deprecated tags section lists the versions that are no longer supported or maintained and have been removed from the GitHub repository, with the caveat that the last versions pushed might still be available on Docker Hub if anyone has been pulling them. Those are python3.9, python3.8, python3.8-alpine, python3.7, python3.6 and python2.7, and the README gives the final date tag for each, from python3.9-2025-11-09 down to python2.7-2022-11-25.

That last detail is the operational one to hold on to. A tag like python3.9 still resolves for people who pull it today, and it is a build from November 2025 with whatever Python and system packages that build carried. A deployment that silently starts pulling a different image content than it did last year is the kind of thing that is hard to attribute later.

The README also notes that there are tags for each build date, and that if you need to pin the image version you should select one of those, giving the example tiangolo/uwsgi-nginx:python3.12-2024-11-02. That is the only reproducibility advice in the document, and for a deprecated image it is the advice that matters most: pin by date, not by a moving tag.

Running the old image: UWSGI_INI, WORKDIR and the worker counts

The rest of the README is preserved mainly for historical reasons, and the historical section is the operational documentation for anyone who still has the image in production.

The base usage pattern is a Dockerfile that inherits from the image, installs your requirements and copies your app in:

Dockerfile
FROM tiangolo/uwsgi-nginx:python3.12

COPY ./requirements.txt /app/requirements.txt

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

COPY ./app /app

By default the image looks for a uWSGI config file at /app/uwsgi.ini, and that file makes it run a Python file at /app/main.py. The README also steers Flask users to the separate tiangolo/uwsgi-nginx-flask image rather than this base one.

The advanced section covers the two things people actually change. To use a different application directory, you override the uWSGI config path with the environment variable UWSGI_INI:

Dockerfile
FROM tiangolo/uwsgi-nginx:python3.12

ENV UWSGI_INI /application/uwsgi.ini

COPY ./application /application
WORKDIR /appapplication

and the ini file points at your module:

ini
[uwsgi]
wsgi-file=/application/main.py

The README flags the WORKDIR option as important, because without it uWSGI starts the application in /app.

The other knob is process count. By default the image starts with 2 uWSGI processes and creates up to 16 on demand when the server is under high load. The starting number is controlled by UWSGI_CHEAPER, by default set to 2, and the maximum is controlled by a second environment variable whose name the README section does not finish naming. That truncated line is a good illustration of why the deprecation notice matters.

What is left in the repository

The repository is now small. The top level holds a .github directory with the test and deploy workflows that the badges point at, a .gitignore, LICENSE.txt, the README, a release-notes.md, a docker-images directory holding the per-version Dockerfiles, and a tests directory.

The release history explains the shape of the last few years. The tags are 2.1.0 from 2024-03-18, 2.0.0 from 2022-11-25 and 1.4.0 from 2020-05-09, so the version line moved twice in the 2020s and the last tagged release is more than two years old. The last push to the repository was on 2026-09-28, so the file tree still receives changes even though the image itself is finished.

The licence is Apache-2.0, with the text in LICENSE.txt at the root, which is the permissive licence with the patent grant and the notice requirement.

The Docker Hub page linked from the README, and named as the project homepage in the metadata, is where the published images live, and the badges at the top of the README track both the test workflow and the deploy workflow, so the images are still being built and pushed for the three supported Python versions even though the maintainer has said no new Python versions will be added.

Editorial conclusion

Adopt uwsgi-nginx only if you are keeping an existing WSGI application running unchanged while you plan a move, because the image still works and the README says as much. Do not adopt it for anything new, since the image is deprecated, uWSGI is in maintenance mode, and the maintainer states plainly that no new Python versions will be supported. Verify first which tag you actually pull, since the deprecated python3.9 to python2.7 tags were removed from the repository and the last pushed versions may still sit on Docker Hub, and decide whether to pin by build date tag, as the README suggests, or to rebuild your own image with a single process and the cluster doing the replication.

Frequently asked questions

Is the tiangolo uwsgi-nginx Docker image deprecated?

Yes. The README opens with a deprecation notice and states the image is now deprecated. The maintainer says they have not used it in years, that uWSGI is in maintenance mode, and that no new Python versions will be supported, while suggesting people still use it as is while they migrate.

What should I use instead of the uwsgi-nginx image on Kubernetes?

The README recommends building a Docker image from scratch and running a single process, handling replication at the cluster level instead of running a process manager with multiple workers inside each container. It gives a Gunicorn config example and a Dockerfile based on python:3.12 that installs your requirements and starts gunicorn with that config.

Which tags of the uwsgi-nginx image are still supported?

The supported tags are python3.12, which is also latest, plus python3.11 and python3.10, each built from its own Dockerfile under docker-images. The python3.9 down to python2.7 tags are no longer maintained and were removed from the repository, although the last pushed versions may still be on Docker Hub.

How do I pin the uwsgi-nginx image version?

The README points to the tag list on Docker Hub, where there is a tag for each build date, and gives the example tiangolo/uwsgi-nginx:python3.12-2024-11-02. For a deprecated image, pinning by date rather than by a moving tag is the option that keeps a deployment reproducible.

Official sources

  1. License: Apache-2.0
  2. Project website
  3. README
  4. Releases
  5. tiangolo/uwsgi-nginx-docker on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/tiangolo-uwsgi-nginx-docker.svg)](https://hysenlabs.com/projects/tiangolo-uwsgi-nginx-docker)

Was this useful?