6.3 KiB
Deployment aircard-ios.org
Die Seite wird auf dem Webklar-Server aus dem Gitea-Repo knso/AirCardIOS gebaut und von nginx ausgeliefert. Traefik stellt TLS und Weiterleitungen. Dieser Ordner enthält alles, was dafür im Repo liegt; die Dateien auf dem Server sind Kopien davon.
Bestandteile
| Datei im Repo | Ziel auf dem Server (/home/webklar/apps/) |
Aufgabe |
|---|---|---|
deploy/deploy.sh |
aircard-ios.org/deploy.sh (ausführbar) |
klont/aktualisiert das Repo, baut web/ und kopiert dist/ nach out/ |
deploy/webhook-server.js |
aircard-ios.org/webhook-server.js |
nimmt den Gitea-Webhook an, startet deploy.sh nacheinander, pollt alle 15 Minuten |
deploy/nginx/aircard-ios.org.conf |
aircard-ios.org/nginx/aircard-ios.org.conf |
nginx-Konfiguration der Seite |
deploy/traefik/aircard.yml |
traefik/dynamic/aircard.yml |
Route /v1 mit Header X-Appwrite-Project: aircard an Appwrite |
deploy/compose-snippet.yml |
docker-compose.yml (nach dem eship-Block) |
Dienste aircard-build und aircard |
Weitere Ordner unter aircard-ios.org/ (nicht im Repo): build/ (Klon des Repos, Arbeitsordner des Build-Containers), out/ (gebaute Seite, von nginx ausgeliefert), dev/ (Arbeitskopie für die Entwicklung, nicht gemountet).
Einrichten (einmalig)
APP=/home/webklar/apps
SRC=$APP/aircard-ios.org/dev/deploy
mkdir -p $APP/aircard-ios.org/build $APP/aircard-ios.org/out $APP/aircard-ios.org/nginx
cp $SRC/deploy.sh $APP/aircard-ios.org/deploy.sh && chmod +x $APP/aircard-ios.org/deploy.sh
cp $SRC/webhook-server.js $APP/aircard-ios.org/webhook-server.js
cp $SRC/nginx/aircard-ios.org.conf $APP/aircard-ios.org/nginx/aircard-ios.org.conf
# Compose: Backup, dann den Inhalt von compose-snippet.yml unter `services:` direkt nach dem eship-Block einfügen
cp $APP/docker-compose.yml $APP/docker-compose.yml.bak-2026-10-04-aircard
cd $APP && docker compose config -q; echo $? # 0; einzige erlaubte Ausgabe: Warnung "attribute `version` is obsolete"
# Traefik-Route atomar ablegen (Datei-Provider lädt sie ohne Neustart)
cp $SRC/traefik/aircard.yml $APP/traefik/dynamic/aircard.yml.tmp && mv $APP/traefik/dynamic/aircard.yml.tmp $APP/traefik/dynamic/aircard.yml
Die .env neben der docker-compose.yml muss GITEA_DEPLOY_TOKEN (Lesezugriff auf knso/AirCardIOS) und GITEA_DEPLOY_WEBHOOK_SECRET enthalten. Beide Werte gehören nie in Logs, Chats oder Commits.
Starten
cd /home/webklar/apps && docker compose up -d aircard-build aircard
Nur diese beiden Dienste starten, nie ein nacktes docker compose up -d (das würde nicht laufende Dienste wie eship-build wieder anlegen). Der Build-Container installiert beim Start git, startet den Webhook-Server und baut sofort einmal (initial). Den Fortschritt zeigt docker logs -f webklar-aircard-build; am Ende steht Deployment abgeschlossen (oder eine Zeile mit ERROR:).
Ohne AIRCARD_WEBHOOK_TOKEN (also ohne GITEA_DEPLOY_WEBHOOK_SECRET in der .env) beendet sich der Webhook-Server mit Exit-Code 1, statt Anfragen ungeprüft durchzulassen.
Manuell deployen
docker exec webklar-aircard-build sh /deploy.sh
Ohne DEPLOY_TRIGGER baut das Skript immer neu, auch wenn sich der Commit nicht geändert hat.
Gitea-Webhook
Repo knso/AirCardIOS → Einstellungen → Webhooks → Gitea:
| Feld | Wert |
|---|---|
| Ziel-URL | https://aircard-ios.org/webhook/deploy |
| HTTP-Methode | POST |
| Content-Type | application/json |
| Secret | Wert von GITEA_DEPLOY_WEBHOOK_SECRET aus /home/webklar/apps/.env (volle Länge, nur dort nachsehen) |
| Auslöser | nur Push-Ereignisse |
| Branch-Filter | main |
| Aktiv | ja |
„Test delivery“ muss 202 ergeben. 401 heißt: Secret stimmt nicht. 200 mit {"ignored":true} heißt: Push auf einen anderen Branch als main.
Verhalten
- Webhook (
POST /webhook/deploy): prüft die Signatur im Headerx-gitea-signature(HMAC-SHA256 über den Rohbody).401bei falscher oder fehlender Signatur,413bei Body über 1 MB,200bei Push auf einen anderen Branch,202bei Push aufmain; der Build läuft danach im Hintergrund. Alles andere antwortet404. - Warteschlange: Builds laufen nacheinander, höchstens einer läuft und einer wartet. Weitere Pushes während ein Lauf wartet, werden mit
202beantwortet und fügen keinen Lauf hinzu (der wartende Lauf holt ohnehin den neuesten Stand). - Trigger:
webhookund manuelle Aufrufe bauen immer.initial(Container-Start) undpoll(alle 15 Minuten) bauen nur, wenn es einen neuen Commit gibt oderout/index.htmlfehlt. - Gemerkter Commit:
build/.git/aircard-last-deployed-commitenthält den zuletzt versuchten Commit, geschrieben vor dem Build. Ein kaputter Build wird deshalb nicht alle 15 Minuten wiederholt; die alte Seite bleibt online, bis ein neuer Commit oder ein Webhook-/manueller Lauf kommt. - Fehler: Ein fehlgeschlagener Lauf wird mit
[webhook] … deployment failedprotokolliert und beendet den Server nicht. Fehlerzeilen des Skripts beginnen mitERROR:. - Build-Variablen:
VITE_APPWRITE_ENDPOINTundVITE_APPWRITE_PROJECT_IDkommen aus der Container-Umgebung (compose); Vite liest sie direkt.
Änderungen später
deploy.shändern: Datei auf dem Server mitcpüberschreiben (nichtmv, sonst zeigt der Datei-Mount auf die alte Datei). Gilt beim nächsten Lauf.webhook-server.jsändern: ebenso mitcpersetzen, danncd /home/webklar/apps && docker compose restart aircard-build.- nginx-Konfiguration ändern: mit
cpersetzen, danndocker exec webklar-aircard nginx -t && docker exec webklar-aircard nginx -s reload. - Traefik-Route ändern: Datei atomar ersetzen wie oben; Löschen der Datei entfernt die Route wieder.
www.aircard-ios.org
Solange dig +short www.aircard-ios.org @8.8.8.8 nichts liefert, gibt es nur die Hauptdomain. Zeigt der A-Record auf 91.99.156.85, werden die auskommentierten www-Labels am Dienst aircard in docker-compose.yml aktiviert (Backup vorher, dann docker compose config -q und docker compose up -d aircard). Sie leiten per 301 auf https://aircard-ios.org weiter und haben eigene Router, damit ein www-Fehler das Zertifikat der Hauptdomain nicht blockiert.
Tests
node --test deploy/webhook-server.test.js
Die Tests brauchen nur Node und starten die Server auf Port 0.