# linuxmuster-voucher ## **Überblick** Dieses Projekt stellt eine Flask-basierte Anwendung bereit, die mittels Unifi-API WLAN-Voucher generiert und QR-Codes für den einfachen Zugang erstellt, um sie dann großflächig auf dem Bildschirm anzuzeigen. Damit ist es z.B. für Lehrkräfte möglich, Schülern und Schülerinnen einen zeitlich begrenzten WLAN-Zugang freizugeben, ohne dass die Geräte das Netz dauerhaft belasten. --- ## **Voraussetzungen** - Ein Server mit Docker und Docker Compose müssen installiert sein. - Ein funktionierender UniFi-Controller, der über die API erreichbar ist. - Ein Reverse Proxy (z. B. Nginx oder Traefik) für die Weiterleitung und HTTPS-Unterstützung. --- ## **Installation** ### mit docker compose - Verzeichnis erstellen und docker-compose.yml erzeugen mit folgendem Inhalt: ``` name: linuxmuster-voucher services: linuxmuster-voucher: image: git.az-it.net/az/linuxmuster-voucher:latest container_name: linuxmuster-voucher ports: - 42425:42425 volumes: # Eigenes Logo einbinden - MUSS ein PNG sein # - ./.png:/app/script/static/logo.png:ro working_dir: /app/script env_file: - .env restart: unless-stopped ``` - falls der Port 42425 schon belegt ist (sehr unwahrscheinlich), einen freien aussuchen. - .env Datei erzeugen und mit folgendem (angepassten) Inhalt füllen ``` UNIFI_HOST = 'unifi.deineSchule.de' UNIFI_USERNAME = 'admin' UNIFI_PASSWORD = 'yourPassword' UNIFI_PORT = 443 UNIFI_SSL_VERIFY = True UNIFI_SITE_ID = 'yourSiteID' WLAN_SSID = 'your WLAN-SSID' WLAN_PASSWORD = 'your WLAN Passwort' ``` Es wird dringend empfohlen, vernünftige SSL-Zertifikate zu verwenden. Das ist auch nicht so kompliziert umzusetzen. Wenn du noch keine Ahnung hast, wie du es bewerkstelligen sollst, schau dir mal [DNSRoboCert](https://github.com/adferrand/dnsrobocert) an. - starten mit ```docker compose up -d``` Nach wenigen Augenblicken ist die Anwendung am Start und kann (wenn die Firewall das zulässt) schon unsicher auf http://dein.docker.server:42425 erreicht werden. - Reverse-Proxy einrichten (z.B. für nginx wäre es eine Config mit solchem Inhalt) ``` server { listen [::]:443 ssl; listen 443 ssl; server_name voucher.deine-schule.tld ; add_header Strict-Transport-Security "max-age=15768000; includeSubDomains"; ssl_certificate /etc/letsencrypt/live/deine-schule.tld/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/deube.schule.tld/privkey.pem; ssl_session_cache builtin:1000 shared:SSL:50m; ssl_protocols TLSv1.2; ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4; ssl_prefer_server_ciphers on; access_log /var/log/nginx/access.log ; location / { 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 $scheme; proxy_pass http://127.0.0.1:42425; proxy_read_timeout 90; } } ``` Damit wäre der Voucher-Generator (ungeschützt) unter der Domain erreichbar. Wenn du den Generator per MDM als Web-App an die Endgeräte ausrollst, kannst du durch *security by obscurity* einen zufälligen Missbrauch verhindern, indem du die Seite nicht auf / auslieferst, sondern mit einem Pseudo-Zufalls-URI. Dazu würdest du in der nginx-config ``` location / { ``` durch ``` location /afskjhsh98zafuihjkancs98 ``` ersetzen. Der Voucher-Generator wäre dann unter https://voucher.deine-schule.de/afskjhsh98zafuihjkancs98/ erreichbar. Wenn du dann noch mit der Firewall einschränkst, dass diese Seite nur aus dem Schul-WLAN erreichbar ist, bist du schon recht sicher - denn wer den URI kennt, muss dann, um ihn nutzen zu können schon Zugriff haben. Sollte man dann irgendwann mitbekommen, dass die Adresse die Runde macht, ändert man einfach irgend ein Zeichen im Location-Block. Ich selbst nutze das System hinter einem Passwortschutz mit Keycloak, das ist aber nicht *mal schnell* eingerichtet, weshalb ich hier eine niederschwelligere Version bereitstelle. ### alternativ: selber bauen - Repo clonen und .env erstellen ```bash git clone https://git.az-it.net/linuxmuster-voucher.git cd linuxmuster-voucher cp .env-dist .env ``` - .env anpassen (s.o.) - **Docker-Image bauen** ```bash docker compose build ``` - **Container starten** ```bash docker compose up -d ``` Die Anwendung ist unter `http://:42425` erreichbar. ## **Verwendung** ### 1. **Startseite** Rufe die Startseite unter `https://voucher.deine-schule.tld` (die im Reverseproxy konfigurierte URL) auf. ![Startseite](https://git.az-it.net/az/linuxmuster-voucher/src/commit/6828ead83393f51f9020e6bc5f950fac3d8c6c77/screenshots/startseite.png) ### 2. **Voucher erstellen** Ein Druck auf eine der beiden Schaltflächen startet die Magie und du erhältst: (./screenshots/codeseite.png) Die Seite zeigt den generierten Zugangscode und einen QR-Code an, der die WLAN-Zugangsdaten enthält. --- ## **Anpassungen** ### 1. **Logo ändern** - Lege dein Logo in das Projektverzeichnis. - Erstelle in der docker-compose.yml einen Bind-Mount zu dieser Datei: ```yaml ... volumes: # Eigenes Logo einbinden - MUSS ein PNG sein - ./.png:/app/script/static/logo.png:ro ... ``` - Achte dabei auf die Einrückungstiefe. **volumes:** muss sich auf der selben Ebene befinden wie **image**, **ports** usw. ### 2. **Port ändern** Passe bei Bedarf den den Port in der `docker-compose.yml` an: ```yaml ports: - "8080:42425" ``` --- ## **Fehlerbehebung** ### 1. **Fehler: `ModuleNotFoundError`** Stellen Sie sicher, dass alle Abhängigkeiten installiert sind: ```bash docker compose exec pip install -r /app/requirements.txt ``` ### 2. **UniFi-Controller nicht erreichbar** - Überprüfen Sie die Zugangsdaten in der `.env`-Datei. - Stellen Sie sicher, dass der UniFi-Controller über die API erreichbar ist. ### 3. **Logs prüfen** Prüfen Sie die Logs des Containers: ```bash docker compose logs -f ``` --- ## **Lizenz** Dieses Projekt steht unter der MIT-Lizenz. Weitere Informationen finden Sie in der Datei `LICENSE`. 1. Das Python-Script nutzt verschiedene Module: - authlib.integrations.flask_client - flask - werkzeug.middleware.proxy_fix - pyunifi.controller - qrcode 2. Das Wifi-Symbol habe ich von hier: [Wifi Icons No Attribution](https://www.freeiconspng.com/img/3780) ---