Deploy Django on Bahriya
Django is a batteries-included Python web framework. In production you run it behind a WSGI server rather than the development server — gunicorn is the usual choice, listening on port 8000. This guide packages a Django project as a container image and deploys it as an HTTP container.
Django is a batteries-included Python web framework. In production you run it behind a WSGI server rather than the development server — gunicorn is the usual choice, listening on port 8000. This guide packages a Django project as a container image and deploys it as an HTTP container.
Only two things change between stacks on Bahriya: the Dockerfile that builds your image, and the port your application listens on. For Django served by gunicorn, that port is 8000.
Dockerfile
This builds on the slim Python base image, installs your requirements, collects static files, and starts gunicorn bound to 0.0.0.0:8000 so the platform can reach it.
FROM python:3.12-slim
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1
WORKDIR /app
# Install dependencies first so they cache across builds
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy the project
COPY . .
# Collect static assets at build time
RUN python manage.py collectstatic --noinput
EXPOSE 8000
# Replace "myproject" with your project's WSGI module
CMD ["gunicorn", "myproject.wsgi:application", "--bind", "0.0.0.0:8000", "--workers", "3"]Make sure gunicorn is listed in your requirements.txt. Django logs to standard output by default, which is what the platform captures.
Application settings
A few settings need attention before you deploy:
ALLOWED_HOSTS— add your container's hostname. Your default hostname follows the pattern<handle>.<region>.x.on.bahriya.app, and you can allow all of them with a suffix entry such as.on.bahriya.app, plus any custom domain you configure.collectstatic— the Dockerfile above runs it at build time so your static files ship inside the image. SetSTATIC_ROOTin your settings accordingly.DEBUG— set it toFalsein production, driven by an environment variable.
Deploy from the Console
- Create (or open) a project, then create a container.
- Set the image to your pushed image reference, and the port to
8000. - Set a health check path the app answers with a 2xx — a lightweight view such as
/healthzworks well. - Choose your regions, set CPU and memory, and attach any secrets.
- Create the container and wait for it to reach a running state.
See Deploy your first container for the full walkthrough.
Deploy with the Reis CLI
reis container:create \
--type http \
--name "Django App" \
--handle django-app \
--image ghcr.io/myorg/django-app:v1.0.0 \
--project my-project \
--port 8000 \
--healthcheck /healthz \
--cpu 500 \
--memory 512 \
--regions falkenstein-1 \
--env DJANGO_SETTINGS_MODULE=myproject.settings \
--secrets SECRET_KEY=django-secret-key \
--secrets DATABASE_URL=database-urlSee Deploy an HTTP container with flags for the full flag reference.
Configuration, secrets, and databases
- Non-sensitive configuration — pass values such as
DJANGO_SETTINGS_MODULEor feature flags as plain environment variables. - Sensitive values — your
SECRET_KEY, database password, and any API keys belong in secrets. They are encrypted at rest and injected as environment variables at runtime. Read them insettings.pywithos.environ. - Database connections — point Django at your managed database using a connection URL or discrete host/user/password values, supplied through secrets. Bahriya does not host your database; connect to whichever database you run.
Running migrations
Run python manage.py migrate as a one-off before or after a deploy rather than inside your web process. Bahriya supports init jobs — short-lived containers that run to completion — which are a natural fit for migrations. They use the same image as your web container with a different command (python manage.py migrate). See HTTP containers for how container types relate.
Next steps
- Deploy your first container — the end-to-end walkthrough.
- Environment variables — plain config versus secrets.
- Secrets — encrypted values injected at runtime.
- HTTP containers — hostnames, autoscaling, and init jobs.