Schulwirken in 10 Minuten einrichten

Schulwirken läuft als Docker-Container auf jedem Linux-Server. Du brauchst keine .NET-Kenntnisse - nur Docker und einen Lizenzkey. Wie die App bedient wird, steht in der Hilfe.

Voraussetzungen

  • Linux-Server (Ubuntu 22.04 oder neuer empfohlen)
  • Docker ≥ 24 und Docker Compose ≥ 2
  • Rund 1,5 GB freier Speicher für das App-Image (es enthält LibreOffice für die Vorschau von Word-, PowerPoint- und Excel-Dateien)
  • Einen gültigen Schulwirken-Lizenzkey (hier kaufen)
  • Eine Domain, die auf deinen Server zeigt
  • Einen SMTP-Zugang für den E-Mail-Versand (Einladungen)

Installation

1

Arbeitsverzeichnis anlegen

mkdir schulwirken && cd schulwirken
2

docker-compose.yml anlegen

Erstelle eine Datei docker-compose.yml mit folgendem Inhalt:

services:
  app:
    image: ghcr.io/daniel-kinas/schulwirken-web-selfhosted:latest
    container_name: schulwirken-app
    restart: unless-stopped
    ports:
      - "127.0.0.1:8080:8080"
    environment:
      - App__LicenseKey=${LICENSE_KEY}
      - App__BaseUrl=${BASE_URL}
      - App__SchoolName=${SCHOOL_NAME:-Meine Schule}
      - App__AdminEmail=${ADMIN_EMAIL:-admin@schulwirken.local}
      - App__AdminPassword=${ADMIN_PASSWORD:-}
      - ConnectionStrings__Default=Server=db;Database=schulwirken;User=root;Password=${DB_PASSWORD}
      - Jwt__Key=${JWT_KEY}
      - Email__Host=${EMAIL_HOST}
      - Email__Port=${EMAIL_PORT:-587}
      - Email__Username=${EMAIL_USERNAME}
      - Email__Password=${EMAIL_PASSWORD}
      - Email__FromAddress=${EMAIL_FROM_ADDRESS}
      - Email__FromName=${EMAIL_FROM_NAME:-Schulwirken}
      - Push__PublicKey=${PUSH_PUBLIC_KEY}
      - Push__PrivateKey=${PUSH_PRIVATE_KEY}
      - Push__Subject=${PUSH_SUBJECT:-mailto:admin@example.com}
    volumes:
      - schulwirken_uploads:/app/wwwroot/uniformen
      - schulwirken_logs:/app/logs
    depends_on:
      db:
        condition: service_healthy

  db:
    image: mysql:8.4
    container_name: schulwirken-db
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
      MYSQL_DATABASE: schulwirken
    volumes:
      - mysql_data:/var/lib/mysql
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-p${DB_PASSWORD}"]
      interval: 10s
      timeout: 5s
      retries: 10

volumes:
  mysql_data:
  schulwirken_uploads:
  schulwirken_logs:
3

.env-Datei anlegen

nano .env

Inhalt (siehe Konfiguration unten).

Konfiguration

Lege eine .env-Datei im selben Verzeichnis wie die docker-compose.yml an:

# Lizenzkey (erhalten nach Kauf)
LICENSE_KEY=XXXX-XXXX-XXXX-XXXX

# Deine Domain (mit https://)
BASE_URL=https://schule.meinedomain.de

# Datenbankpasswort (sicheres Passwort wählen)
DB_PASSWORD=sicheres-passwort-hier

# JWT-Schlüssel (mindestens 32 zufällige Zeichen)
JWT_KEY=ersetze-mit-mind-32-zeichen-langem-key

# ── Erststart: Admin-Konto & Schulname ────────────────────
# Nur beim ersten Start verwendet. Danach kann das Passwort
# unter “Mein Profil” geändert werden.
SCHOOL_NAME=Grundschule Musterstadt
ADMIN_EMAIL=schulleitung@muster.de
# Empfohlen: eigenes Passwort setzen. Wenn leer, wird beim
# ersten Start ein Passwort generiert und in initial-admin.txt
# im Container-Arbeitsverzeichnis gespeichert.
ADMIN_PASSWORD=sicheres-admin-passwort

