„Warum gebe ich eigentlich meine Trainingsdaten an Strava ab, wenn die ohnehin schon auf meinem iPhone liegen?“
Diese Frage habe ich mir irgendwann letzten Sommer beim Laufen gestellt. Apple Health weiß über meinen Körper inzwischen mehr als mein Hausarzt – jeder Puls egal ob in Ruhe oder beim Sport, jeder Höhenmeter, jede verbrannte Kalorie. Aber sobald ich das für mich auswerten will, lande ich entweder in der minimalistischen Health-App zumindest was Dashboards und Fitness angeht, die für lange Verläufe nicht gemacht ist, oder ich lade das ganze in eine Cloud, die mir genau diese Daten als „Bezahlung“ abnimmt.
lso habe ich mir was Eigenes gebaut. Heraus gekommen ist MyActivityLog – ein zweiteiliges System aus iOS-App und selbstgehostetem Webservice. Ich nutze das mittlerweile seit Monaten selbst täglich, natürlich ist ja mein Produkt, deshalb möchte ich das Projekt mal ausfürhlich vorstellen. Denn mit dem Juni Release sind coole neue Features dazugekommen. Erwartet aber keinen Hochglanz-Pressetext, sondern so wie es ist: ein Hobby-Projekt mit dem Anspruch, sauber zu funktionieren – und das tut es tatsächlich.



Was ist MyActivityLog eigentlich?
Ganz einfach: MyActivityLog holt deine Workouts aus Apple Health raus und schiebt sie in ein Dashboard, das dir gehört. Server steht bei dir zu Hause, in einem Container, in einer VM, auf einem Raspberry Pi, oder bei einem beliebigen Hoster – egal. Hauptsache nicht in der Cloud eines Unternehmens, das möglicherweise deine Aktivitäten zu Geld macht. Du sorgst für den Schutz deiner Daten
Das Ganze besteht aus zwei Komponenten:
1. Die iOS-App (verfügbar im App Store) – die Brücke zwischen Apple Health und deinem Server. Liest HealthKit-Daten, sendet sie via HTTPS an das Backend.
2. Das Webservice (Open Source) – Docker-Compose-Stack mit FastAPI-Backend, PostgreSQL + PostGIS für die GeoDaten, und einem Vue-Frontend.
Dazwischen läuft eine ganz schlichte REST-API mit einem Personal Access Token. Kein OAuth Gefriement, keine Drittanbieter, kein Tracking. Du, dein iPhone, dein Server.

Aber warum überhaupt selbst hosten?
Die ehrliche Antwort: Ich bin ein bisschen ein Datenmessie. Ich habe seit Jahren eine Apple Watch, ich laufe gern wenn es die Zeit zulässt, ich fahre auch Rad und dann lange Strecken oder hoch hinaus, ich gehe in den Ostirroler und Kärntner Bergern wandern. Jede dieser Aktivitäten erzeugt GPS-Spuren, Herzfrequenzkurven, Höhenmeter. Das ist mein Trainingstagebuch, und ich möchte es in 20 Jahren noch lesen können – nicht von der Geschäftsstrategie eines Anbieters abhängig, nicht durch einen abgeschalteten Server weg, nicht in irgendeinem proprietären Format eingesperrt.
Dazu kommt ein zweiter Punkt, der für mich fast wichtiger ist: Datenschutz aus Prinzip. GPS-Tracks sind sensibel. Wer mein Trainingsverlauf liest, sieht möglicherweise meine Adresse, meine täglichen Routen Es gibt schon genug Studien dazu, was Heatmaps von Fitness-Plattformen über Militärbasen verraten haben – im Privaten ist es nicht viel besser. Dazu kommt aber auch sich digital unabhängig zu machen. Ein US Konzern weniger, der diese Daten vorhält – Ja ich weiß: Apple als Einstiegspunkt bleibt bestehen – es geht im Moment auch nicht darum alles umzustellen – aber auch das wird kommen. Klopf, klopf Polar 😉 .
Und viertens, ganz banal: Ich wollte mal wieder etwas Eigenes bauen. Und diesmal etwas Größeres – ich mag meine Selfhosting-Ecke mit den vielen kleinen gebrauten Microservices und und in diese passt MyActivityLog perfekt rein.
Was kann das Dashboard?
Hier wird es interessant. Das Dashboard ist im Laufe der Monate immer üppiger geworden, weil ich Features hinzugefügt habe, sobald sie mir im Alltag gefehlt haben. Stand heute:
Workout-Liste mit allem was zählt
Paginierte Übersicht, filterbar nach Aktivitätstyp. Jedes Workout zeigt Ort, Distanz, Dauer, Puls und Aktivitätstyp auf einen Blick. Den Ort holt sich das Backend per Reverse Geocoding aus dem GPS-Startpunkt – ohne extra Klick weißt du also sofort: das war die Runde durch den Draupark, das war Glocknerradweg.

