Skip to main content

Overview

The Wagtail Bakery Demo is designed for easy deployment to Heroku using container-based deployment with heroku.yml. This guide walks you through deploying the application to Heroku from scratch.

Prerequisites

Before deploying to Heroku, ensure you have:
1

Heroku Account

Create a free account at heroku.com if you don’t have one.
2

Heroku CLI

Install the Heroku CLI:
brew tap heroku/brew && brew install heroku
Verify installation:
heroku --version
3

Login to Heroku

Authenticate with your Heroku account:
heroku login
4

Container Registry Login

Enable container deployment:
heroku container:login

Quick Deploy

Deploy the Bakery Demo to Heroku in just a few commands:
# Clone the repository
git clone https://github.com/wagtail/bakerydemo.git
cd bakerydemo

# Create a Heroku app
heroku create your-app-name

# Add PostgreSQL database
heroku addons:create heroku-postgresql:essential-0

# Add Redis (optional but recommended)
heroku addons:create heroku-redis:mini

# Set required environment variables
heroku config:set DJANGO_SECRET_KEY=$(python -c 'from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())')
heroku config:set DJANGO_SETTINGS_MODULE=bakerydemo.settings.production

# Deploy using container stack
heroku stack:set container
git push heroku main

# Open your app
heroku open
The first deployment may take 5-10 minutes as Heroku builds the Docker image and runs migrations.

Heroku Configuration Files

The project includes two configuration files for Heroku deployment:

heroku.yml

The heroku.yml file defines the container-based build and release process:
build:
  docker:
    web:
      dockerfile: Dockerfile
  config:
    NIGHTLY: 0

release:
  image: web
  command:
    - /venv/bin/python manage.py migrate --noinput
Configuration Breakdown:
  • build.docker.web: Specifies the Dockerfile to build the web container
  • build.config.NIGHTLY: Set to 0 for stable Wagtail, 1 for nightly builds
  • release.command: Runs database migrations automatically before each release

Procfile

The Procfile defines process types (legacy support):
release: yes "yes" | python manage.py migrate
web: uwsgi ./etc/uwsgi.ini
When using heroku.yml, the Procfile is primarily for reference. The heroku.yml configuration takes precedence.

Step-by-Step Deployment Guide

1. Create Your Heroku App

Create a new Heroku application:
# Create app with a specific name
heroku create bakery-demo-production

# Or let Heroku generate a name
heroku create

# Set stack to container
heroku stack:set container

2. Add Required Add-ons

Add a PostgreSQL database:
# Essential plan (suitable for production)
heroku addons:create heroku-postgresql:essential-0

# Or mini plan for small projects
heroku addons:create heroku-postgresql:mini
This automatically sets the DATABASE_URL environment variable.

3. Configure Environment Variables

Set required environment variables:
# Generate and set Django secret key
heroku config:set DJANGO_SECRET_KEY=$(python -c 'from django.core.management.utils import get_random_secret_key; print(get_random_secret_key())')

# Set Django settings module
heroku config:set DJANGO_SETTINGS_MODULE=bakerydemo.settings.production

# Set allowed hosts (replace with your domain)
heroku config:set DJANGO_ALLOWED_HOSTS=your-app-name.herokuapp.com

# Set primary host for admin emails
heroku config:set PRIMARY_HOST=your-app-name.herokuapp.com

# Ensure debug is off
heroku config:set DJANGO_DEBUG=off
Never commit your DJANGO_SECRET_KEY to version control. Always generate it securely and set it via environment variables.

4. Deploy Your Application

Push your code to Heroku:
# Deploy main branch
git push heroku main

# Or deploy a different branch
git push heroku your-branch:main
The deployment process:
  1. Build Phase: Heroku builds the Docker image from the Dockerfile
  2. Release Phase: Runs python manage.py migrate --noinput
  3. Deploy Phase: Starts the web dyno with uWSGI

5. Post-Deployment Tasks

After deployment, complete these tasks:
1

Create Superuser

Create an admin user to access the Wagtail admin:
heroku run python manage.py createsuperuser
Follow the prompts to set username, email, and password.
2

Load Demo Data (Optional)

Load the bakery demo content:
heroku run python manage.py load_initial_data
Or enable automatic loading on deployment:
heroku config:set DJANGO_LOAD_INITIAL_DATA=on
3

Verify Deployment

Open your application:
heroku open
Access the admin at: https://your-app-name.herokuapp.com/admin/

Advanced Configuration

Custom Domain Setup

Add a custom domain to your Heroku app:
1

Add Domain to Heroku

heroku domains:add www.yourdomain.com
heroku domains:add yourdomain.com
2

Get DNS Target

heroku domains
Note the DNS target provided by Heroku.
3

Update DNS Records

Add CNAME or ALIAS records with your DNS provider:
www.yourdomain.com  CNAME  your-dns-target.herokudns.com
yourdomain.com      ALIAS  your-dns-target.herokudns.com
4

Enable Automatic SSL

Heroku automatically provisions SSL certificates:
heroku certs:auto:enable
5

Update Django Settings

Update allowed hosts:
heroku config:set DJANGO_ALLOWED_HOSTS=yourdomain.com,www.yourdomain.com
heroku config:set PRIMARY_HOST=yourdomain.com

AWS S3 for Media Storage

Configure AWS S3 for storing user uploads:
# Set AWS credentials
heroku config:set AWS_ACCESS_KEY_ID=your-access-key-id
heroku config:set AWS_SECRET_ACCESS_KEY=your-secret-access-key
heroku config:set AWS_STORAGE_BUCKET_NAME=your-bucket-name
heroku config:set AWS_S3_REGION_NAME=us-east-1

