This repository contains the complete infrastructure configuration for the Revel project, including all services, observability stack, and reverse proxy setup.
This repository contains the infrastructure and deployment configurations for Revel. The complete platform consists of:
- revel-backend - Django REST API, business logic, database models
- revel-frontend - SvelteKit web application, user interface
- infra (this repository) - Docker Compose setup, reverse proxy, observability stack, deployment configurations
This is a consolidated Docker Compose setup that includes:
- Web - Django application (Gunicorn + Uvicorn workers)
- Frontend - Next.js/SvelteKit frontend application
- Celery Workers - Background task processing (default queue)
- Beat - Celery scheduler for periodic tasks
- Flower - Celery monitoring UI
- Telegram Bot - Telegram bot service
- Caddy - Reverse proxy with automatic HTTPS
- PostgreSQL (PostGIS) - Primary database
- PgBouncer - Connection pooler for PostgreSQL
- Redis - Cache and message broker
- Grafana - Metrics and logs visualization
- Prometheus - Metrics collection
- Loki - Log aggregation
- Tempo - Distributed tracing
- Pyroscope - Continuous profiling
- Alloy - eBPF-based profiling collector
- postgres-exporter - PostgreSQL metrics exporter
- ClamAV - Antivirus scanning for uploaded files
-
Clone the repository
cd /path/to/revel/infra -
Create environment file
cp .env.example .env # Edit .env with your actual configuration -
Start all services
docker compose up -d
-
Check service status
docker compose ps
-
View logs
docker compose logs -f [service_name]
All configuration is done through the .env file. See .env.example for all available options.
Key variables to configure:
- Database credentials (
DB_*) - Django secret key (
SECRET_KEY) - Google SSO for Flower (
GOOGLE_SSO_*) - Grafana admin credentials (
GRAFANA_ADMIN_*) - Pushover notifications (
PUSHOVER_USER_KEY,PUSHOVER_APP_TOKEN)
The Caddyfile is configured for the following domains:
beta.letsrevel.io- Frontend applicationbeta-api.letsrevel.io- Backend APIflower.letsrevel.io- Celery monitoringgrafana.letsrevel.io- Grafana dashboard
Update the Caddyfile if you need to change domains or add new ones.
.
├── docker-compose.yml # Main compose file
├── Caddyfile # Reverse proxy configuration
├── .env # Environment variables (create from .env.example)
├── .env.example # Environment variables template
├── observability/ # Observability stack configurations
│ ├── alloy-config.alloy
│ ├── grafana-datasources.yaml
│ ├── loki-config.yaml
│ ├── prometheus-config.yml
│ └── tempo-config.yaml
├── media/ # User-uploaded media files
├── geo-data/ # Geographic data files
├── sentinel/ # LLM sentinel data
└── certs/ # Apple Wallet certificates (optional)
The application supports generating Apple Wallet passes for event tickets. This requires Apple Developer certificates to be placed in the certs/ directory.
certs/
├── pass_certificate.pem # Apple Pass Type ID certificate
├── pass_key.pem # Private key for the certificate
└── wwdr.pem # Apple Worldwide Developer Relations certificateIMPORTANT: All certificate files must be readable by the Docker container (which runs as non-root user appuser):
chmod 644 /path/to/revel/infra/certs/pass_certificate.pem
chmod 644 /path/to/revel/infra/certs/pass_key.pem
chmod 644 /path/to/revel/infra/certs/wwdr.pemWhy 644 for all files (including the private key)?
644(rw-r--r--): Owner can read/write, others can read- The Docker container runs as
appuser(non-root), which needs read access to mounted files - While
600would be ideal for private keys in traditional setups, Docker volume mounts require readable permissions when the container user differs from the host file owner - The files are only accessible within the server's filesystem (not exposed externally)
If you see errors like PermissionError: [Errno 13] Permission denied: '/app/certs/pass_certificate.pem', verify the file permissions are set correctly.
The following Docker volumes are created for persistent data:
caddy_data- Caddy data (SSL certificates)caddy_config- Caddy configuration cacherevel_postgres_data- PostgreSQL databaseredis_data- Redis persistenceloki_data- Log storagetempo_data- Trace storageprometheus_data- Metrics storagepyroscope_data- Profiling dataalloy_data- Alloy configurationgrafana_data- Grafana dashboards and settings
All services run on a dedicated bridge network called revel_network.
Revel is deployed on a Hetzner CCX33 instance:
- CPU: 8 vCPU
- RAM: 32 GB
- Disk: 240 GB
- Set up your server with Docker and Docker Compose
- Clone this repository
- Configure your
.envfile - Ensure DNS records point to your server:
- beta.letsrevel.io
- beta-api.letsrevel.io
- flower.letsrevel.io
- grafana.letsrevel.io
- Start services:
docker compose up -d - Caddy will automatically provision SSL certificates
To update a service to the latest image:
docker compose pull [service_name]
docker compose up -d [service_name]To update all services:
./deploy.sh updateIMPORTANT: The Revel frontend uses SvelteKit with streaming Server-Side Rendering (SSR). Improper Caddy configuration will cause pages to hang indefinitely with "eternal loading" states.
The Caddyfile MUST NOT buffer responses. Buffering breaks SvelteKit's streaming SSR.
❌ WRONG - DO NOT USE:
beta.letsrevel.io {
reverse_proxy revel_frontend:3000 {
flush_interval -1 # ❌ Buffers entire response - BREAKS SVELTEKIT!
}
}✅ CORRECT - Streaming enabled:
beta.letsrevel.io {
encode zstd gzip
reverse_proxy revel_frontend:3000 {
# No flush_interval = streaming enabled by default ✅
transport http {
keepalive 90s
keepalive_idle_conns 32
max_conns_per_host 100
}
}
}With flush_interval -1 (buffering enabled):
- ❌ Caddy holds the ENTIRE HTML response in memory
- ❌ Browser receives nothing until SSR fully completes
- ❌ Pages appear to "hang" or show eternal loading spinner
- ❌ Poor user experience, especially on slow connections
- ❌ Potential timeout issues on large pages
Without buffering (default):
- ✅ Caddy streams HTML as SvelteKit generates it
- ✅ Browser receives and renders content progressively
- ✅ Faster perceived load times (better TTFB)
- ✅ Better user experience
- ✅ Support for large pages without timeouts
If you experience these issues, check the Caddyfile for response buffering:
- Pages show eternal loading spinner
- Network tab shows request pending for many seconds
- HTML arrives all at once after a long delay
- Time-to-first-byte (TTFB) equals total response time
# Test response timing - should see progressive delivery
curl -w "\nTTFB: %{time_starttransfer}s\nTotal: %{time_total}s\n" \
-o /dev/null \
"https://beta.letsrevel.io/events"
# Good: TTFB and Total are close (streaming)
# Bad: TTFB ≈ Total time (buffering!)See the Caddyfile in this repository for the correct production configuration. All reverse_proxy blocks for the frontend must not include flush_interval -1.
Access monitoring tools:
- Grafana: https://grafana.letsrevel.io
- Flower (Celery): https://flower.letsrevel.io
- Prometheus (metrics): Available internally at
revel_prometheus:9090
docker compose exec revel_postgres pg_dump -U $DB_USER $DB_NAME > backup.sqlView logs for a specific service:
docker compose logs -f [service_name]View all logs:
docker compose logs -fTo scale up celery workers:
docker compose up -d --scale celery_default=4If you see errors like:
PermissionError: [Errno 13] Permission denied: '/app/certs/pass_certificate.pem'
Fix the certificate file permissions:
chmod 644 /path/to/revel/infra/certs/*.pemVerify permissions are correct:
ls -la /path/to/revel/infra/certs/All files should show -rw-r--r-- (644 permissions).
docker compose psdocker compose restart [service_name]docker compose down -v- Change all default passwords in
.env - Never commit
.envto version control - Regularly update Docker images
- Monitor Grafana for security alerts
- Review Pushover alert notifications
This consolidated setup differs from the previous multi-repo setup:
- All services are in a single
docker-compose.yml - Uses a dedicated
revel_networkinstead of an externalsharednetwork - Includes Redis directly (was previously in shared services)
- Simplified volume management
- All observability services are included
- Comprehensive alerting via Prometheus and Pushover
See LICENSE file in the repository root.