Use a Docker image to package your Python web app, its pinned dependencies, configuration interface and runtime into one reproducible unit. A practical path is to copy the dependency file first, install it in a trusted Python base image, copy the source, bind the server to 0.0.0.0, and publish the container port to your host. For production, build dependencies in a separate stage, run as a non-root user, inject secrets at runtime and expose a health check.
Antihost offers VPS plans with one-click Docker, NVMe storage and a 14-day free trial.
The walkthrough below uses a small FastAPI application and port 8000. Replace the module name, framework command and port with the values used by your project.
As an Amazon Associate I earn from qualifying purchases.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
What containerizing a Python app actually does
A container image combines your application code with its Python runtime, installed packages and the configuration interface the process expects. Starting that image creates an isolated process with the same filesystem and dependency set on a developer laptop, a CI runner or a production host. The host still supplies the kernel and hardware, but the application no longer depends on an accidentally different virtual environment.
Docker does not automatically make an application production-ready. The Dockerfile determines what is inside the image; the run command or Compose file supplies ports, environment variables, volumes and resource limits. A good design keeps build tools and secrets out of the runtime image and makes the process observable and stoppable.
#1 Best Overall
Prepare the project before writing the Dockerfile
Keep the build inputs together
Place the application source, a pinned dependency definition and the Docker assets in one project directory. You can use requirements.txt, pyproject.toml with a lock file, or an equivalent package-manager format. Pinning versions makes a rebuild resolve the same dependency set instead of silently pulling a newer release.
my-python-app/
├── app.py
├── requirements.txt
├── Dockerfile
├── compose.yaml
└── .dockerignore
A minimal FastAPI example might contain this application and dependency file:
# app.py
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def root():
return {"status": "ok"}
@app.get("/health")
def health():
return {"healthy": True}
# requirements.txt
fastapi==0.115.0
uvicorn[standard]==0.30.6
The exact versions are illustrative. Use versions that your application supports and commit the resulting lock or requirements file.
Exclude files that should never enter the build context
Docker sends the build context (the directory represented by the final dot in docker build ... .) to the builder. A .dockerignore prevents local environments, caches, version-control metadata, test output and secrets from being sent or copied.
.git
.gitignore
.venv/
venv/
__pycache__/
*.py[cod]
.pytest_cache/
.mypy_cache/
.coverage
.env
.env.*
tests/
dist/
build/
Do not rely on .dockerignore as a secret-management system. If a secret was copied into an image layer, removing it in a later layer does not erase it from the image history. Keep credentials outside the image and provide them when the container starts.
Build a first image for local development
Choose and record a base image
Start from a trusted Python image appropriate for the application and record its tag. A slim variant usually contains fewer operating-system packages than a full image, but packages with native extensions may require additional build tools. Keep the tag explicit so two developers do not unknowingly build against different Python releases.
Copy dependencies before source code
Docker reuses completed layers. Dependency files change less often than application code, so copy and install them before copying the rest of the source. A source edit can then reuse the expensive package-install layer. BuildKit can also cache package downloads between builds.
Rank #2
# syntax=docker/dockerfile:1
FROM python:3.12-slim
ENV PYTHONDONTWRITEBYTECODE=1
PYTHONUNBUFFERED=1
WORKDIR /app
COPY requirements.txt .
RUN --mount=type=cache,target=/root/.cache/pip
python -m pip install --upgrade pip
&& python -m pip install -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["python", "-m", "uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]
WORKDIR makes subsequent paths relative to /app. EXPOSE documents the port; it does not publish that port by itself. The JSON (exec) form of CMD starts Uvicorn directly, allowing Docker to deliver stop and terminate signals to the server process.
Build and run it
- From the directory containing the Dockerfile, build an image:
docker build -t my-python-app .
- Start a disposable container and map host port 8000 to container port 8000:
docker run --rm -p 8000:8000 my-python-app
- Open
http://localhost:8000or request the health endpoint:
curl http://localhost:8000/health
The mapping syntax is host-port:container-port. The process must listen on the container interface, commonly 0.0.0.0; listening only on 127.0.0.1 inside the container makes it unreachable through the published port.
Adapt the runtime command to your framework
FastAPI and other ASGI applications
Uvicorn is a direct ASGI server option. The module path in app:app means “import the app object from app.py.” If your file is src/main.py and the object is named api, use a matching import path such as src.main:api and ensure the package is copied into the image.
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →CMD ["python", "-m", "uvicorn", "src.main:api", "--host", "0.0.0.0", "--port", "8000"]
Development reload is useful when a source directory is mounted into the container, but it watches files and is not a production process model. Keep reload tooling in a development target rather than the minimal runtime image.
Flask and other WSGI applications
A WSGI application can be served by Gunicorn. If app.py defines a Flask object named app, an exec-form command is:
CMD ["gunicorn", "app:app", "--bind", "0.0.0.0:8000"]
Gunicorn’s worker count should be sized against the CPU and memory limits assigned to the container. More workers are not automatically faster: each worker consumes memory, and an oversize value can cause contention or restarts. Select the command that matches the framework and the deployment architecture instead of placing both Uvicorn and Gunicorn in the same image command.
Use a multi-stage Dockerfile for production
A single-stage build can leave compilers, downloaded archives and packaging tools in the final image. A multi-stage build creates wheels in a builder stage and copies only those wheels into a clean runtime stage. This separates build concerns, reduces the runtime image and removes unnecessary attack surface. The Python version below is an example; align it with your application’s support policy.
Windows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallOutdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchRank #3
# syntax=docker/dockerfile:1
FROM python:3.12-slim AS builder
WORKDIR /build
COPY requirements.txt .
RUN python -m pip install --upgrade pip
&& pip wheel --no-cache-dir --wheel-dir /wheels -r requirements.txt
FROM python:3.12-slim AS runtime
WORKDIR /app
COPY --from=builder /wheels /wheels
RUN python -m pip install --no-cache-dir /wheels/*
&& rm -rf /wheels
COPY . .
EXPOSE 8000
CMD ["gunicorn", "app:app", "--bind", "0.0.0.0:8000"]
The builder’s pip wheel command turns the pinned requirements into installable wheel files. The runtime stage receives those files, installs them without retaining pip’s download cache, then deletes the temporary wheel directory. If a dependency needs a system library at runtime, install that library in the runtime stage; build-only compilers belong in the builder stage.
Run the production process as a non-root user
Processes in a container should not need root privileges. Create an application user, copy files with the correct ownership and switch users before the command runs:
FROM python:3.12-slim AS runtime
WORKDIR /app
RUN useradd --create-home --shell /usr/sbin/nologin appuser
COPY --from=builder /wheels /wheels
RUN python -m pip install --no-cache-dir /wheels/*
&& rm -rf /wheels
COPY --chown=appuser:appuser . .
USER appuser
EXPOSE 8000
CMD ["gunicorn", "app:app", "--bind", "0.0.0.0:8000"]
Check that the application writes only to directories the user can access. If it needs uploads, logs or a cache, mount a volume or provide a writable path deliberately rather than making the whole filesystem writable.
Configure secrets, ports and health checks at runtime
Keep configuration outside the image
Use environment variables or your platform’s secret manager for database URLs, signing keys and API credentials. Do not put values in ENV instructions, source files or committed Compose files. A local run can receive a variable explicitly:
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Scan for outdated or missing drivers - takes under a minute3Repair Windows errors before they cause bigger problemsdocker run --rm
-p 8000:8000
-e DATABASE_URL="$DATABASE_URL"
-e APP_ENV=production
my-python-app
Keep non-sensitive defaults in application configuration, but make production values explicit in the deployment environment. Gunicorn settings such as bind address and worker count can likewise be driven by environment-aware startup configuration when the platform needs different limits.
Add an application endpoint and a container health check
A health endpoint should answer quickly and avoid performing an expensive full business transaction. The /health route above is suitable for a basic process check. Add a Docker health check when your platform uses Docker’s health status for restart or routing decisions. The following form uses Python from the image and therefore does not require a separate curl binary:
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3
CMD ["python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/health', timeout=3)"]
Place the instruction after the application and its dependencies are installed. If your health check must verify a database or another dependency, define that contract carefully; failing a liveness check because a temporary downstream service is unavailable can cause unnecessary restarts.
Rank #4
- This dive logbook is made from genuine cowhide leather, and just like fingerprints, each piece is one-of-a-kind. Each logbook flaunts its own unique personality with varying colors, textures, and markings. Over time, the leather develops its own charming "battle scars," making it even more beautiful and uniquely yours. It's like your favorite pair of jeans – the more you use it, the cooler it gets
- Its compact A6 size (5.1in x 7.5in) makes it super easy to carry around, letting you jot down your dive logs anytime, anywhere. Whether you toss it in your dive bag or take it on the go, it’s a breeze to bring along. Perfectly suited for A6 dive logs and A6 binders. Think of it as your trusty sidekick – always ready for the next adventure
- This dive logbook isn't just a pretty face – it's got some serious chops too. The genuine leather cover laughs in the face of splashes, and the 120g high-quality paper ensures your notes won't dissolve into a soggy mess. Perfect for those damp and drizzly dives
- 3 Card Slots: Perfect for stashing your dive cards, transit passes, and other important cards. 1 Zipper Pocket: Keep your valuables secure and safe. 4 Receipt Pockets: Perfect for holding tickets, passports, and other essential documents We’ve included 2 removable, expandable PVC pages: Transparent PVC Page: Holds up to 3 cards, making them easy to see and use. PVC Storage Bag: Specially designed waterproof bag for those items that just hate getting wet.
- Our dive logbook includes all the essential fields for divers to record every dive, such as date, dive site, conditions, equipment, dive stats, and dive verification, among others. With 50 pages designed to capture the key details of each dive adventure, it's perfect for PADI divers and fits the A6 size dive log requirements
Use Compose for a repeatable local stack
Compose describes services, ports, environment variables, named volumes and resource limits in one file. It is useful when the web process needs a database or another local dependency. Keep live-reload shells and debugging tools in a development stage, while production deployments use the minimal runtime stage.
Free tools Windows power users keep installed
One-click scans. No signup required.
services:
web:
build:
context: .
target: builder
command: python -m uvicorn app:app --host 0.0.0.0 --port 8000 --reload
ports:
- "8000:8000"
environment:
APP_ENV: development
DATABASE_URL: postgresql://app:app@db:5432/app
volumes:
- .:/app
depends_on:
- db
deploy:
resources:
limits:
cpus: "1.0"
memory: 512M
db:
image: postgres:16
environment:
POSTGRES_DB: app
POSTGRES_USER: app
POSTGRES_PASSWORD: change-me-for-local-use
volumes:
- db-data:/var/lib/postgresql/data
volumes:
db-data:
The database image and credentials in this file are local-development examples. Use your organization’s approved database image and a secret mechanism for shared or production environments. A named volume preserves database data when the database container is recreated. The bind mount on web makes source edits visible for reload; omit it for a production-style immutable container.
Build and start the stack with:
docker compose up --build
Stop the services while retaining the named volume with docker compose down. Remove the volume only when you intentionally want to delete the local database data.
Choose between common approaches
| Decision | Option | Use it when | Trade-off |
|---|---|---|---|
| Image construction | Single stage | Quick experiments or a simple development image | Build tools and package artifacts can remain in the runtime image |
| Image construction | Multi-stage | Production images and applications with compiled dependencies | More Dockerfile structure, but a smaller and cleaner runtime |
| ASGI runtime | Uvicorn directly | FastAPI or another ASGI app where the platform supplies process management | Worker management is outside the command unless you add it |
| WSGI/runtime management | Gunicorn | Flask or another WSGI app, or deployments needing managed workers | Worker count must be tuned to assigned CPU and memory |
| Local orchestration | docker run |
One container and a simple port mapping | Ports, variables and supporting services are specified manually |
| Local orchestration | Compose | Web app plus database, volumes, environment and resource settings | An extra configuration file and service lifecycle to maintain |
Security and reliability checks before publishing an image
- Base image: Use a trusted, small Python image and update it under your project’s patching policy. Record the selected tag.
- Dependencies: Pin versions and rebuild when security fixes are released. Keep the dependency file ahead of source-copy instructions for cache reuse.
- Build separation: Use a builder and runtime stage so compilers and download artifacts do not ship to production.
- Privileges: Create an unprivileged application user and verify that every required directory is readable or writable by that user.
- Secrets: Pass credentials at runtime through environment variables or a secret manager; never bake them into layers.
- Signals: Use JSON/exec-form
CMDso the server receives container stop signals directly. - Health: Provide a lightweight endpoint and configure a health check when the hosting platform uses it.
- Context: Keep virtual environments, caches, VCS metadata, local environment files and test artifacts out of the build context.
- Resources: Set CPU and memory limits where your orchestrator supports them, then size Gunicorn workers within those limits.
Troubleshoot the failures that appear most often
The container starts, but the browser cannot connect
- Confirm the server command uses
--host 0.0.0.0or Gunicorn’s--bind 0.0.0.0:8000. - Confirm the run command publishes the same container port declared by the server, for example
-p 8000:8000. - Check logs with
docker logs <container-name>and verify that the process did not exit during import.
Changes to requirements do not appear
Changing only application source can legitimately reuse the dependency layer. After editing the dependency file, rebuild; if you suspect an invalid cached layer, use docker build --no-cache -t my-python-app .. Keep the dependency copy before COPY . . so normal source edits remain fast.
The process reports “module not found”
Check the module path in the command, the package layout inside /app and whether the required file is excluded by .dockerignore. A command such as app:app requires an app.py file and an object named app.
Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →A package fails while building
Some Python packages compile native extensions. Add the required compiler or operating-system headers only in the builder stage, then copy the resulting wheels into the runtime stage. If the package also needs a shared library when the application runs, install that runtime library in the second stage.
The application cannot write files
After switching to USER appuser, inspect ownership of application directories and mounted volumes. Copy files with --chown and mount a specifically writable data directory instead of reverting the entire container to root.
Make builds reproducible in CI and deployment
- Commit the Dockerfile, dependency lock or requirements file and
.dockerignore. - Build from a clean checkout so untracked local files cannot affect the image.
- Tag the image with an immutable release identifier in addition to any human-friendly tag.
- Run the container with the same port, environment contract and health endpoint expected in deployment.
- Scan and update the base image and dependencies according to your security process.
- Promote the built image rather than rebuilding separately in each environment; supply environment-specific configuration at runtime.
This workflow preserves the main advantages of containers: identical dependency resolution, explicit runtime behavior and a clear boundary between the packaged application and the environment that operates it.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




