Self-Hosting
Since ClassQuiz is open-source, it can also be self-hosted.
Warning
Although some versions are already released, I would recommend to run the latest commit (where checks pass) from the master-branch.
Requirements
Software
3rd-Parties
Required
Optional
Installation
At first, clone the repo:
git clone https://github.com/mawoka-myblock/classquiz && cd ClassQuiz
Now, you'll configure your frontend. You'll have to change the following in frontend/Dockerfile
:
VITE_MAPBOX_ACCESS_TOKEN
: A Mapbox-token which is optional.VITE_HCAPTCHA
: The hCaptcha-Siteky for captchasVITE_CAPTCHA_ENABLED
: Set it totrue
, if the captcha should be availableVITE_SENTRY
: A Sentry-DSN for Sentry (optional)VITE_GOOGLE_AUTH_ENABLED
: Set it totrue
, if Google-Auth is set up. Otherwise, leave it unset.VITE_GITHUB_AUTH_ENABLED
: Set it totrue
, if GitHub-Auth is set up. Otherwise, leave it unset.
Configuration
Storage Provider
You'll have to set up a storage provider for some pictures (these getting imported from
KAHOOT!). For now, you can use Deta or the local filesystem.
Please note that I would NOT use the local file system because of
Path Traversals. I tried to
prevent these attacks, but I really wouldn't trust it, because it's a regex! You'll have to
set the
STORAGE_BACKEND
-environment-variable to either deta
or
local
.
If you chose Deta...
...you'll also have to set the DETA_PROJECT_KEY
and the
DETA_PROJECT_ID
.
If you chose the local filesystem...
...you'll have to set the STORAGE_PATH
environment variable. The path must be
absolute (so start with a /
).
Before you can start your stack, you have to set some environment-variables in your
docker-compose.yml
.
GitHub/Google-Auth
This step is purely optional, but it will enable users to log in using their Google/GitHub-accounts.
First, go to console.cloud.google.com/apis/dashboard and create a new project and select it. Then, go to the "OAuth consent screen" and set it up. Next, go to the "Credentials"-tab and click on "Create Credentials" and create a new "OAuth Client ID". This ID should be from the application-type "Web application". Afterwards, add a new "Authorised JavaScript origin", which is just the base-domain (with https) of your ClassQuiz-installation. Then, add a new "Authorised redirect URI". This URI will have the following scheme:
https://[BASE_URL]/api/v1/users/oauth/google/auth
You're done! Not the client-secret and the client-id down, you'll need it later.
GitHub
First, go to github.com/settings/developers and create a "new OAuth App". The "Authorization callback URL" has the following schema:
https://[BASE_URL]/api/v1/users/oauth/github/auth
That's it. Click on "Register application" and generate a new client secret and save it for later, together with your client-id.
Docker-Compose File
version: "3"
services:
frontend:
restart: always
build:
context: ./frontend
dockerfile: Dockerfile
depends_on:
- redis
- api
environment:
REDIS_URL: redis://redis:6379/0?decode_responses=True # don't change
API_URL: http://api:80 # don't change
api:
build:
context: .
dockerfile: Dockerfile
restart: always
depends_on:
- db
- redis
environment:
ROOT_ADDRESS: "https://classquiz.de" # Base-URL (change it)
DB_URL: "postgresql://postgres:classquiz@db:5432/classquiz" # don't change
MAIL_ADDRESS: "classquiz@mawoka.eu" # Email-Address (change it)
MAIL_PASSWORD: "MAIL_PASSWORD" # Email-Password (change it)
MAIL_USERNAME: "classquiz@mawoka.eu" # Email-Username (change it)
MAIL_SERVER: "smtp.gmail.com" # SMTP-Server (change it)
MAIL_PORT: "587" # SMTP-Port
SKIP_EMAIL_VERIFICATION: True # Set this to skip sending emails
MAX_WORKERS: "1" # Very important and don't change it!
REDIS: "redis://redis:6379/0?decode_responses=True" # don't change
SECRET_KEY: "TOP_SECRET" # openssl rand -hex 32
MEILISEARCH_URL: "http://meilisearch:7700" # don't change
ACCESS_TOKEN_EXPIRE_MINUTES: 30 # don't change
HCAPTCHA_KEY: "" # Private hCaptcha key for verification (change it)
STORAGE_BACKEND: "deta" # MUST BE EITHER "deta" OR "local"
# If STORAGE_BACKEND is "deta"
DETA_PROJECT_KEY: "YOUR_DETA_PROJECT_KEY"
DETA_PROJECT_ID: "YOUR_DETA_PROJECT_ID"
# If STORAGE_BACKEND is "local"
STORAGE_PATH: "/var/storage"
# GOOGLE_AUTH
GOOGLE_CLIENT_ID: # Your Google-Client ID, or leave it unset if you don't want it.
GOOGLE_CLIENT_SECRET: # Your Google-Client Secret, or leave it unset if you don't want it.
# GITHUB_AUTH
GITHUB_CLIENT_ID: # Your GitHub-Client ID, or leave it unset if you don't want it.
GITHUB_CLIENT_SECRET: # Your GitHub-Client Secret, or leave it unset if you don't want it.
redis:
image: redis:alpine
restart: always
healthcheck:
test: [ "CMD", "redis-cli","ping" ]
db:
image: postgres:14-alpine
restart: always
healthcheck:
test: [ "CMD-SHELL", "pg_isready -U postgres" ]
interval: 5s
timeout: 5s
retries: 5
environment:
POSTGRES_PASSWORD: "classquiz"
POSTGRES_DB: "classquiz"
volumes:
- data:/var/lib/postgresql/data
proxy:
image: caddy:alpine
restart: always
volumes:
- ./Caddyfile-docker:/etc/caddy/Caddyfile
ports:
- "8000:8080" # Adjust the 8000 to your needs
meilisearch:
image: getmeili/meilisearch:latest
restart: always
environment:
MEILI_NO_ANALYTICS: true
volumes:
- meilisearch-data:/data.ms
volumes:
data:
meilisearch-data:
Run the following command to generate and set the secret up automatically
sed -i "s/TOP_SECRET/$(openssl rand -hex 32)/g" docker-compose.yml
Now build and deploy:
docker compose build && docker compose up -d
ClassQuiz needs HTTPS/SSL to work properly!
Enjoy! ❤️