# ── E-Mail (für Einladungen an Nutzer) ──────────────────
EMAIL_HOST=smtp.meinprovider.de
EMAIL_PORT=587
EMAIL_USERNAME=noreply@meinedomain.de
EMAIL_PASSWORD=email-passwort
EMAIL_FROM_ADDRESS=noreply@meinedomain.de
EMAIL_FROM_NAME=Schulwirken

# ── Push-Benachrichtigungen (Chat, optional) ─────────────────
# VAPID-Schlüsselpaar für Browser-/Handy-Push bei neuen
# Chat-Nachrichten. Leer lassen = Push deaktiviert (Chat
# funktioniert trotzdem). Erzeugen siehe Hinweis unten.
PUSH_PUBLIC_KEY=
PUSH_PRIVATE_KEY=
PUSH_SUBJECT=mailto:schulleitung@muster.de

Den JWT-Schlüssel kannst du so generieren:

openssl rand -base64 32

E-Mail-Pflicht: Schulwirken versendet Einladungslinks per E-Mail, wenn du neue Nutzer hinzufügst. Ohne gültige SMTP-Konfiguration können keine Nutzer eingeladen werden.

Push-Benachrichtigungen (optional)

Damit Nutzer bei neuen Chat-Nachrichten eine Browser- bzw. Handy-Benachrichtigung erhalten - auch bei geschlossenem Tab - brauchst du ein VAPID-Schlüsselpaar. Erzeuge es einmalig, z. B. mit Node:

npx web-push generate-vapid-keys

Trage den Public Key in PUSH_PUBLIC_KEY und den Private Key in PUSH_PRIVATE_KEY ein. PUSH_SUBJECT ist eine Kontakt-Adresse im Format mailto:deine@adresse.de.

Hinweise: Push funktioniert nur über https:// (deine BASE_URL sollte also TLS nutzen). Lässt du die Schlüssel leer, ist Push einfach deaktiviert - der Chat selbst bleibt voll funktionsfähig. Den privaten Schlüssel niemals weitergeben. Unabhängig davon verschickt Schulwirken bei länger ungelesenen Chat-Nachrichten (ab 4 Stunden) eine Erinnerungs-E-Mail - dafür genügt die SMTP-Konfiguration oben.

Lizenzkey aktivieren

Schulwirken prüft beim Start automatisch deinen Lizenzkey gegen license.schulwirken.de. Der Key wird an deine Domain gebunden - du musst nichts weiter tun.

Läuft die Lizenz ab, wechselt die App in den Lesezugriff-Modus. Du kannst die Lizenz jederzeit unter Preise verlängern.

Bezahlung auf Rechnung: Schulwirken wird per Rechnung mit Überweisung bezahlt (14 Tage Zahlungsziel). Keine Kreditkarte nötig. Die Aktivierung erfolgt nach Zahlungseingang. Vor Ablauf erinnert dich Schulwirken automatisch per Mail (30 / 14 / 0 Tage).

App starten

docker compose up -d

Beim ersten Start wird die Datenbank automatisch angelegt und alle Migrationen eingespielt. Das dauert einige Sekunden.

Logs ansehen:

docker compose logs -f app

Die App läuft auf Port 8080.

Erster Login

