BookWyrm + Caddy: Static Files Fix
Caddy is proxying directly to Gunicorn, which doesn't serve static files. It returns HTML for every /static/ request, and the browser blocks it due to MIME type mismatch.
The fix is to add a small nginx container between Caddy and Gunicorn. nginx serves /static/ and /images/ straight from the Docker volumes, and passes everything else to Gunicorn.
1. Add the nginx config
Create nginx-books/nginx.conf next to your docker-compose.yml:
upstream bookwyrm {
server bookwyrm-web:8000;
}
server {
listen 80;
client_max_body_size 10M;
location /static/ {
alias /app/static/;
}
location /images/ {
alias /app/images/;
}
location / {
proxy_pass http://bookwyrm;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto https;
proxy_redirect off;
}
}
2. Add the nginx service to docker-compose.yml
bookwyrm-nginx:
image: nginx:alpine
restart: unless-stopped
depends_on:
- bookwyrm-web
volumes:
- ./nginx-books/nginx.conf:/etc/nginx/conf.d/default.conf:ro
- bookwyrm_static:/app/static:ro
- bookwyrm_media:/app/images:ro
Make sure it's on the same Docker network as your other BookWyrm containers.
3. Update Caddy to point at nginx, not Gunicorn
books.yourdomain.com {
reverse_proxy bookwyrm-nginx:80
}
Instead of bookwyrm-web:8000.
4. Restart everything
docker compose up -d
If Caddy seems to be ignoring the new config, caddy reload doesn't always apply changes. Do a full restart instead:
docker compose up -d --force-recreate caddy
One gotcha: celery-beat needs EMAIL_HOST
BookWyrm's settings require EMAIL_HOST even for containers that never send email (like celery-beat). Pass the full email env block to all BookWyrm containers or beat will crash on startup.