services:
# Caddy server for reverse proxy
caddy:
image: caddy:latest
ports:
- '80:80' # HTTP port
- '443:443' # HTTPS port
- '443:443/udp' # QUIC port
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile # Mount the Caddyfile for configuration
- caddy_data:/data # Store SSL certificates and Caddy data
- caddy_config:/config # Store Caddy config
- ./static:/var/www/static # Bind static files directory
- ./media:/var/www/media # Bind media files directory
depends_on:
- web
networks:
- web
restart: unless-stopped
# web service
web:
build:
context: .
dockerfile: Dockerfile
env_file:
- .env
ports:
- '${WEB_PORT:-8000}:8000'
volumes:
- ./static:/app/staticfiles
- ./media:/app/media
depends_on:
- db
- redis
networks:
- web
restart: on-failure
# PostgreSQL Database
db:
image: postgres:16
env_file:
- .env # Make sure this .env has DB_NAME, DB_USER, DB_PASSWORD
environment:
- POSTGRES_DB=${DB_NAME}
- POSTGRES_USER=${DB_USER}
- POSTGRES_PASSWORD=${DB_PASSWORD}
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DB_USER} -d ${DB_NAME}"]
interval: 10s
retries: 5
start_period: 30s
timeout: 10s
volumes:
- db_data:/var/lib/postgresql/data
networks:
- web
restart: unless-stopped
# Redis service for message brokering and caching
redis:
image: "redis:alpine"
volumes:
- redis_data:/data
networks:
- web
restart: always
networks:
web:
driver: bridge
volumes:
db_data:
redis_data:
caddy_data:
caddy_config:
example.com {
encode gzip
# Proxy all requests to the Django app
reverse_proxy web:8000
# Serve static files
handle_path /static/* {
root * /var/www/static
file_server
}
# Serve media files
handle_path /media/* {
root * /var/www/media
file_server
}
# Security headers
header {
-Server
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
}
}