← Zurück zu allen Beiträgen
Mobilithek mTLS Go

Mobilithek über mTLS abrufen — eine funktionierende Schritt-für-Schritt-Anleitung

1. Mai 2026 · 9 Min. Lesezeit

Mobilithek ist Deutschlands National Access Point — der Bundes-Hub für Verkehrs-, Mobilitäts- und AFIR-Ladedaten, betrieben von T-Systems im Auftrag des BMDV. Seit der operativen Stilllegung des MDM (Mobility Data Marketplace) in H1 2025 ist Mobilithek der kanonische Einstiegspunkt für jede produktive Mobilitätsintegration in Deutschland. Ab dem 14. April 2026 ist DATEX II das verbindliche Austauschformat.

Die meisten öffentlichen APIs nutzen API-Schlüssel. Mobilithek nicht. Sie verwendet eine TLS-Client-Zertifikat-Authentifizierung (mTLS): Ihr Client präsentiert während des TLS-Handshakes ein X.509-Zertifikat, und der Broker entscheidet, ob Sie abrufen oder Push-Daten erhalten dürfen.

Das bringt fast jeden bei der ersten Integration ins Stolpern. Es gibt keinen Authorization: Bearer ...-Header. Es gibt keinen API-Schlüssel. Wenn der TLS-Handshake fehlschlägt, erhalten Sie einen generischen Verbindungsfehler und einen langen Debugging-Nachmittag. Hier ist die funktionierende Anleitung, die wir uns selbst gewünscht hätten.

1. Mobilithek-Konsumentenkonto beantragen

Antrag stellen unter mobilithek.info/registration-request. Sie geben an:

Für eine typische NAP-Integration brauchen Sie ein Konsumentenkonto. Konsumenten öffentlicher Daten zahlen nichts; bei kommerziellen Daten kann je nach Anbieter eine Gebühr anfallen. Die Bereitstellung dauert einige Tage.

2. Zertifikat erzeugen

Nach Freigabe können Sie in der Admin-Komponente einen Certificate Signing Request (CSR) hochladen und das ausgestellte Zertifikat herunterladen. Erzeugen Sie das Schlüsselpaar lokal:

# 1. 4096-Bit RSA-Privatschlüssel erzeugen
openssl genrsa -out mobilithek.key 4096

# 2. CSR erstellen. Der CN muss zum hinterlegten Organisationsnamen passen.
openssl req -new -key mobilithek.key -out mobilithek.csr \
  -subj "/CN=YourOrgName/O=YourOrg/C=DE"

# 3. mobilithek.csr in der Mobilithek-Admin-Komponente hochladen.
# 4. Ausgestelltes Zertifikat als mobilithek.crt herunterladen

Sie benötigen außerdem das Mobilithek-Root-CA und alle Intermediate-CAs, um die Server-Seite des Handshakes zu verifizieren.

3. Dateilayout

Auf dem Anwendungsserver legen Sie die Dateien etwa so ab:

/etc/napspan/mobilithek/
├── client.crt   # das für Sie ausgestellte Zertifikat
├── client.key   # der Privatschlüssel (chmod 600)
└── ca.pem       # Mobilitheks CA-Bundle für Server-Verifikation

Berechtigungen sind wichtig: Der Privatschlüssel sollte chmod 600 haben und dem Benutzer gehören, unter dem der Worker-Prozess läuft. Verschlüsselte Schlüssel gehören nicht in die Produktion — der Worker würde bei jedem Start nach einer Passphrase fragen. Wenn Sie Verschlüsselung at rest brauchen, verschlüsseln Sie das Volume, nicht die Datei.

Verweisen Sie auf diese Pfade über Umgebungsvariablen, damit das Binary keine Geheimnisse enthält:

MOBILITHEK_CERT_PATH=/etc/napspan/mobilithek/client.crt
MOBILITHEK_KEY_PATH=/etc/napspan/mobilithek/client.key
MOBILITHEK_CA_PATH=/etc/napspan/mobilithek/ca.pem

4. Das Broker-URL-Muster

Jeder Datensatz auf Mobilithek hat eine numerische Publikations-ID. Das Broker-URL-Muster lautet:

