✨ Closes #327
This commit is contained in:
@@ -11,6 +11,8 @@ repos:
|
|||||||
- id: trailing-whitespace
|
- id: trailing-whitespace
|
||||||
- id: end-of-file-fixer
|
- id: end-of-file-fixer
|
||||||
- id: check-yaml
|
- id: check-yaml
|
||||||
|
args:
|
||||||
|
- --allow-multiple-documents
|
||||||
# - id: check-added-large-files
|
# - id: check-added-large-files
|
||||||
|
|
||||||
- repo: https://github.com/psf/black
|
- repo: https://github.com/psf/black
|
||||||
|
|||||||
+43
-12
@@ -26,21 +26,52 @@ services:
|
|||||||
- redis
|
- redis
|
||||||
|
|
||||||
environment: &env_vars
|
environment: &env_vars
|
||||||
DB_URL: "postgresql://postgres:classquiz@db:5432/classquiz"
|
# --- DON'T CHANGE FROM HERE ---
|
||||||
REDIS: "redis://redis:6379/0?decode_responses=True"
|
DB_URL: "postgresql://postgres:classquiz@db:5432/classquiz" # DON'T CHANGE
|
||||||
|
REDIS: "redis://redis:6379/0?decode_responses=True" # DON'T CHANGE
|
||||||
|
SECRET_KEY: "TOP_SECRET" # Don't change it manually, use the one-liner provided in the documentation
|
||||||
|
MAX_WORKERS: "1" # Very important and DON'T CHANGE
|
||||||
|
ACCESS_TOKEN_EXPIRE_MINUTES: 30 # DON'T CHANGE
|
||||||
|
MEILISEARCH_URL: "http://meilisearch:7700" # DON'T CHANGE
|
||||||
|
# -- DON'T CHANGE TILL HERE ---
|
||||||
|
|
||||||
|
# --- MAIL CONFIG ---
|
||||||
|
MAIL_PORT: "587"
|
||||||
MAIL_ADDRESS: "email@email@email.email"
|
MAIL_ADDRESS: "email@email@email.email"
|
||||||
MAIL_PASSWORD: "PASSWORT"
|
MAIL_PASSWORD: "PASSWORT"
|
||||||
MAIL_USERNAME: "email@email@email.email"
|
MAIL_USERNAME: "email@email@email.email"
|
||||||
MAIL_SERVER: "email@email@email.emai"
|
MAIL_SERVER: "email@email@email.emai"
|
||||||
MAX_WORKERS: "1" # Very important
|
SKIP_EMAIL_VERIFICATION: "True" # Does the user have to confirm its email by clicking a link?
|
||||||
MAIL_PORT: "587"
|
|
||||||
SECRET_KEY: "mysecretkey"
|
# --- EXTERNAL API CONFIG ---
|
||||||
ACCESS_TOKEN_EXPIRE_MINUTES: 30
|
# HCAPTCHA_KEY: "HCAPTCHA_PRIVATE_KEY"
|
||||||
SKIP_EMAIL_VERIFICATION: True
|
# PIXABAY_API_KEY: "" # Get it from here: https://pixabay.com/api/docs/
|
||||||
HCAPTCHA_KEY: "HCAPTCHA_PRIVATE_KEY"
|
# RECAPTCHA_KEY: "" Get it from Google for the Captcha.
|
||||||
MEILISEARCH_URL: "http://meilisearch:7700"
|
|
||||||
STORAGE_BACKEND: "local"
|
# -- STORAGE CONFIG ---
|
||||||
STORAGE_PATH: "/app/data"
|
STORAGE_BACKEND: "local" # Could also be s3
|
||||||
|
STORAGE_PATH: "/app/data" # When s3 is used, this isn't needed.
|
||||||
|
# If STORAGE_BACKEND is "s3"
|
||||||
|
#S3_ACCESS_KEY: "YOUR_ACCESS_KEY"
|
||||||
|
#S3_SECRET_KEY: "YOUR_SECRET_KEY"
|
||||||
|
#S3_BASE_URL: "YOUR_S3_BASE_URL"
|
||||||
|
|
||||||
|
# --- 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.
|
||||||
|
|
||||||
|
# --- Custom OpenID ---
|
||||||
|
#CUSTOM_OPENID_PROVIDER__CLIENT_ID: "" # Adjust if needed
|
||||||
|
#CUSTOM_OPENID_PROVIDER__CLIENT_SECRET: "" # Adjust if needed
|
||||||
|
#CUSTOM_OPENID_PROVIDER__SERVER_METADATA_URL: "/.well-known/openid-configuration" # Adjust if needed
|
||||||
|
|
||||||
|
volumes: # Only needed if you chose the "local" storage-backend
|
||||||
|
- ./uploads:/var/storage
|
||||||
|
|
||||||
redis:
|
redis:
|
||||||
image: redis:alpine
|
image: redis:alpine
|
||||||
restart: always
|
restart: always
|
||||||
@@ -66,7 +97,7 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- ./Caddyfile-docker:/etc/caddy/Caddyfile
|
- ./Caddyfile-docker:/etc/caddy/Caddyfile
|
||||||
ports:
|
ports:
|
||||||
- "8000:8080"
|
- "8000:8080" # The 8000 can be changed.
|
||||||
meilisearch:
|
meilisearch:
|
||||||
image: getmeili/meilisearch:v0.28.0
|
image: getmeili/meilisearch:v0.28.0
|
||||||
restart: always
|
restart: always
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ SPDX-FileCopyrightText: 2023 Marlon W (Mawoka)
|
|||||||
|
|
||||||
SPDX-License-Identifier: MPL-2.0
|
SPDX-License-Identifier: MPL-2.0
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang='ts'>
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import '$lib/hljs.css';
|
import '$lib/hljs.css';
|
||||||
|
|
||||||
@@ -16,12 +16,12 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
<svelte:head>
|
<svelte:head>
|
||||||
<title>ClassQuiz/docs - Self-Host</title>
|
<title>ClassQuiz/docs - Self-Host</title>
|
||||||
<meta
|
<meta
|
||||||
name="description"
|
name='description'
|
||||||
content="How to self-host ClassQuiz, the open-source quiz-application"
|
content='How to self-host ClassQuiz, the open-source quiz-application'
|
||||||
/>
|
/>
|
||||||
</svelte:head>
|
</svelte:head>
|
||||||
<article
|
<article
|
||||||
class="prose prose-sm sm:prose lg:prose-lg xl:prose-xl mx-auto mt-10 prose-slate px-4 dark:prose-invert"
|
class='prose prose-sm sm:prose lg:prose-lg xl:prose-xl mx-auto mt-10 prose-slate px-4 dark:prose-invert'
|
||||||
>
|
>
|
||||||
<h1>Self-Hosting</h1>
|
<h1>Self-Hosting</h1>
|
||||||
<p>Since ClassQuiz is open-source, it can also be self-hosted.</p>
|
<p>Since ClassQuiz is open-source, it can also be self-hosted.</p>
|
||||||
@@ -36,43 +36,43 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
<h3>Software</h3>
|
<h3>Software</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<a href="https://docker.com" target="_blank">Docker</a> (<a
|
<a href='https://docker.com' target='_blank'>Docker</a> (<a
|
||||||
href="https://docs.docker.com/compose/install/linux/"
|
href='https://docs.docker.com/compose/install/linux/'
|
||||||
target="_blank">Compose</a
|
target='_blank'>Compose</a
|
||||||
>)
|
>)
|
||||||
</li>
|
</li>
|
||||||
<li><a href="https://git-scm.com/" target="_blank">Git</a></li>
|
<li><a href='https://git-scm.com/' target='_blank'>Git</a></li>
|
||||||
<li>
|
<li>
|
||||||
A <a href="https://redis.com" target="_blank">Redis</a>-Server
|
A <a href='https://redis.com' target='_blank'>Redis</a>-Server
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<h3>3rd-Parties</h3>
|
<h3>3rd-Parties</h3>
|
||||||
<h4>Required</h4>
|
<h4>Required</h4>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="https://hcaptcha.com">hCaptcha (Captcha)</a></li>
|
<li><a href='https://hcaptcha.com'>hCaptcha (Captcha)</a></li>
|
||||||
<li><a href="https://www.mapbox.com/">Mapbox (Maps)</a></li>
|
<li><a href='https://www.mapbox.com/'>Mapbox (Maps)</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
<h4>Optional</h4>
|
<h4>Optional</h4>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="https://sentry.io">Sentry (Error-Logging)</a></li>
|
<li><a href='https://sentry.io'>Sentry (Error-Logging)</a></li>
|
||||||
<li>
|
<li>
|
||||||
<a href="https://console.cloud.google.com/apis/dashboard"
|
<a href='https://console.cloud.google.com/apis/dashboard'
|
||||||
>Google-Credentials (Sign-In)</a
|
>Google-Credentials (Sign-In)</a
|
||||||
>
|
>
|
||||||
</li>
|
</li>
|
||||||
<li><a href="https://github.com/settings/developers">GitHub-Credentials (Sign-In)</a></li>
|
<li><a href='https://github.com/settings/developers'>GitHub-Credentials (Sign-In)</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<h2>Installation</h2>
|
<h2>Installation</h2>
|
||||||
<p>At first, clone the repo:</p>
|
<p>At first, clone the repo:</p>
|
||||||
|
|
||||||
<pre><code class="language-bash"
|
<pre><code class='language-bash'
|
||||||
>git clone https://github.com/mawoka-myblock/classquiz && cd ClassQuiz</code
|
>git clone https://github.com/mawoka-myblock/classquiz && cd ClassQuiz</code
|
||||||
></pre>
|
></pre>
|
||||||
<p>
|
<p>
|
||||||
Now, you'll configure your frontend. You'll have to change the following in <code
|
Now, you'll configure your frontend. You'll have to change the following in <code
|
||||||
>frontend/Dockerfile</code
|
>frontend/Dockerfile</code
|
||||||
>:
|
>:
|
||||||
</p>
|
</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><code>VITE_MAPBOX_ACCESS_TOKEN</code>: A Mapbox-token which is optional.</li>
|
<li><code>VITE_MAPBOX_ACCESS_TOKEN</code>: A Mapbox-token which is optional.</li>
|
||||||
@@ -96,7 +96,7 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
<h3>Storage Provider</h3>
|
<h3>Storage Provider</h3>
|
||||||
<p>
|
<p>
|
||||||
You'll have to set up a storage provider for some pictures (these getting imported from
|
You'll have to set up a storage provider for some pictures (these getting imported from
|
||||||
Kahoot!). For now, you can use <a href="https://min.io/" target="_blank">Minio (S3)</a> or
|
Kahoot!). For now, you can use <a href='https://min.io/' target='_blank'>Minio (S3)</a> or
|
||||||
the local filesystem. Please not that I'd recommend Minio for larger instances, since it can
|
the local filesystem. Please not that I'd recommend Minio for larger instances, since it can
|
||||||
be scaled and the media doesn't have to streamed through the (comparatively) slow ClassQuiz
|
be scaled and the media doesn't have to streamed through the (comparatively) slow ClassQuiz
|
||||||
server. Now, that you've decided on a storage backend, you can set the
|
server. Now, that you've decided on a storage backend, you can set the
|
||||||
@@ -120,16 +120,16 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
Before you can start your stack, you have to set some environment-variables in your
|
Before you can start your stack, you have to set some environment-variables in your
|
||||||
<code>docker-compose.yml</code>.
|
<code>docker-compose.yml</code>.
|
||||||
</p>
|
</p>
|
||||||
<h3>GitHub/Google-Auth</h3>
|
<h3>GitHub/Google/OpenID-Auth</h3>
|
||||||
<p>
|
<p>
|
||||||
This step is purely optional, but it will enable users to log in using their
|
This step is purely optional, but it will enable users to log in using their
|
||||||
Google/GitHub-accounts.
|
Google/GitHub-accounts.
|
||||||
</p>
|
</p>
|
||||||
<h4>Google</h4>
|
<h4>Google</h4>
|
||||||
<p>
|
<p>
|
||||||
First, go to <a href="https://console.cloud.google.com/apis/dashboard"
|
First, go to <a href='https://console.cloud.google.com/apis/dashboard'
|
||||||
>console.cloud.google.com/apis/dashboard</a
|
>console.cloud.google.com/apis/dashboard</a
|
||||||
> and create a new project and select it. Then, go to the "OAuth consent screen" and set it up.
|
> 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
|
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
|
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.
|
JavaScript origin", which is just the base-domain (with https) of your ClassQuiz-installation.
|
||||||
@@ -140,129 +140,30 @@ SPDX-License-Identifier: MPL-2.0
|
|||||||
|
|
||||||
<h4>GitHub</h4>
|
<h4>GitHub</h4>
|
||||||
<p>
|
<p>
|
||||||
First, go to <a href="https://github.com/settings/developers"
|
First, go to <a href='https://github.com/settings/developers'
|
||||||
>github.com/settings/developers</a
|
>github.com/settings/developers</a
|
||||||
> and create a "new OAuth App". The "Authorization callback URL" has the following schema:
|
> and create a "new OAuth App". The "Authorization callback URL" has the following schema:
|
||||||
</p>
|
</p>
|
||||||
<pre><code>https://[BASE_URL]/api/v1/users/oauth/github/auth</code></pre>
|
<pre><code>https://[BASE_URL]/api/v1/users/oauth/github/auth</code></pre>
|
||||||
<p>
|
<p>
|
||||||
That's it. Click on "Register application" and generate a new client secret and save it for
|
That's it. Click on "Register application" and generate a new client secret and save it for
|
||||||
later, together with your client-id.
|
later, together with your client-id.
|
||||||
</p>
|
</p>
|
||||||
|
<h4>Custom OpenID auth</h4>
|
||||||
|
<p>A login using a custom OpenID provider is also possible. For that, adjust the settings in the docker-compose.yml
|
||||||
|
and configure the following scopes: "openid email profile". The follwoing redirect-url should be used:</p>
|
||||||
|
<pre><code>https://[BASE_URL]/api/v1/users/oauth/custom/auth</code></pre>
|
||||||
|
You'll also need to tell the frontend by editing the <code>frontend/Dockerfile</code>. Add the following line at the top, where all the other ENV's are as well:
|
||||||
|
<pre><code>ENV VITE_CUSTOM_OAUTH_NAME=[SOME_DISPLAY_NAME_FOR_THE_PROVIDER]</code></pre>
|
||||||
|
|
||||||
|
|
||||||
<h3>Docker-Compose File</h3>
|
<h3>Docker-Compose File</h3>
|
||||||
<pre><code class="language-yaml"
|
Please go through the <code>docker-compose.yml</code> thoroughly and fill out all the details, which should be
|
||||||
>version: "3"
|
self-explanatory.
|
||||||
|
|
||||||
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: &build_cfg
|
|
||||||
context: .
|
|
||||||
dockerfile: Dockerfile
|
|
||||||
restart: &restart always
|
|
||||||
depends_on: &depends
|
|
||||||
- db
|
|
||||||
- redis
|
|
||||||
|
|
||||||
environment: &env_vars
|
|
||||||
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: "local" # MUST BE EITHER "s3" OR "local"
|
|
||||||
FREE_STORAGE_LIMIT: "1074000000" # Free storage limit in bytes (default: 1GB)
|
|
||||||
|
|
||||||
# If STORAGE_BACKEND is "s3"
|
|
||||||
S3_ACCESS_KEY=YOUR_ACCESS_KEY
|
|
||||||
S3_SECRET_KEY=YOUR_SECRET_KEY
|
|
||||||
S3_BASE_URL=YOUR_S3_BASE_URL
|
|
||||||
|
|
||||||
# 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.
|
|
||||||
|
|
||||||
volumes: # Only needed if you chose the "local" storage-backend
|
|
||||||
- ./uploads:/var/storage
|
|
||||||
|
|
||||||
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
|
|
||||||
worker:
|
|
||||||
build: *build_cfg
|
|
||||||
environment: *env_vars
|
|
||||||
restart: *restart
|
|
||||||
depends_on: *depends
|
|
||||||
command: arq classquiz.worker.WorkerSettings
|
|
||||||
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
data:
|
|
||||||
meilisearch-data:
|
|
||||||
</code></pre>
|
|
||||||
<p>Run the following command to generate and set the secret up automatically</p>
|
<p>Run the following command to generate and set the secret up automatically</p>
|
||||||
<pre><code class="language-bash"
|
<pre><code class='language-bash'
|
||||||
>sed -i "s/TOP_SECRET/$(openssl rand -hex 32)/g" docker-compose.yml</code
|
>sed -i "s/TOP_SECRET/$(openssl rand -hex 32)/g" docker-compose.yml</code
|
||||||
></pre>
|
></pre>
|
||||||
<p>Now build and deploy:</p>
|
<p>Now build and deploy:</p>
|
||||||
<pre><code>docker compose build && docker compose up -d</code></pre>
|
<pre><code>docker compose build && docker compose up -d</code></pre>
|
||||||
<p><b>ClassQuiz needs HTTPS/SSL to work properly!</b></p>
|
<p><b>ClassQuiz needs HTTPS/SSL to work properly!</b></p>
|
||||||
|
|||||||
Reference in New Issue
Block a user