Workout-Detail: das Herzstück
Klick auf ein Workout, und du landest auf einer Seite, die ich liebevoll Stück für Stück gebaut habe:
MapLibre-Karte mit pace-farbkodierter Route – grün für schnelle Kilometer, rot für die zähen. Auf einen Blick siehst du, wo du eingebrochen bist. In meinem Fall, eh immer.
Streckenprofil-Chart – Höhe, Pace und Herzfrequenz in einem kombinierten Diagramm.
HR-Chart – klassische Herzfrequenzkurve.
Pace-Splits-Tabelle – Kilometer für Kilometer, farbkodiert konsistent zur Karte.
Höhenmeter aus GPS-Altitude
VO2max – wenn die Apple Watch ihn geschätzt hat, zeigen wir ihn an.

Statistiken, Fitness, Verlauf
Drei Views, die zusammen ein ziemlich vollständiges Bild deines Trainings ergeben:
Statistiken – km pro Monat, Stunden pro Woche, Aktivitätstypen-Verteilung. Mit einheitlicher Filter-Bar und Zeitraum-Presets (letzte 30 Tage, dieses Jahr, alles…).
Fitness – Banister-TRIMP-Modell mit CTL (Chronic Training Load = Fitness), ATL (Acute Training Load = Ermüdung) und TSB (Training Stress Balance = Form). Wer das aus Strava kennt, fühlt sich sofort zu Hause.
Verlauf – Pace-Verlauf und VO2max pro Aktivitätstyp mit Trendlinie. Du wirst schneller. Oder eben nicht. Aber wenigstens weißt du es.

Energiebilanz
Eine View, die ich überraschend oft anschaue: BMR (Mifflin-St Jeor) plus Workout-Kalorien als Bar Chart pro Tag Du gibst einmal dein Körperprofil ein (Gewicht, Größe, Geburtsdatum, Geschlecht, PAL-Faktor), und siehst dann auf einen Blick: was hat dich der Tag gekostet, was kam vom Sport oben drauf.

Heatmap
Alle GPS-Tracks übereinandergelegt auf einer Karte dargestellt. Bisschen unnötig, bisschen Zeitreise.

Segment-Matching
Mein Lieblingsfeature für Vergleichswütige. Das Backend rastert deine GPS-Routen in Zellen, hasht sie zu „Fingerprints“ und sucht dann mit einem Longest-Common-Subsequence-Algorithmus automatisch nach wiederkehrenden Streckenabschnitten in deinen Workouts.
Sprich: läufst du eine Strecke dreimal die Woche, findet das System diese Wiederholungen, zeigt dir die Pace-Vergleiche in einer Mini-Map und du siehst, ob du auf Standardabschnitt schneller geworden bist.

Sharing: granular und mit Ablaufdatum
Manchmal will ich einen Lauf mit jemandem teilen. Aber nicht zwingend mit der Herzfrequenz. Manchmal die Karte ja, die Distanz nein. Deshalb gibt es pro Workout genau einen Share-Token mit individuell konfigurierbaren Berechtigungen:
- Route / GPS-Track an/aus
- Karte an/aus
- Herzfrequenz an/aus
- Distanz an/aus
- Dauer an/aus
Plus Gültigkeit: 7 Tage, 14 Tage, 30 Tage oder permanent. Abgelaufene Links zeigen eine eigene „nicht mehr verfügbar“-Seite. Der öffentliche Share-View ist ein eigenes UI ohne Sidebar, ohne Login, mit Light/Dark-Toggle und Sprachauswahl.
Dazu kannst du Einträge einfach öffentlich machen, sprich es gibt eine öffentliche Timeline. Ausgewählte Läufe kannst du „zum Angeben“ veröffentlichen, diese sind dann unter einem eigenen Link public-workouts wie z.b. diesem hier sichtbar. Die Freigabe dazu kannst du natrlich auch wieder zurückziehen.
Und nun:
Die iOS-App
Auf der iPhone-Seite läuft die MyActivityLog App (App Store) Sie ist bewusst minimalistisch gehalten – sie ist eine Bridge, kein zweites Strava.
Was sie aktuell kann:
- HealthKit lesen – Workouts, GPS-Routen, Herzfrequenz
- Lokaler Export – ein einzelnes Workout, alle Workouts oder ein Zeitraum als JSON ins File Management ablegen. Praktisch zum manuellen Befüllen des Servers oder als Backup ohne Backend.
- Sync zum eigenen Server – HTTPS POST mit Personal Access Token im Keychain
- Inkrementelle Sync – beim zweiten Mal werden nur neue Workouts gesendet
- Background Sync – prizipiell läuft das ganz von selbst im Hintergrund, aber es ist noch etwas buggy. Also ein Background Task ist unter iOS echt fies.
Härtetest: bei meinem initialen Import waren das 186 Workouts mit etwa 1,5 Millionen Zeilen JSON (15 Monate Historie). Das Backend hat das in rund zwei Minuten geschluckt. GPS-Punkte werden im 1-Sekunden-Takt aufgezeichnet – eine längere Bergtour erzeugt locker 30.000 Punkte.


