Deploying Django to DigitalOcean App Platform

python backend django devops

Platform-as-a-Service (PaaS) removes the server management burden. DigitalOcean’s App Platform is a solid option for Django apps—simpler than Kubernetes, more flexible than Heroku.

Why App Platform?

Preparing Your Django App

requirements.txt

Django>=3.0,<4.0
gunicorn>=20.0
psycopg2-binary>=2.8
whitenoise>=5.0
dj-database-url>=0.5
python-decouple>=3.3

Settings Updates

# settings.py
from decouple import config
import dj_database_url

# Security
SECRET_KEY = config('SECRET_KEY')
DEBUG = config('DEBUG', default=False, cast=bool)
ALLOWED_HOSTS = config('ALLOWED_HOSTS', default='').split(',')

# Database
DATABASES = {
    'default': dj_database_url.config(
        default=config('DATABASE_URL')
    )
}

# Static files
STATIC_URL = '/static/'
STATIC_ROOT = BASE_DIR / 'staticfiles'
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'

# Middleware
MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'whitenoise.middleware.WhiteNoiseMiddleware',  # Add after SecurityMiddleware
    # ... rest of middleware
]
web: gunicorn myproject.wsgi --log-file -

runtime.txt

python-3.9

Creating a Managed Database

  1. Go to DigitalOcean → Databases
  2. Create a PostgreSQL cluster
  3. Note the connection details

Or let App Platform create one for you (easier).

Deploying to App Platform

1. Create App

From DigitalOcean control panel:

2. Configure Resources

For a typical Django app:

Web Service:

3. Add Database

4. Configure Environment Variables

SECRET_KEY=your-secret-key-here
DEBUG=False
ALLOWED_HOSTS=${APP_DOMAIN}

The DATABASE_URL is automatically injected when you add a database.

5. Deploy

Click “Create Resources” and watch it build.

App Spec (For Reproducibility)

Create .do/app.yaml for version-controlled configuration:

name: myproject
services:
  - name: web
    github:
      repo: username/myproject
      branch: main
    build_command: |
      pip install -r requirements.txt
      python manage.py collectstatic --noinput
      python manage.py migrate
    run_command: gunicorn myproject.wsgi --log-file -
    http_port: 8080
    instance_count: 1
    instance_size_slug: basic-xxs
    envs:
      - key: SECRET_KEY
        scope: RUN_TIME
        value: ${SECRET_KEY}
      - key: DEBUG
        scope: RUN_TIME
        value: "False"
      - key: DJANGO_SETTINGS_MODULE
        scope: RUN_AND_BUILD_TIME
        value: myproject.settings
      - key: DATABASE_URL
        scope: RUN_TIME
        value: ${db.DATABASE_URL}

databases:
  - name: db
    engine: PG
    version: "13"

Deploy with:

doctl apps create --spec .do/app.yaml

Running Migrations

During Deployment

Add to build command:

pip install -r requirements.txt && python manage.py migrate && python manage.py collectstatic --noinput

Via Console

From App Platform:

Custom Domains

  1. App Settings → Domains
  2. Add your domain
  3. Update DNS with provided records
  4. SSL is automatic (Let’s Encrypt)

Scaling

Horizontal Scaling

Increase instance count:

instance_count: 3

Vertical Scaling

Upgrade instance size:

instance_size_slug: professional-xs

Background Workers (Celery)

Add a worker service:

workers:
  - name: celery-worker
    github:
      repo: username/myproject
      branch: main
    build_command: pip install -r requirements.txt
    run_command: celery -A myproject worker -l info
    instance_count: 1
    instance_size_slug: basic-xxs
    envs:
      - key: CELERY_BROKER_URL
        scope: RUN_TIME
        value: ${redis.REDIS_URL}

Add Redis for the broker:

databases:
  - name: redis
    engine: REDIS
    version: "6"

Monitoring and Logs

Logs

App Platform streams logs:

Metrics

Built-in metrics for:

External Monitoring

Add Sentry for error tracking:

# settings.py
import sentry_sdk
from sentry_sdk.integrations.django import DjangoIntegration

sentry_sdk.init(
    dsn=config('SENTRY_DSN'),
    integrations=[DjangoIntegration()],
    traces_sample_rate=0.1,
)

Cost Optimization

Final Thoughts

App Platform hits a sweet spot between Heroku’s simplicity and raw VPS flexibility. For Django projects, it’s a solid choice.

Deploy with GitHub integration. Start with the free tier. Scale when traffic demands it.


Focus on code, not servers.

All posts