This comprehensive guide will walk you through deploying your Python web application to Azure App Service.
Table of Contents
- Pre-Deployment Preparation
- Azure Setup
- Framework-Specific Deployment
- Database Configuration
- Advanced Configuration
- CI/CD Pipeline
- Monitoring and Scaling
- Security Best Practices
- Troubleshooting
Pre-Deployment Preparation
1. Application Readiness Checklist
Before deploying, ensure your application is production-ready:
- Requirements file:
requirements.txt
orpyproject.toml
with all dependencies - Environment variables: Use
.env
for development but prepare for Azure configuration - Static files: Configured for your framework (Django:
collectstatic
, Flask: typicallystatic
folder) - Database: Local DB for development, but prepared for cloud DB connection
- Logging: Proper logging configuration
- WSGI/ASGI: Entry point configured (
application
object for WSGI, appropriate ASGI setup)
2. Local Testing
- Test with production settings locally
- Run linters and tests
- Check for hardcoded values that should be environment variables
Azure Setup
1. Prerequisites
- Azure account (free tier available)
- Azure CLI installed (
az
command) - Python 3.7+ (matching your target version)
2. Resource Group Creation
az group create --name myPythonAppResourceGroup --location eastus
3. App Service Plan
Choose based on your needs:
# Free tier (not recommended for production)
az appservice plan create --name myPythonAppPlan --resource-group myPythonAppResourceGroup --sku FREE --is-linux
# Production tier (B1 is the smallest production tier)
az appservice plan create --name myPythonAppPlan --resource-group myPythonAppResourceGroup --sku B1 --is-linux
4. Web App Creation
az webapp create --resource-group myPythonAppResourceGroup \
--plan myPythonAppPlan \
--name myPythonApp \
--runtime "PYTHON|3.9" \
--deployment-local-git
Note: Replace "3.9" with your Python version (3.7, 3.8, 3.9, 3.10 supported as of 2023)
Framework-Specific Deployment
Django Deployment
1. Configuration Adjustments
- Update
settings.py
:
DEBUG = os.getenv('DEBUG', 'False') == 'True'
ALLOWED_HOSTS = [os.getenv('WEBSITE_HOSTNAME', 'localhost')]
SECRET_KEY = os.getenv('SECRET_KEY') # Ensure this is set in Azure config
2. Static Files Configuration
- Install WhiteNoise for static files:pip install whitenoise
- Update
settings.py
:
MIDDLEWARE = [
# ...
'whitenoise.middleware.WhiteNoiseMiddleware',
# ...
]
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
3. Deployment File Structure
Create .production/
folder with:
startup.sh
(make it executable:chmod +x startup.sh
)
#!/bin/bash
# Collect static files
echo "Collect static files"
python manage.py collectstatic --noinput
# Apply database migrations
echo "Apply database migrations"
python manage.py migrate
# Start server
echo "Starting server"
gunicorn --bind 0.0.0.0:8000 --workers 4 myproject.wsgi:application
4. Azure Configuration
az webapp config set --resource-group myPythonAppResourceGroup \
--name myPythonApp \
--startup-file ".production/startup.sh"
Flask Deployment
1. Application Factory Pattern (Recommended)
# app/__init__.py
from flask import Flask
from .config import Config
def create_app(config_class=Config):
app = Flask(__name__)
app.config.from_object(config_class)
# Initialize extensions
from .extensions import db, migrate
db.init_app(app)
migrate.init_app(app, db)
# Register blueprints
from .main import bp as main_bp
app.register_blueprint(main_bp)
return app
2. WSGI Entry Point
Create wsgi.py
:
from app import create_app
application = create_app()
3. Deployment Configuration
.production/startup.sh
:
#!/bin/bash
# Start server
gunicorn --bind 0.0.0.0:8000 --workers 4 wsgi:application
4. Azure Configuration
Same as Django configuration above.
FastAPI Deployment
1. ASGI Configuration
- Install requirements:
pip install fastapi uvicorn[standard]
2. Deployment Options
Option 1: Gunicorn with Uvicorn workers
.production/startup.sh
:
#!/bin/bash gunicorn -k uvicorn.workers.UvicornWorker -w 4 -b 0.0.0.0:8000 main:app
Option 2: Pure Uvicorn (for smaller apps)
.production/startup.sh
:
#!/bin/bash
gunicorn -k uvicorn.workers.UvicornWorker -w 4 -b 0.0.0.0:8000 main:app
3. Azure Configuration
Same as previous frameworks.
Database Configuration
1. Azure Database for PostgreSQL (Recommended for Django)
az postgres server create --resource-group myPythonAppResourceGroup \
--name mypythonpostgres \
--location eastus \
--admin-user myadmin \
--admin-password ComplexPassword123! \
--sku-name B_Gen5_1 \
--version 11
2. Connection String Configuration
For Django:
az webapp config appsettings set --resource-group myPythonAppResourceGroup \
--name myPythonApp \
--settings DJANGO_DB_HOST="mypythonpostgres.postgres.database.azure.com" \
DJANGO_DB_NAME="postgres" \
DJANGO_DB_USER="myadmin@mypythonpostgres" \
DJANGO_DB_PASSWORD="ComplexPassword123!"
For Flask/FastAPI with SQLAlchemy:
az webapp config appsettings set --resource-group myPythonAppResourceGroup \
--name myPythonApp \
--settings DATABASE_URL="postgresql://myadmin@mypythonpostgres:ComplexPassword123!@mypythonpostgres.postgres.database.azure.com/postgres?sslmode=require"
3. Database SSL Configuration
Most Azure databases require SSL. For Django:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.getenv('DJANGO_DB_NAME'),
'USER': os.getenv('DJANGO_DB_USER'),
'PASSWORD': os.getenv('DJANGO_DB_PASSWORD'),
'HOST': os.getenv('DJANGO_DB_HOST'),
'PORT': '5432',
'OPTIONS': {
'sslmode': 'require',
},
}
}
Advanced Configuration
1. Custom Domain Setup
- Purchase domain in Azure or bring your own
- Add DNS records
- Configure in App Service:
az webapp config hostname add --webapp-name myPythonApp \
--resource-group myPythonAppResourceGroup \
--hostname www.yourdomain.com
2. SSL/TLS Configuration
az webapp config ssl bind --resource-group myPythonAppResourceGroup \
--name myPythonApp \
--certificate-thumbprint [THUMBPRINT] \
--ssl-type SNI
3. Deployment Slots
# Create staging slot
az webapp deployment slot create --name myPythonApp \
--resource-group myPythonAppResourceGroup \
--slot staging
# Swap slots
az webapp deployment slot swap --name myPythonApp \
--resource-group myPythonAppResourceGroup \
--slot staging
4. Environment-Specific Settings
Use slot settings for different environments:
az webapp config appsettings set --resource-group myPythonAppResourceGroup \
--name myPythonApp \
--slot staging \
--settings ENVIRONMENT="staging"
CI/CD Pipeline
1. GitHub Actions
Create .github/workflows/azure-deploy.yml
:
name: Deploy Python app to Azure
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.9'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Run tests
run: |
python manage.py test
- name: 'Deploy to Azure'
uses: azure/webapps-deploy@v2
with:
app-name: 'myPythonApp'
slot-name: 'production'
publish-profile: ${{ secrets.AZURE_PUBLISH_PROFILE }}
2. Azure DevOps Pipeline
trigger:
- main
pool:
vmImage: 'ubuntu-latest'
variables:
python.version: '3.9'
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: '$(python.version)'
- script: |
python -m pip install --upgrade pip
pip install -r requirements.txt
displayName: 'Install dependencies'
- script: |
python manage.py test
displayName: 'Run tests'
- task: AzureWebApp@1
inputs:
azureSubscription: 'your-azure-subscription'
appName: 'myPythonApp'
slotName: 'production'
package: $(System.DefaultWorkingDirectory)
Monitoring and Scaling
1. Application Insights
az monitor app-insights component create --app myPythonAppInsights \
--location eastus \
--resource-group myPythonAppResourceGroup \
--application-type web
# Connect to your web app
az webapp config appsettings set --resource-group myPythonAppResourceGroup \
--name myPythonApp \
--settings APPLICATION_INSIGHTS_KEY="your-instrumentation-key" \
APPINSIGHTS_INSTRUMENTATIONKEY="your-instrumentation-key"
2. Auto-scaling
# Create autoscale rule
az monitor autoscale create --resource-group myPythonAppResourceGroup \
--resource myPythonAppPlan \
--resource-type Microsoft.Web/serverfarms \
--name myPythonAppAutoscale \
--min-count 1 \
--max-count 5 \
--count 1
# Add scale condition
az monitor autoscale rule create --resource-group myPythonAppResourceGroup \
--autoscale-name myPythonAppAutoscale \
--condition "CpuPercentage > 70 avg 5m" \
--scale out 2
3. Log Streaming
az webapp log tail --resource-group myPythonAppResourceGroup --name myPythonApp
Security Best Practices
1. Environment Variables
Never commit secrets. Configure in Azure:
az webapp config appsettings set --resource-group myPythonAppResourceGroup \
--name myPythonApp \
--settings SECRET_KEY="your-secret-key-here"
2. Managed Identity for Database Access
# Enable managed identity
az webapp identity assign --resource-group myPythonAppResourceGroup \
--name myPythonApp
# Grant database access
az postgres server ad-admin create --resource-group myPythonAppResourceGroup \
--server-name mypythonpostgres \
--display-name myPythonApp \
--object-id $(az webapp identity show --resource-group myPythonAppResourceGroup --name myPythonApp --query principalId -o tsv)
3. Network Security
- Configure VNET integration
- Set up IP restrictions
- Enable private endpoints for databases
Troubleshooting
Common Issues and Solutions
- Application Not Starting
- Check logs:
az webapp log tail
- Verify startup file is executable
- Check Python version matches runtime
- Check logs:
- Static Files Not Loading
- Verify WhiteNoise configuration
- Check
STATIC_ROOT
setting - Run
collectstatic
manually if needed
- Database Connection Issues
- Verify connection string
- Check firewall rules
- Ensure SSL is properly configured
- Memory Errors
- Reduce Gunicorn worker count
- Upgrade App Service plan
- Implement worker timeouts
- Deployment Failures
- Check
.deployment
anddeploy.cmd
files - Verify all dependencies are in
requirements.txt
- Check for Python version conflicts
- Check
Diagnostic Tools
- Kudu Console: Access via
https://<app-name>.scm.azurewebsites.net
- SSH Access: az webapp ssh --resource-group myPythonAppResourceGroup --name myPythonApp
- Application Logs: az webapp log download --resource-group myPythonAppResourceGroup --name myPythonApp
Final Checklist Before Production
- All environment variables configured in Azure
- Database properly migrated and backed up
- Static files collected and configured
- Proper logging setup
- Monitoring configured (Application Insights)
- Backup strategy in place
- Security review completed
- Performance testing conducted
- Deployment rollback plan prepared
- DNS and SSL properly configured
By following this comprehensive guide, you should have a robust Python application running on Azure App Service with all the necessary production-grade configurations. Remember to monitor your application regularly and adjust scaling rules as your traffic patterns evolve.