Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save beezeebly/542e2eb64f38d9cfd2a0938b73b9b4ba to your computer and use it in GitHub Desktop.

Select an option

Save beezeebly/542e2eb64f38d9cfd2a0938b73b9b4ba to your computer and use it in GitHub Desktop.
Complete guide for deploying Django to Azure App Service with static files, WhiteNoise, and CI/CD

πŸš€ Django to Azure App Service - Production Deployment Guide

Complete guide for deploying Django applications to Azure App Service (Linux) with static files, WhiteNoise, Oryx builds, and GitHub Actions CI/CD. Solves common GLIBC compatibility and static file serving issues.

Author's Note: After spending hours debugging GLIBC incompatibilities and static file issues, I created this guide so you don't have to. This approach works with Django 4.x/5.x on Azure App Service.


🎯 Quick Start Prompt for AI Assistants

Use this prompt with Claude, ChatGPT, or other AI assistants to get help deploying Django to Azure:

I need to deploy a Django application to Azure App Service (Linux). Here's my setup:

Current Environment

  • Django Version: [e.g., 5.2]
  • Python Version: [e.g., 3.12]
  • Database: PostgreSQL on Azure / Azure Database for PostgreSQL
  • Cache/Message Broker: Redis on Azure (if applicable)
  • Frontend Build Tool: [e.g., Vite, Webpack, or None]
  • Static Files: [e.g., "Vite builds to static/ directory" or "Standard Django static files"]

Infrastructure Already Provisioned

  • Azure App Service (Linux) - Basic/Standard/Premium tier
  • Azure Database for PostgreSQL Flexible Server
  • Azure Cache for Redis (optional)
  • Application Insights (optional)

Current Project Structure

  • Django settings in: [project_name]/settings.py
  • Requirements file: requirements.txt or pyproject.toml
  • Static files: STATIC_ROOT and STATICFILES_DIRS configured
  • Frontend assets (if any): Built to [directory]

What Needs to Be Done

  1. Set up GitHub Actions CI/CD workflow to deploy to Azure App Service
  2. Configure Azure App Service for Django (startup command, build settings)
  3. Set up WhiteNoise for serving static files in production
  4. Configure Oryx to run collectstatic after building dependencies
  5. Ensure database migrations run automatically on deployment
  6. Build and deploy frontend assets (if applicable)

Key Requirements

  • Use Azure's Oryx build system (no Docker)
  • Fast deployments (avoid rebuilding at every startup)
  • Static files must be served efficiently
  • Production-ready configuration

Known Challenges to Address

  • GLIBC binary compatibility (don't pre-build Python packages in CI)
  • Static file serving (Django doesn't serve static files in production by default)
  • Frontend build integration with Django's collectstatic
  • Oryx post-build configuration

Deployment Strategy

Use the Azure Oryx remote build approach:

  • GitHub Actions builds frontend assets only
  • Azure Oryx builds Python dependencies on the Azure server (correct GLIBC)
  • WhiteNoise serves static files
  • Migrations run automatically via startup command

Please help me:

  1. Create/update GitHub Actions workflow (.github/workflows/azure-deploy.yml)
  2. Configure WhiteNoise middleware in Django settings
  3. Create .oryx-config.yml for post-build steps
  4. Set up Azure App Service startup command
  5. Update requirements.txt with all necessary dependencies

Working directory: [path to your Django project]


πŸ“¦ Required Configuration Files

  1. .oryx-config.yml

Place this in your project root:

Oryx build configuration for Azure App Service

Runs after Python dependencies are installed

version: 1

post-build: | echo "Running Django collectstatic..." python manage.py collectstatic --noinput echo "Oryx build completed successfully!"

  1. .github/workflows/azure-deploy.yml

GitHub Actions workflow for CI/CD:

name: Deploy to Azure App Service

on: push: branches: [ main ] workflow_dispatch:

env: AZURE_WEBAPP_NAME: your-app-name AZURE_RESOURCE_GROUP: your-resource-group

jobs: deploy: runs-on: ubuntu-latest

  steps:
  - uses: actions/checkout@v4

  # Build frontend if you have one (Vite/Webpack/etc)
  - name: Set up Node.js
    uses: actions/setup-node@v4
    with:
      node-version: '20'
      cache: 'npm'

  - name: Build frontend assets
    run: |
      npm ci
      npm run build

  # Create deployment package (source + built frontend)
  - name: Create deployment package
    run: |
      zip -r deploy.zip . \
        -x "*.git*" "*node_modules*" "*.venv*" "*__pycache__*" "*.pyc" \
        "*logs*" "*.terraform*"

  # Deploy to Azure
  - name: Deploy to Azure Web App
    uses: azure/webapps-deploy@v3
    with:
      app-name: ${{ env.AZURE_WEBAPP_NAME }}
      publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }}
      package: deploy.zip

Note: Get AZURE_WEBAPP_PUBLISH_PROFILE from Azure Portal β†’ App Service β†’ Deployment Center β†’ Manage publish profile

  1. Django Settings Updates

Add WhiteNoise to your settings.py:

Add to MIDDLEWARE (right after SecurityMiddleware)

MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'whitenoise.middleware.WhiteNoiseMiddleware', # Add this line 'django.contrib.sessions.middleware.SessionMiddleware', # ... rest of your middleware ]

Update STORAGES configuration (Django 4.2+)

STORAGES = { "default": { "BACKEND": "django.core.files.storage.FileSystemStorage", }, "staticfiles": { "BACKEND": "whitenoise.storage.CompressedManifestStaticFilesStorage", }, }