Nach dem Start erreichst du Schulwirken unter deiner konfigurierten BASE_URL (oder zunächst über http://server-ip:8080).

Beim ersten Start wird automatisch ein Admin-Konto angelegt. Hast du ADMIN_PASSWORD in der .env gesetzt, verwendest du dieses direkt.

Ohne ADMIN_PASSWORD wird ein Zufalls-Passwort generiert und in der Datei initial-admin.txt im Arbeitsverzeichnis des Containers gespeichert:

docker compose exec app cat initial-admin.txt

Bitte lösche die Datei nach dem ersten Login:

docker compose exec app rm initial-admin.txt

Das Passwort kann anschließend jederzeit unter Mein Profil geändert werden.

Weitere Nutzer lädst du danach unter Verwaltung → Benutzer ein. Welche Rolle was darf, steht unter Benutzer & Rollen.

Updates einspielen

Schulwirken-Updates werden als neue Docker-Images veröffentlicht. Einspielen:

docker compose pull
docker compose up -d

Datenbank-Migrationen laufen beim App-Start automatisch. Deine Daten bleiben im benannten Volume mysql_data erhalten.

Reverse Proxy (HTTPS)

Schulwirken lauscht auf Port 8080. Stelle einen Reverse Proxy davor, der HTTPS terminiert.

Nginx

server {
    listen 443 ssl;
    server_name schule.meinedomain.de;

    ssl_certificate     /etc/letsencrypt/live/schule.meinedomain.de/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/schule.meinedomain.de/privkey.pem;

    location / {
        proxy_pass         http://127.0.0.1:8080;
        proxy_set_header   Host $host;
        proxy_set_header   X-Real-IP $remote_addr;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Proto https;
    }
}

Backup

Datenbank

# Backup erstellen
docker compose exec db mysqldump -u root -p"$DB_PASSWORD" schulwirken \
  > backup_$(date +%Y%m%d).sql

# Backup einspielen
docker compose exec -T db mysql -u root -p"$DB_PASSWORD" schulwirken \
  < backup_20250101.sql

Hochgeladene Dateien (Schulkleidungs-Katalog)

Bilder aus dem Schulkleidungs-Katalog werden im Docker-Volume schulwirken_uploads gespeichert und überleben Neustarts und Updates. Für ein vollständiges Backup solltest du dieses Volume zusätzlich sichern:

# Uploads-Volume sichern
docker run --rm \
  -v schulwirken_uploads:/data \
  -v "$(pwd)":/backup \
  busybox tar czf /backup/uploads_$(date +%Y%m%d).tar.gz -C /data .

# Uploads-Volume wiederherstellen
docker run --rm \
  -v schulwirken_uploads:/data \
  -v "$(pwd)":/backup \
  busybox tar xzf /backup/uploads_20250101.tar.gz -C /data

Dokumente-Ablage (Add-on)

Hochgeladene Dokumente liegen, wenn das Add-on gebucht ist, im eigenen Docker-Volume schulwirken_documents - getrennt vom Uploads-Volume, damit ein Restore des einen nicht versehentlich das andere überschreibt:

# Dokumente-Volume sichern
docker run --rm \
  -v schulwirken_documents:/data \
  -v "$(pwd)":/backup \
  busybox tar czf /backup/dokumente_$(date +%Y%m%d).tar.gz -C /data .

# Dokumente-Volume wiederherstellen
docker run --rm \
  -v schulwirken_documents:/data \
  -v "$(pwd)":/backup \
  busybox tar xzf /backup/dokumente_20250101.tar.gz -C /data

Troubleshooting

Die App startet nicht
Prüfe die Logs: docker compose logs app. Häufige Ursachen: falscher DB_PASSWORD, MySQL noch nicht bereit (kurz warten und erneut starten), oder ungültiger JWT_KEY.
Wo finde ich die Anwendungs-Logs?
Warnungen und Fehler live in der Konsole: docker compose logs -f app. Das vollständige Log mit allen Meldungen schreibt die App als rollende Tagesdateien nach /app/logs im Container. Dieses Verzeichnis liegt im Docker-Volume schulwirken_logs und überdauert Neustarts und Updates. Auf den Host kopieren z. B. mit docker compose cp app:/app/logs ./logs. Alte Dateien werden automatisch nach 31 Tagen aufgeräumt (anpassbar über Logging__RetainedFileCountLimit).
Einladungs-E-Mails kommen nicht an
Prüfe die SMTP-Einstellungen in der .env: Host, Port (meist 587 für STARTTLS), Benutzername und Passwort. Viele Provider erfordern App-Passwörter statt des normalen Passworts. Logs: docker compose logs app | grep -i mail.
Lizenz ungültig / Lesezugriff-Modus
Prüfe, ob LICENSE_KEY und BASE_URL in der .env korrekt sind. Der Server muss ausgehende HTTPS-Verbindungen zu license.schulwirken.de erlauben.
Port 8080 ist bereits belegt
Ändere in der docker-compose.yml den Host-Port: - "127.0.0.1:8081:8080" und passe deinen Reverse Proxy entsprechend an.

Fragen zur Bedienung (Passwort vergessen, Eltern sehen etwas nicht) beantwortet die Hilfe.

Weitere Fragen? Schreib uns an hallo@schulwirken.de.