Wie einfach ist das Hosten?
Hier wird es für die Selfhoster interessant. Ich habe mich beim Setup bewusst an einem Docker Compose und fertig orientiert. Drei Container, ein `.env`, los gehts.
Voraussetzungen:
- Ein Linux-Server (getestet auf Ubuntu 24.04 LTS), Docker und Docker Compose
- Python 3 für ein einmaliges Setup-Script
Sicherheit: nicht ganz so nebenbei
Ich habe das Projekt im von diversen Tools analysieren lassen, auch von Claude Code. Basieren darauf hab ich auch mit Claude Code, an der Security gefeilt. Dazu kommt noch eine auf Security, Vulnerability Checks und Abhängigkeiten fokussierte Gitlab Pipelline.
Was inzwischen drin ist:
- Personal Access Tokens (PAT) statt statischer API-Key
- Brute-Force-Schutz
- Rate Limiting
- TOTP (2FA) für den Dashboard-Login, Secret AES-256-GCM-verschlüsselt
- Audit-Log für sicherheitsrelevante Aktionen (Login, Token-Erstellung, Passwortänderung)
- Security Headers + CSP im Frontend
- SQL-Injection Fixes – hoff ich mal dass ich das nun im Griff hab, aber kein Tool jammer
- Docker-User unprivilegiert – manchen ist das ja egal. Aber warum sollt dieser Service root haben, also nein, non-privileged
Für wen ist das?
Ehrlich gesagt: für eine ziemlich spezifische Zielgruppe.
Du bist wahrscheinlich richtig hier, wenn…
- du eine Apple Watch trägst und Apple Health regelmäßig befüllst
- du Selfhosting magst
- du deine Trainingsdaten nicht mehr in der Cloud eines Anbieters haben willst
- dir die kleinen Details wichtig sind: pace-farbkodierte Routen, vernünftige Höhenmeter, Fitness-Trend mit echtem Modell, Reverse Geocoding für Ortsangaben
Du bist wahrscheinlich woanders besser aufgehoben, wenn…
- du Social Features willst (Kudos, Following, Segmente in der Community)
- du Race-Planning oder Workout-Plans suchst
- du Android nutzt – die App ist iOS-only und wird das vorerst auch bleiben
Das ist kein Strava-Klon. Es ist ein persönliches Trainingstagebuch mit Datenschutz im Mittelpunkt.
—
Wo bekommst du es?
Der Server-Teil ist Open Source. Pull Requests sind willkommen, Issues auch. Ich entwickle das in meiner Freizeit, also bitte keine SLA-Erwartungen – aber ich antworte, und ich freue mich über Feedback. Das Repo in Codeberg wird nicht immer bespielt, nur wenn meine Changes intern durch die Pipeline gelaufen sind und Test bestanden haben. Also Issues und Featurewünsche kommen zuerst in mein internes Gitlab und gehen dann wieder raus an Codeberg.
Und, wie geht es weiter?
Was noch auf der Roadmap steht:
- Background-Sync in der iOS-App polieren – funktioniert irgendwie, aber muss noch zuverlässiger werden
- HR-Zonen-Analyse im Backend
- CSV/JSON Bulk-Export für das ganze Archiv
- GPS Export für Workouts
- Tainingsstrecken festlegen aus bestehendem Workout
- Tägliche Metriken (Steps, Sleep, RHR)
Zum Schluss noch…
Ich nutze MyActivityLog inzwischen täglich. Beim Sonntag-Lauf öffne ich nach der Dusche das Dashboard und schaue, ob ich tatsächlich schneller war als letzte Woche (manchmal ja, oft nicht). Ich teile gelegentlich einen Lauf mit Freunden via Share-Link, ohne dass sie sich irgendwo anmelden müssen.
Und das Beste: alle ausgewerteten Daten liegen auf meinem Server. Wenn ich morgen umziehe, kommen sie mit. Wenn der Anbieter X morgen verschwindet, betrifft es mich nicht. Wenn Apple mal irgendwann die Services killt oder eine Unterseekabel, oder Donald Trump, oder andere Außerirdische, die Daten liegen sie bei mir am Server. Ich kann sie dann vielleicht nicht mehr so einfachbefüllen, aber die bisherigen Daten sind noch da.




Schreibe einen Kommentar