Overview
ClassQuiz is fully open-source under the Mozilla Public License 2.0, enabling you to host your own instance with complete control over your data and customization.While official releases are available, the maintainer recommends running the latest commit from the
master branch where CI checks pass, as it contains the most recent bug fixes and improvements.Prerequisites
Required Software
Docker & Docker Compose
Container orchestration for all services
Git
Version control to clone the repository
OpenSSL
For generating secure secret keys
SSL Certificate
HTTPS is required for proper WebSocket functionality
System Requirements
- CPU: 2+ cores recommended
- RAM: 4GB minimum, 8GB+ recommended for production
- Storage: 10GB+ depending on media uploads
- Network: Public IP address or domain name with SSL
Optional Third-Party Services
Email Service (SMTP)
Email Service (SMTP)
Required for user registration and email verification.
- Configure any SMTP server (Gmail, SendGrid, Mailgun, etc.)
- Default: Email verification can be disabled
OAuth Providers
OAuth Providers
Enable single sign-on for users:
- Google OAuth: console.cloud.google.com
- GitHub OAuth: github.com/settings/developers
- Custom OpenID: Any OpenID Connect provider
Captcha Service
Captcha Service
Prevent spam registrations:
- hCaptcha: hcaptcha.com
- reCAPTCHA: google.com/recaptcha
Image Search
Image Search
Enable image search in quiz editor:
- Pixabay API: pixabay.com/api/docs
Error Tracking
Error Tracking
Monitor application errors:
- Sentry: sentry.io
Installation
Configure Frontend Build
Edit
frontend/Dockerfile to set build-time environment variables:Frontend Environment Variables
| Variable | Required | Description |
|---|---|---|
VITE_HCAPTCHA | No | hCaptcha site key for captcha challenges |
VITE_CAPTCHA_ENABLED | No | Set to true to enable captcha on registration |
VITE_GOOGLE_AUTH_ENABLED | No | Set to true to show Google login button |
VITE_GITHUB_AUTH_ENABLED | No | Set to true to show GitHub login button |
VITE_CUSTOM_OAUTH_NAME | No | Display name for custom OpenID provider |
VITE_SENTRY | No | Sentry DSN for frontend error tracking |
Configure Storage Backend
ClassQuiz requires a storage backend for uploaded media files.
- Local Filesystem
- S3-Compatible Storage
Recommended for: Small deployments, single-server setups
docker-compose.yml
Local storage stores files directly on the server filesystem. Ensure the
./uploads directory has appropriate permissions.Configure OAuth (Optional)
Enable third-party authentication for easier user registration.Update
- Google OAuth
- GitHub OAuth
- Custom OpenID
- Visit Google Cloud Console
- Create a new project or select existing
- Navigate to APIs & Services > OAuth consent screen
- Configure consent screen with your application details
- Go to Credentials > Create Credentials > OAuth Client ID
- Set application type to Web application
- Add Authorized JavaScript origins:
- Add Authorized redirect URIs:
- Copy the Client ID and Client Secret
docker-compose.yml:frontend/Dockerfile:Build and Deploy
Build Containers
- frontend: SvelteKit frontend (Node.js)
- api: FastAPI backend (Python)
- worker: ARQ background worker (Python)
Start Services
frontend(port 3000)api(port 80)workerdb(PostgreSQL)redis(cache and queue)meilisearch(search engine)proxy(Caddy reverse proxy on port 8000)
Verify Deployment
The Caddy proxy listens on port 8000 by default. Change this in
docker-compose.yml under the proxy service:Architecture Overview
Services
Tech Stack
Frontend
- SvelteKit: Modern web framework
- TailwindCSS: Utility-first CSS
- Socket.IO: Real-time communication
Backend
- FastAPI: High-performance Python API
- Ormar: Async ORM
- ARQ: Background task queue
Database
- PostgreSQL: Primary database
- Redis: Caching and queues
- Meilisearch: Full-text search
Infrastructure
- Docker: Containerization
- Caddy: Reverse proxy
- S3: Optional object storage
Environment Variables Reference
Database & Cache (Do Not Change)
| Variable | Default | Description |
|---|---|---|
DB_URL | postgresql://postgres:classquiz@db:5432/classquiz | PostgreSQL connection string |
REDIS | redis://redis:6379/0?decode_responses=True | Redis connection string |
MEILISEARCH_URL | http://meilisearch:7700 | Meilisearch endpoint |
MAX_WORKERS | 1 | Worker pool size (keep at 1) |
Required Configuration
| Variable | Required | Description |
|---|---|---|
ROOT_ADDRESS | Yes | Public URL (no trailing slash) |
SECRET_KEY | Yes | 32+ character secret for JWT signing |
STORAGE_BACKEND | Yes | local or s3 |
Email Configuration
| Variable | Required | Description |
|---|---|---|
MAIL_SERVER | Yes | SMTP server hostname |
MAIL_PORT | Yes | SMTP server port (587 for TLS) |
MAIL_USERNAME | Yes | SMTP authentication username |
MAIL_PASSWORD | Yes | SMTP authentication password |
MAIL_ADDRESS | Yes | Sender email address |
SKIP_EMAIL_VERIFICATION | No | Set to True to disable email verification |
Storage Configuration
| Variable | Required | Description |
|---|---|---|
STORAGE_PATH | If STORAGE_BACKEND=local | Absolute path for file storage |
S3_ACCESS_KEY | If STORAGE_BACKEND=s3 | S3 access key |
S3_SECRET_KEY | If STORAGE_BACKEND=s3 | S3 secret key |
S3_BASE_URL | If STORAGE_BACKEND=s3 | S3 endpoint URL |
S3_BUCKET_NAME | No | S3 bucket name (default: classquiz) |
OAuth Configuration
| Variable | Required | Description |
|---|---|---|
GOOGLE_CLIENT_ID | No | Google OAuth client ID |
GOOGLE_CLIENT_SECRET | No | Google OAuth client secret |
GITHUB_CLIENT_ID | No | GitHub OAuth client ID |
GITHUB_CLIENT_SECRET | No | GitHub OAuth client secret |
CUSTOM_OPENID_PROVIDER__CLIENT_ID | No | Custom OIDC client ID |
CUSTOM_OPENID_PROVIDER__CLIENT_SECRET | No | Custom OIDC client secret |
CUSTOM_OPENID_PROVIDER__SERVER_METADATA_URL | No | OIDC discovery URL |
Optional Features
| Variable | Required | Description |
|---|---|---|
HCAPTCHA_KEY | No | hCaptcha secret key |
RECAPTCHA_KEY | No | reCAPTCHA secret key |
PIXABAY_API_KEY | No | Pixabay API key for image search |
SENTRY_DSN | No | Sentry error tracking DSN |
TELEMETRY_ENABLED | No | Enable usage telemetry (default: true) |
FREE_STORAGE_LIMIT | No | Storage quota in bytes (default: 1GB) |
MODS | No | JSON array of moderator emails |
REGISTRATION_DISABLED | No | Disable new registrations |
Maintenance
Updating ClassQuiz
Database Backups
View Logs
Restart Services
Clean Up
Troubleshooting
OAuth Login Fails
OAuth Login Fails
Symptoms: Redirect loops, OAuth errorsSolutions:
- Ensure
ROOT_ADDRESSmatches your public URL exactly (no trailing slash) - Verify redirect URIs in OAuth provider match exactly
- Confirm HTTPS is enabled (OAuth requires secure connections)
- Check that
VITE_GOOGLE_AUTH_ENABLEDorVITE_GITHUB_AUTH_ENABLEDis set infrontend/Dockerfile - Rebuild frontend after environment variable changes:
WebSocket Connection Errors
WebSocket Connection Errors
Symptoms: “Connection refused” in browser console, games don’t startSolutions:
- Ensure reverse proxy forwards
/socket.io/*to the API - Verify WebSocket upgrade headers are set:
- Check that HTTPS is enabled (WebSocket over HTTP fails in production)
- Test WebSocket endpoint:
Email Verification Not Working
Email Verification Not Working
Symptoms: Users don’t receive verification emailsSolutions:
- Verify SMTP credentials in
docker-compose.yml - Check API logs for email errors:
- Ensure firewall allows outbound SMTP (port 587 or 465)
- Test SMTP connection:
- Temporarily disable verification for testing:
File Upload Errors
File Upload Errors
Symptoms: “Storage error” when uploading mediaSolutions:
- Local storage: Check directory permissions
- S3 storage: Verify credentials and bucket access
- Check storage limit:
- Verify allowed MIME types (source:
classquiz/config.py:109):- Images: PNG, JPEG, GIF, WebP
- Videos: MP4
Database Migration Errors
Database Migration Errors
Symptoms: “Table doesn’t exist” errorsSolutions:
- Run migrations manually:
- Check migration status:
- If migrations fail, check database connectivity:
Search Not Working
Search Not Working
Symptoms: Quiz search returns no resultsSolutions:
- Check Meilisearch status:
- Rebuild search index:
- Verify Meilisearch connection:
Security Best Practices
Secret Management
- Generate unique
SECRET_KEYfor each deployment - Never commit secrets to version control
- Rotate secrets periodically
- Use environment files with restricted permissions
Network Security
- Always use HTTPS in production
- Restrict database access to Docker network
- Keep services updated
- Enable fail2ban for brute-force protection
Access Control
- Set up moderators with
MODSvariable - Disable registration if running private instance
- Enable captcha to prevent spam
- Review OAuth scopes carefully
Backups
- Backup database daily
- Store media backups separately
- Test restoration procedures
- Keep backups encrypted
Performance Optimization
Scaling Considerations
- Single Server
- Load Balanced
- Enterprise
Sufficient for most deployments (under 100 concurrent users):
- Use local storage
- Single instance of each service
- PostgreSQL on same host
Resource Limits
Add to services indocker-compose.yml:
Getting Help
Community Support
Join the Matrix Space for community support and discussions
Report Issues
Found a bug? Open an issue on GitHub
Documentation
Check the official docs for more information
Contribute
Want to contribute? See CONTRIBUTING.md
Remember: You must publish any modifications to the source code under the MPL 2.0 license. This protects the open-source nature of ClassQuiz.