# Optional: Custom domain for S3
heroku config:set AWS_S3_CUSTOM_DOMAIN=cdn.yourdomain.com
Using S3 is highly recommended for production deployments to persist media files across dyno restarts.

Elasticsearch Search Backend

Add Elasticsearch for enhanced search:
# Using Bonsai Elasticsearch add-on
heroku addons:create bonsai:sandbox-10

# Get Elasticsearch URL
heroku config:get BONSAI_URL

# Set environment variables
heroku config:set ELASTICSEARCH_ENDPOINT=your-elasticsearch-host
heroku config:set ELASTICSEARCH_PORT=9200
heroku config:set ELASTICSEARCH_USE_SSL=on
heroku config:set ELASTICSEARCH_VERIFY_CERTS=on

Cloudflare CDN Integration

Enable cache purging for Cloudflare:
heroku config:set FRONTEND_CACHE_CLOUDFLARE_ZONEID=your-zone-id
heroku config:set FRONTEND_CACHE_CLOUDFLARE_BEARER_TOKEN=your-api-token

Scaling Your Application

Dyno Scaling

Scale your web dynos based on traffic:
# Scale to 2 web dynos
heroku ps:scale web=2

# Scale up to Standard-1X dyno type
heroku ps:type web=standard-1x

# View current dyno status
heroku ps
Dyno Types:
TypeRAMPriceUse Case
Eco512MB$5/moDevelopment/staging
Basic512MB$7/moLow-traffic sites
Standard-1X512MB$25/moProduction sites
Standard-2X1GB$50/moHigh-traffic sites
Performance2.5GB+$250+/moEnterprise applications

Database Scaling

Upgrade your PostgreSQL plan:
# View current plan
heroku pg:info

# Upgrade to Standard-0
heroku addons:upgrade heroku-postgresql:standard-0

# View database metrics
heroku pg:diagnose

Monitoring and Logs

View Application Logs

# Tail logs in real-time
heroku logs --tail

# View last 500 lines
heroku logs -n 500

# Filter by source
heroku logs --source app --tail

Application Metrics

View application metrics:
# View application metrics in browser
heroku open --metrics

# Or visit dashboard
heroku dashboard

Database Monitoring

# Database diagnostics
heroku pg:diagnose

# Connection info
heroku pg:info

# Long-running queries
heroku pg:ps

# Database backups
heroku pg:backups:capture
heroku pg:backups:download

Maintenance and Updates

Deploy Updates

# Pull latest changes
git pull origin main

# Deploy to Heroku
git push heroku main

# Monitor deployment
heroku logs --tail

Run Management Commands

# Access Django shell
heroku run python manage.py shell

# Run custom management commands
heroku run python manage.py update_index

# Create cache table
heroku run python manage.py createcachetable

Database Backups

# Create manual backup
heroku pg:backups:capture

# Schedule automatic backups (included in Standard plans and above)
heroku pg:backups:schedule DATABASE_URL --at '02:00 America/Los_Angeles'

# List backups
heroku pg:backups

# Download backup
heroku pg:backups:download

# Restore from backup
heroku pg:backups:restore b001 DATABASE_URL
Always test your backup restoration process in a staging environment before relying on it in production.

Troubleshooting

Error: “Application crashed” or “H10 error”Solutions:
  1. Check application logs:
    heroku logs --tail
    
  2. Verify environment variables:
    heroku config
    
  3. Check dyno status:
    heroku ps
    
  4. Restart dynos:
    heroku restart
    
Error: “Could not connect to database”Solutions:
  1. Verify DATABASE_URL is set:
    heroku config:get DATABASE_URL
    
  2. Check database status:
    heroku pg:info
    
  3. Run migrations:
    heroku run python manage.py migrate
    
Error: 404 errors for CSS/JS filesSolutions:Static files are handled by WhiteNoise. Ensure:
  1. WhiteNoise is in MIDDLEWARE (automatically configured in production.py)
  2. Collectstatic runs during build (automatically handled in Dockerfile)
Manually collect static files:
heroku run python manage.py collectstatic --noinput
Issue: Application responds slowlySolutions:
  1. Scale up dyno type:
    heroku ps:type web=standard-2x
    
  2. Add more dynos:
    heroku ps:scale web=2
    
  3. Ensure Redis is configured for caching
  4. Upgrade database plan:
    heroku addons:upgrade heroku-postgresql:standard-0
    
  5. Check slow queries:
    heroku pg:ps
    
Error: “Memory quota exceeded”Solutions:
  1. Upgrade to larger dyno:
    heroku ps:type web=standard-2x
    
  2. Reduce worker threads in uwsgi.ini (edit locally and redeploy)
  3. Monitor memory usage:
    heroku logs --tail | grep "Memory"
    

Cost Optimization

Minimal Production (~$20/month):
# Eco dynos (can sleep)
heroku ps:type web=eco
heroku ps:scale web=1

# Essential PostgreSQL
heroku addons:create heroku-postgresql:essential-0

# Mini Redis
heroku addons:create heroku-redis:mini
Standard Production (~$75/month):
# Standard dynos (no sleeping)
heroku ps:type web=standard-1x
heroku ps:scale web=2

# Standard PostgreSQL
heroku addons:upgrade heroku-postgresql:standard-0

# Premium Redis with persistence
heroku addons:upgrade heroku-redis:premium-0
Eco dynos sleep after 30 minutes of inactivity. Use Basic or Standard dynos for production sites that need 24/7 availability.

Next Steps

Production Settings

Deep dive into production configuration

Docker Deployment

Alternative deployment with Docker

Environment Variables

Learn about configuration options

Deployment Overview

Explore other deployment options

Build docs developers (and LLMs) love