https://mobilithek.info:8443/mobilithek/api/v1.0/publication/<Publikations-ID>

Beachten Sie den nicht-standardmäßigen Port 8443. Das ist der mTLS-geschützte Endpunkt — Standard-Port 443 ist nur für die öffentliche Website. Pull-Modus heißt: Sie holen die Broker-URL planmäßig per GET ab. Push-Modus heißt: Sie melden in der Admin-Komponente einen eigenen Service-Endpunkt an, und der Broker schickt POST-Requests an Sie, sobald die Publikation aktualisiert wird — Sie antworten mit einer Bestätigung. Beide Modi nutzen denselben v1.0-API-Root.

5. Ein funktionierender Go-Client

Hier der minimale Go-Client, den wir zum Abrufen einer Mobilithek-Publikation einsetzen. Er baut eine tls.Config mit Client-Zertifikat und CA-Pool, hängt sie an einen http.Transport und teilt sich einen Client über alle Mobilithek-Anfragen.

package mobilithek

import (
    "crypto/tls"
    "crypto/x509"
    "fmt"
    "io"
    "net/http"
    "os"
    "time"
)

func NewClient(certPath, keyPath, caPath string) (*http.Client, error) {
    cert, err := tls.LoadX509KeyPair(certPath, keyPath)
    if err != nil {
        return nil, fmt.Errorf("load client cert: %w", err)
    }
    caPEM, err := os.ReadFile(caPath)
    if err != nil {
        return nil, fmt.Errorf("read ca: %w", err)
    }
    pool := x509.NewCertPool()
    if !pool.AppendCertsFromPEM(caPEM) {
        return nil, fmt.Errorf("parse ca pem")
    }
    transport := &http.Transport{
        TLSClientConfig: &tls.Config{
            Certificates: []tls.Certificate{cert},
            RootCAs:      pool,
            MinVersion:   tls.VersionTLS12,
        },
        MaxIdleConns:        20,
        IdleConnTimeout:     90 * time.Second,
        TLSHandshakeTimeout: 10 * time.Second,
    }
    return &http.Client{
        Transport: transport,
        Timeout:   60 * time.Second,
    }, nil
}

func FetchPublication(c *http.Client, pubID string) ([]byte, error) {
    url := fmt.Sprintf(
        "https://mobilithek.info:8443/mobilithek/api/v1.0/publication/%s",
        pubID,
    )
    req, err := http.NewRequest("GET", url, nil)
    if err != nil {
        return nil, err
    }
    req.Header.Set("Accept", "application/xml")
    req.Header.Set("User-Agent", "NAPSPAN/1.0")

    resp, err := c.Do(req)
    if err != nil {
        return nil, fmt.Errorf("mobilithek request: %w", err)
    }
    defer resp.Body.Close()

    body, err := io.ReadAll(resp.Body)
    if err != nil {
        return nil, err
    }
    if resp.StatusCode != 200 {
        return nil, fmt.Errorf("mobilithek %d: %s", resp.StatusCode, string(body))
    }
    return body, nil
}

Das Ergebnis ist ein DATEX-II-XML-Dokument — meist eine SituationPublication oder eine VmsTablePublication, je nach abgerufener Publikations-ID. Übergeben Sie es Ihrem DATEX-II-Parser und der Auth-Teil ist erledigt.

6. Häufige Fehlerbilder

„Connection reset" oder „EOF" direkt nach ClientHello

Fast immer ein Zertifikatsproblem. Der Broker lehnt den Handshake ohne TLS-Alert ab. Triage:

  1. Verifizieren, dass das Zertifikat für diese Umgebung ausgestellt ist (Mobilithek vergibt unterschiedliche Zertifikate für Staging und Produktion).
  2. Verifizieren, dass das Zertifikat nicht abgelaufen ist. Erneuerungen sind manuell; an Tag 1 nach Ablauf erinnert Sie niemand.
  3. openssl s_client -connect mobilithek.info:8443 -cert client.crt -key client.key -CAfile ca.pem ausführen und die Handshake-Ausgabe lesen.

HTTP 403 nach erfolgreichem Handshake

