Dockerfile Templates

Ready-to-copy Dockerfiles for common runtimes. Place the Dockerfile in your repo root (or in the root_dir you configured).

Important: Your app must listen on the port specified by the PORT environment variable. Bind to 0.0.0.0:$PORT. All templates below are configured for this.

Python (Flask / FastAPI)

With requirements.txt

FROM python:3.12-slim

WORKDIR /app

# Install dependencies first for better layer caching
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

EXPOSE $PORT

# Flask
CMD gunicorn --bind 0.0.0.0:$PORT app:app

# FastAPI (uncomment and replace the line above)
# CMD uvicorn main:app --host 0.0.0.0 --port $PORT

With pyproject.toml

FROM python:3.12-slim

WORKDIR /app

COPY pyproject.toml .
RUN pip install --no-cache-dir .

COPY . .

EXPOSE $PORT
CMD gunicorn --bind 0.0.0.0:$PORT app:app

Django

FROM python:3.12-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

# Collect static files at build time
RUN python manage.py collectstatic --noinput

EXPOSE $PORT
CMD gunicorn --bind 0.0.0.0:$PORT myproject.wsgi:application

Node.js

Express / Fastify

FROM node:22-slim

WORKDIR /app

# Install dependencies first for better layer caching
COPY package*.json ./
RUN npm ci --omit=dev

COPY . .

EXPOSE $PORT
CMD ["npm", "start"]

npm ci requires a package-lock.json. Run npm install locally first to generate it.

Make sure your app listens on process.env.PORT:

// server.js
const port = process.env.PORT || 8080;
app.listen(port, '0.0.0.0');

Next.js

FROM node:22-slim AS builder

WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:22-slim
WORKDIR /app
COPY --from=builder /app/.next .next
COPY --from=builder /app/node_modules node_modules
COPY --from=builder /app/package.json .
COPY --from=builder /app/public public

EXPOSE $PORT
ENV PORT=8080
CMD ["npm", "start"]

Go

FROM golang:1.23 AS builder

WORKDIR /app
COPY go.* ./
RUN go mod download

COPY . .
RUN CGO_ENABLED=0 go build -o server .

FROM alpine:3.21

COPY --from=builder /app/server /server

EXPOSE $PORT
CMD ["/server"]

Make sure your Go app reads the port from the PORT environment variable:

port := os.Getenv("PORT")
if port == "" {
    port = "8080"
}
http.ListenAndServe(":"+port, router)

Static Site / WASM

For static files, single-page apps, or WASM games. Uses nginx to serve files with SPA fallback routing.

FROM nginx:alpine

# Copy your static files
COPY . /usr/share/nginx/html

# nginx config template — $PORT is substituted at container start
RUN printf 'server {\n\
    listen ${PORT};\n\
    root /usr/share/nginx/html;\n\
    index index.html;\n\
    location / {\n\
        try_files $uri $uri/ /index.html;\n\
    }\n\
}\n' > /etc/nginx/conf.d/default.conf.template

EXPOSE $PORT
ENV PORT=8080
CMD ["/bin/sh", "-c", "envsubst '${PORT}' < /etc/nginx/conf.d/default.conf.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'"]

Monorepo tip: If your static files are in a subdirectory (e.g. game/), set root_dir to that directory using configure_app. You can run multiple apps from the same repo — one for your API, one for your static site.

Rust

FROM rust:1.83 AS builder

WORKDIR /app
COPY Cargo.toml Cargo.lock ./
# Cache dependency build
RUN mkdir src && echo "fn main() {}" > src/main.rs && cargo build --release && rm -rf src

COPY . .
RUN cargo build --release

FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y ca-certificates && rm -rf /var/lib/apt/lists/*

COPY --from=builder /app/target/release/app /app

EXPOSE $PORT
CMD ["/app"]

Tips