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
- Layer caching: Copy dependency files (requirements.txt, package.json, go.mod) before copying the full source. This way, dependencies are only rebuilt when they change.
- Multi-stage builds: Use a builder stage for compiled languages (Go, Rust) to keep the final image small.
- PORT: Always bind to
0.0.0.0:$PORT(notlocalhostor127.0.0.1). The platform setsPORT=8080and routes HTTPS traffic to it. - .dockerignore: Add a
.dockerignorefile to excludenode_modules/,.git/,__pycache__/, and other unnecessary files from the build context.