Die TLS-Schicht hat Sie akzeptiert, aber der Broker autorisiert dieses Zertifikat nicht für die angefragte Publikations-ID. Entweder haben Sie diese Publikation nicht in der Admin-Komponente abonniert, oder Ihr Abo wurde widerrufen. Prüfen im Konsumenten-Dashboard.

HTTP 410 Gone

Die Publikation wurde stillgelegt. Manchmal werden Datensätze auf eine neue Publikations-ID migriert — besonders während der MDM-zu-Mobilithek-Übergangsphase 2025. Im Publikationskatalog nachsehen.

Veraltete Daten trotz HTTP 200

Mobilithek cached einige Publikationen hinter einem CDN. Den Last-Modified-Header prüfen und Parsen überspringen, wenn er sich nicht bewegt hat. Aber nicht als alleinige Wahrheit verwenden — manche Anbieter aktualisieren ihn nicht korrekt.

7. Rate-Limits und Höflichkeit

Mobilithek veröffentlicht keine harten Rate-Limits, in der Praxis gilt:

8. Was Sie zurückbekommen

Eine typische Vorfalls-Publikation sieht etwa so aus:

<d2:payloadPublication
    xsi:type="d2:SituationPublication"
    lang="de"
    xmlns:d2="http://datex2.eu/schema/2/2_0">
  <d2:publicationTime>2026-05-01T08:34:00Z</d2:publicationTime>
  <d2:publicationCreator>
    <d2:country>de</d2:country>
    <d2:nationalIdentifier>DE-Mobilithek</d2:nationalIdentifier>
  </d2:publicationCreator>
  <d2:situation id="DE_BAB7_4711">
    <d2:situationRecord
        xsi:type="d2:Accident"
        id="DE_BAB7_4711_R1"
        version="3">
      <d2:situationRecordVersionTime>2026-05-01T08:30:00Z</d2:situationRecordVersionTime>
      ...
    </d2:situationRecord>
  </d2:situation>
</d2:payloadPublication>

Die SituationRecords parsen, Felder auf Ihr normalisiertes TrafficEvent mappen, persistieren und gegen den letzten Fetch differenzieren, um Lebenszyklus-Änderungen zu protokollieren — neuer Schweregrad, neue geschätzte Endzeit, Archivierung.

9. Wie das in NAPSPAN passt

Mobilithek ist einer von 30+ NAPs, die NAPSPAN aggregiert. Der oben beschriebene mTLS-Handshake ist in einem einzigen mobilithekClient gekapselt, der über alle Adapter-Ressourcen geteilt wird — Events, AFIR-Ladestationen, Parkplätze, Wetter. Eine neue Mobilithek-Publikation hinzuzufügen ist eine Zeile:

Register("mobilithek", "afir_charging", fetchMobilithekAFIR)

Die Fetch-Funktion nutzt den geteilten Client, ruft FetchPublication mit der richtigen Publikations-ID auf, übergibt das XML an den DATEX-II-Parser und gibt normalisierte Features zurück. Dieselbe FetchFunc-Signatur wie die übrigen NAPs — der Scheduler weiß und interessiert sich nicht dafür, dass dieser hier ein TLS-Client-Zertifikat braucht.

Ohne eigene Zertifikate ausprobieren

Wenn Sie deutsche Autobahndaten nutzen wollen, ohne ein eigenes Mobilithek-Konto aufzubauen, ist genau das, was NAPSPAN löst — wir pflegen die Zertifikate, die Parser und das Lebenszyklus-Tracking und liefern das Ergebnis über einen normalen API-Schlüssel über klassisches HTTPS:

curl "https://api.napspan.com/api/v1/events?country=DE&status=active" \
  -H "X-API-Key: your_key"

Mobilitheks mTLS-Flow ist gut entworfen, sobald die Bausteine sitzen — nur das Fehlen einer durchgängigen, funktionierenden Anleitung macht die erste Integration schmerzhaft. Wenn dieser Beitrag Ihnen einen Debugging-Nachmittag erspart hat, würden wir uns über eine Rückmeldung freuen.

Bereit, NAPSPAN auszuprobieren?

14 Tage kostenlos. Keine Zertifikate zu verwalten. EU 27 + UK + EFTA, normalisiert.

Kostenlosen API-Schlüssel sichern Karte erkunden