My Dockerfile to build bearblog.
FROM python:3.13-slim AS base
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PIP_NO_CACHE_DIR=1 \
POETRY_VIRTUALENVS_CREATE=false \
PATH="/usr/local/bin:$PATH"
WORKDIR /app
# System deps for psycopg2, Pillow, etc.
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
build-essential \
libpq-dev \
libjpeg62-turbo-dev \
zlib1g-dev \
curl \
&& rm -rf /var/lib/apt/lists/*
# Copy dependency manifests if present; fallback to pip freeze later
COPY conf/settings.py conf/settings.py
COPY architecture.md architecture.md
# Install Python dependencies
# If a requirements.txt is present we'll use it; otherwise install most-likely deps
COPY requirements.txt requirements.txt
RUN --mount=type=cache,target=/root/.cache/pip \
if [ -f requirements.txt ]; then \
pip install -r requirements.txt; \
else \
pip install \
Django==5.2.* \
gunicorn \
dj-database-url \
python-dotenv \
whitenoise \
boto3 \
pillow \
requests \
django-allauth \
tldextract \
pygmentify \
sentry-sdk \
django-debug-toolbar \
geoip2 \
ipaddr \
psycopg2-binary \
; fi
# Copy project
COPY . .
# Create non-root user (optional)
RUN useradd -m appuser && chown -R appuser:appuser /app
USER appuser
ENV PORT=8000 \
DJANGO_SETTINGS_MODULE=conf.settings \
PYTHONPATH=/app
# Expose port
EXPOSE 8000
# Entrypoint handles migrations/collectstatic, then starts gunicorn
ENTRYPOINT ["/app/entrypoint.sh"]