Static files configuration

STATIC_ROOT = BASE_DIR / "static_root" STATIC_URL = "/static/"

STATICFILES_DIRS = [ BASE_DIR / "static", # Your source static files ]

For Django < 4.2, use: STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'

  1. requirements.txt

Ensure these are included:

Core

django>=4.2 gunicorn>=21.0.0 whitenoise>=6.8.0

Database (choose one)

psycopg2-binary>=2.9.0 # For PostgreSQL

Optional but recommended

django-environ>=0.11.0 # For environment variables

If using Django Channels for WebSockets: daphne>=4.1.0 channels>=4.0.0 channels-redis>=4.0.0


βš™οΈ Azure App Service Configuration

Startup Command

Set in Azure Portal β†’ Configuration β†’ General Settings β†’ Startup Command:

python manage.py migrate --noinput && gunicorn your_project.wsgi:application --bind 0.0.0.0:8000 --workers 4 --threads 2 --timeout 120

Replace your_project with your Django project name (the folder containing wsgi.py).

Application Settings

Add these environment variables in Azure Portal β†’ Configuration β†’ Application Settings:

Setting Value Notes
SECRET_KEY Your Django secret key Never commit this!
DEBUG False Always False in production
ALLOWED_HOSTS your-app.azurewebsites.net Comma-separated if multiple
DATABASE_URL postgres://user:pass@host:5432/db From Azure PostgreSQL
REDIS_URL rediss://... From Azure Redis Cache (if used)
SCM_DO_BUILD_DURING_DEPLOYMENT true Important: Enables Oryx build

Python Version

Set in Azure Portal β†’ Configuration β†’ General Settings:

  • Stack: Python
  • Version: 3.12 (or your Python version)

⚠️ Common Pitfalls & Solutions

Problem 1: GLIBC Compatibility Error

Symptom: ImportError: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.33' not found

Cause: Pre-building Python packages (especially cryptography) in GitHub Actions creates binaries incompatible with Azure's runtime.

Solution:

  • βœ… Let Azure Oryx build Python dependencies on deployment
  • ❌ Don't pre-build virtualenv in GitHub Actions
  • ❌ Don't use WEBSITE_RUN_FROM_PACKAGE=1 with pre-built packages

Problem 2: Static Files Not Loading (404 errors)

Symptom: CSS/JS return 404, page has no styling

Cause: Django doesn't serve static files in production without WhiteNoise

Solutions:

  1. Install WhiteNoise: pip install whitenoise
  2. Add middleware (see configuration above)
  3. Update STORAGES configuration
  4. Ensure .oryx-config.yml runs collectstatic
  5. Verify frontend builds before deployment

Problem 3: Module 'daphne' Not Found

Symptom: ModuleNotFoundError: No module named 'daphne'

Cause: Missing dependency when using Django Channels

Solution: Add to requirements.txt: daphne==4.1.2

Problem 4: App Won't Start After Deployment

Symptoms:

  • HTTP 503 errors
  • "Application Error" page
  • Container fails to start

Debug Steps:

  1. Download logs: az webapp log download --name your-app --resource-group your-rg --log-file logs.zip
  2. Check for errors in: - default_docker.log - Startup errors - docker.log - Build errors
  3. Common causes: - Missing dependencies in requirements.txt - Invalid startup command - Database connection issues - Missing environment variables

πŸ” Verification Checklist

After deployment, verify:


πŸŽ“ How This Works

Deployment Flow

  1. Git Push to main branch ↓
  2. GitHub Actions triggered β”œβ”€ Checkout code β”œβ”€ Build frontend (npm run build β†’ static/) └─ Create deployment.zip (source + built frontend) ↓
  3. Deploy to Azure ↓
  4. Azure App Service receives zip β”œβ”€ Oryx detects Python app β”œβ”€ Creates virtualenv β”œβ”€ Installs from requirements.txt (CORRECT GLIBC) └─ Runs post-build (.oryx-config.yml) └─ collectstatic copies files to static_root/ ↓
  5. App starts β”œβ”€ Runs migrations └─ Starts gunicorn ↓
  6. WhiteNoise serves static files from static_root/

Why This Approach Works

  1. Azure Oryx builds Python packages with correct GLIBC version
  2. WhiteNoise serves static files directly from Django (no separate web server needed)
  3. Frontend built in CI before deployment (fast, consistent)
  4. collectstatic runs once during deployment (not on every startup)
  5. Migrations auto-run via startup command (always up-to-date)

πŸ”— Additional Resources


πŸ’‘ Pro Tips

  1. Use django-environ for environment variables: import environ env = environ.Env() SECRET_KEY = env('SECRET_KEY')
  2. Enable Application Insights for monitoring and debugging
  3. Set up staging slots for testing before production
  4. Use Azure Key Vault for sensitive configuration
  5. Configure custom domain and SSL certificate
  6. Set up automated backups for your database

🀝 Contributing

Found an issue or improvement? This is a living document. Feel free to:

  • Fork and improve
  • Share your experiences in comments
  • Link to this gist in your projects

πŸ“ Version History

  • v1.0 (2025-10-10): Initial release
    • Covers Django 4.x/5.x deployment
    • WhiteNoise configuration
    • GLIBC compatibility solutions
    • GitHub Actions CI/CD

⭐ Star this gist if it helped you!

πŸ› Encountered issues? Leave a comment below with:

  • Django version
  • Python version
  • Error message
  • What you've tried

This guide was created after successfully deploying multiple Django applications to Azure App Service and solving common deployment pitfalls.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment