SSD Nodes Learn
Anleitungen Matt ConnorVon Matt Connor · Aktualisiert 2026-07-24

Claude API Tutorial: App auf Ubuntu VPS

Bauen Sie einen Python Log-Explainer auf Ubuntu 24.04. Lernen Sie Streaming, typisierte Exceptions und Kostenkontrolle für die Claude API direkt am VPS.

Was Sie erstellen

Ein Kommandozeilen-Tool auf einem frischen Ubuntu 24.04 VPS. Sie leiten eine Fehlermeldung oder einen Log-Ausschnitt hinein und erhalten eine Diagnose in natürlicher Sprache: journalctl -u nginx -n 50 | explain. Das Programm besteht aus etwa sechzig Zeilen Python und deckt alle Anforderungen einer echten Claude API Anwendung ab: einen korrekt gespeicherten Key, ein virtualenv, die Response-Strukturen des SDKs, Streaming, die typisierte Exception-Chain und eine systemd Unit für den autonomen Betrieb.

Ich habe dieses Projekt bewusst gewählt. Die meisten Tutorials für die "erste API Anwendung" führen zum Bau eines Chatbots, den man nie wieder öffnet. Ein Log-Explainer ist vom ersten Tag an auf einem Server nützlich. Er zwingt Sie dazu, zwei Dinge zu lernen, die Anfänger oft falsch machen: das korrekte Auslesen des Response-Objekts und die Kostenkontrolle. Die API berechnet die Kosten pro Token ohne Obergrenze, außer den von Ihnen gesetzten. Kostenkontrolle ist hier also ein Design-Parameter und kein nachträglicher Gedanke – dieselbe Disziplin ist erforderlich, wenn Sie Claude Code in tmux auf diesem VPS ausführen.

API-Key in der Console abrufen

Der API-Zugriff wird in der Anthropic Console unter platform.claude.com verwaltet. Registrieren Sie sich und erstellen Sie einen Key unter Settings → API Keys (der Link in der Dokumentation führt direkt zu platform.claude.com/settings/keys). Der Key wird nur einmal angezeigt, beginnt mit sk-ant- und kann nicht erneut abgerufen werden. Kopieren Sie ihn sofort oder löschen und erstellen Sie ihn neu.

Zur Preisgestaltung: Ab Juli 2026 gibt es keine dauerhafte kostenlose Nutzung (Free Tier) für die API. Laut der Preisgestaltung von Anthropic erhalten neue Benutzer ein kleines Kontingent an Gratis-Guthaben zum Testen. Die genaue Höhe hängt von der Anzeige in der Console bei der Registrierung ab. Sobald dieses Guthaben aufgebraucht ist, muss das Konto aufgeladen werden, damit Anfragen erfolgreich ausgeführt werden können. Dies ist unabhängig von einem claude.ai-Abonnement – ein Pro- oder Max-Plan enthält kein API-Guthaben, und ein API-Key schaltet die Chat-App nicht frei. Falls Sie zwischen einem Abonnement und der API abwägen: Dies ist ein separates Thema: welcher Claude-Plan Sie tatsächlich benötigen.

Erstellen Sie den Key mit einem eingeschränkten Scope für ein einzelnes Projekt oder einen Server. Wenn ein Key bekannt wird – und über einen langen Zeitraum wird dies passieren –, müssen Sie ihn widerrufen können, ohne andere Systeme zu beeinträchtigen.

Vermeiden Sie die Speicherung des Keys in .bashrc

Die reflexive Methode ist export ANTHROPIC_API_KEY=sk-ant-... in ~/.bashrc. Lassen Sie dies. Es ergeben sich drei separate Probleme:

  • Jeder Prozess erbt ihn. Eine in der Login-Shell exportierte Umgebungsvariable wird an alles weitergegeben, was Sie starten — die Web-App, der Crash-Reporter, der die Umgebung in einem Fehlerbericht speichert, oder die phpinfo()-Seite, die aktiviert wurde. Die Angriffsfläche des Keys umfasst dann "alles, was dieser Benutzer jemals ausführt".
  • Die Eingabe landet in ~/.bash_history. Wenn Sie den Befehl export einmal manuell ausführen, liegt Ihr Key dauerhaft in einer Klartextdatei und wird in jedes Backup Ihres Home-Verzeichnisses synchronisiert.
  • Er ist nicht verfügbar, wenn systemd ihn benötigt. Services lesen Ihre .bashrc nicht aus. Dieses Muster schlägt also genau dann fehl, wenn Sie das Skript in eine Unit umwandeln — meist als mysteriöser 401-Fehler um 6 Uhr morgens.

Das korrekte Muster auf einem Server ist eine dedizierte Environment-Datei mit 600-Berechtigungen, die nur von dem Prozess geladen wird, der sie benötigt:

sudo mkdir -p /opt/explain
sudo install -m 600 -o root -g root /dev/null /etc/claude-explain.env
printf 'ANTHROPIC_API_KEY=sk-ant-YOUR-KEY-HERE\n' | sudo tee /etc/claude-explain.env >/dev/null

Verwenden Sie tee über einen printf anstatt eines Editors, wenn Sie verhindern wollen, dass der Key in Editor-Swap-Files landet. Überprüfen Sie in jedem Fall mit ls -l /etc/claude-explain.env, ob die Datei -rw------- liest und root als Besitzer eingetragen ist. Interaktive Shells erhalten den Key pro Aufruf über einen Wrapper (siehe unten), und systemd erhält ihn über EnvironmentFile= — root liest die Datei, bevor die Privilegien reduziert werden, sodass der Service-User niemals Leseberechtigung benötigt. Der Key erscheint niemals im Code, in git, in ps-Ausgaben oder in der Shell-History.

Installen des SDK in einem venv

Ubuntu 24.04 wird mit Python 3.12 ausgeliefert, das PEP 668 erzwingt. Ein direkter pip install anthropic gegen den System-Interpreter schlägt daher mit error: externally-managed-environment fehl. Dieser Fehler ist ein beabsichtigtes Verhalten des Betriebssystems — verwenden Sie ein virtualenv:

sudo apt update && sudo apt install -y python3-venv
sudo python3 -m venv /opt/explain/venv
sudo /opt/explain/venv/bin/pip install anthropic

Auf einem Server ist keine Aktivierung erforderlich: Der direkte Aufruf von /opt/explain/venv/bin/python nutzt immer die Pakete des venv.

Erster Aufruf und korrektes Lesen der Antwort

import anthropic

client = anthropic.Anthropic()  # reads ANTHROPIC_API_KEY from the environment

response = client.messages.create(
    model="claude-opus-4-8",
    max_tokens=1000,
    messages=[{"role": "user", "content": "Explain what a systemd unit file is in three sentences."}],
)

for block in response.content:
    if block.type == "text":
        print(block.text)

Zwei Aspekte in diesen zwölf Zeilen sind entscheidend für das Verständnis der API. Erstens liest anthropic.Anthropic() ohne Argumente den Key aus den Umgebungsvariablen – übergeben Sie ihn niemals als String-Literal. Zweitens ist response.content eine Liste von Content-Blöcken und kein String. Wenn Sie sie direkt ausgeben, erhalten Sie die typische Fehlermeldung für Anfänger:

[TextBlock(citations=None, text='A systemd unit file is...', type='text')]

Dies ist kein Fehler, sondern die repr-Darstellung des Objekts. Antworten können mehrere Block-Typen enthalten (text, tool calls, thinking). Daher müssen Sie die Liste iterieren und block.type == "text" prüfen, bevor Sie auf .text zugreifen. Implementieren Sie diese Schleife von Beginn an, um Verwirrungen durch fehlerhafte Ausgaben zu vermeiden.

Verwenden Sie die exakte Model-ID claude-opus-4-8. IDs der aktuellen Generation enthalten kein Datum – ignorieren Sie die Gewohnheit (oder alte Blogposts), die Ihnen rät, ein Datums-Suffix anzuhängen; dies führt zu einem 404-Fehler, der unten beschrieben wird.

Das eigentliche Tool: Erklärung

Hier ist das vollständige Programm — Eingabe über stdin, Diagnose als Stream ausgegeben, Fehlerbehandlung integriert:

#!/usr/bin/env python3
"""explain: pipe an error or log excerpt in, get a diagnosis out."""
import sys
import anthropic

MODEL = "claude-opus-4-8"

def main() -> int:
    text = sys.stdin.read().strip()
    if not text:
        print("usage: journalctl -u nginx -n 50 | explain", file=sys.stderr)
        return 1

    client = anthropic.Anthropic()
    try:
        with client.messages.stream(
            model=MODEL,
            max_tokens=1500,
            system=(
                "You are a senior Linux sysadmin. The user pipes you server "
                "logs or error output. Name the most likely cause outright, "
                "then give the commands to confirm and fix it. Be terse."
            ),
            messages=[{"role": "user", "content": text}],
        ) as stream:
            for chunk in stream.text_stream:
                print(chunk, end="", flush=True)
        print()
    except anthropic.RateLimitError as e:
        retry_after = e.response.headers.get("retry-after", "60")
        print(f"rate limited; retry in {retry_after}s", file=sys.stderr)
        return 2
    except anthropic.APIStatusError as e:
        print(f"API error {e.status_code}: {e.message}", file=sys.stderr)
        return 2
    except anthropic.APIConnectionError:
        print("network error reaching the API", file=sys.stderr)
        return 2
    return 0

if __name__ == "__main__":
    sys.exit(main())

Speichern Sie dies als /opt/explain/explain.py und fügen Sie einen Wrapper hinzu, der den Key für die interaktive Nutzung lädt:

sudo tee /usr/local/bin/explain >/dev/null <<'EOF'
#!/bin/sh
set -a; . /etc/claude-explain.env; set +a
exec /opt/explain/venv/bin/python /opt/explain/explain.py "$@"
EOF
sudo chmod 755 /usr/local/bin/explain

(Der Wrapper muss über sudo ausgeführt werden oder die env-Datei muss einer Gruppe angehören, in der Ihr Admin-User Mitglied ist — wählen Sie eine dieser Optionen, anstatt die Berechtigungen auf 644 zu lockern.)

Warum Streaming. client.messages.stream gibt Tokens aus, sobald sie eintreffen, anstatt während der gesamten Generierung zu warten. Dies verhindert HTTP-Timeouts bei langen Ausgaben — das SDK lehnt sehr große max_tokens-Werte bei Non-Streaming-Aufrufen aus genau diesem Grund ab. Falls Sie das zusammengesetzte Objekt nachträglich benötigen, rufen Sie stream.get_final_message() innerhalb des with-Blocks auf.

Warum diese Reihenfolge der Ausnahmen. Das SDK wirft typisierte Exceptions, wobei die spezifischste zuerst genannt wird: RateLimitError entspricht einem 429-Fehler und enthält einen retry-after-Header, der die Wartezeit angibt; APIStatusError deckt andere Non-2xx-Antworten ab (prüfen Sie e.status_code >= 500 bei serverseitigen Problemen); APIConnectionError bedeutet, dass die Anfrage gar keine Antwort erhalten hat. Bevor Sie eine Retry-Schleife implementieren: Das SDK führt Retries für 429- und 5xx-Fehler bereits selbst aus, standardmäßig zweimal mit exponentiellem Backoff (max_retries auf Client-Seite). Wenn Ihr except ausgeführt wird, sind die Retries bereits verbraucht — die korrekte Vorgehensweise für ein CLI ist daher, den Fehler zu melden und das Programm zu beenden, anstatt zu warten und erneut Anfragen zu senden.

Kostenkontrolle

Dieser Abschnitt ist separat aufgeführt, da die API über keine integrierte monatliche Obergrenze hinaus der benutzerdefinierten Konfiguration verfügt und jeder Fehler hier die Kosten unbemerkt erhöht.

max_tokens ist die Ausgabegrenze pro Aufruf. Output-Token sind die teuerste Komponente — bei Opus 4.8 kosten sie das Fünffache des Input-Preises — und max_tokens ist die strikte Grenze für die Anzahl der produzierten Token. Ein fehlerhafter Prompt kann nicht mehr Output verursachen, als Sie erlaubt haben. Passen Sie die Größe der Aufgabe an: 1.500 Token reichen für eine Log-Diagnose aus; eine Klassifizierungsaufgabe benötigt 100. Wenn Antworten mit stop_reason: "max_tokens" mitten im Satz abbrechen, war die Grenze zu niedrig eingestellt — erhöhen Sie diesen Wert gezielt, anstatt ihn pauschal sehr hoch zu wählen.

Zählen vor dem Senden. Auch Input kostet Geld, und Logs sind umfangreich. Die API bietet einen kostenlosen Counting-Endpoint (dieser hat eigene Rate Limits, unabhängig von der Erstellung von Nachrichten):

count = client.messages.count_tokens(
    model="claude-opus-4-8",
    messages=[{"role": "user", "content": big_log_text}],
)
print(count.input_tokens)

Nutzen Sie diesen, um zu verhindern, dass versehentlich ein 2 GB großes Log-File an das Tool gesendet wird. Verwenden Sie tiktoken nicht hierfür — dies ist der Tokenizer von OpenAI; er unterschätzt die Claude-Token bei typischem Text um etwa 15–20 % und bei Code noch stärker.

Wählen Sie das Modell nach Aufgabe, nicht nach Markentreue. Stand Juli 2026 kostet Opus 4.8 (claude-opus-4-8) 5 $ pro Million Input-Token und 25 $ pro Million Output; Haiku 4.5 (claude-haiku-4-5) kostet 1 $/5 $ bei einem 200K Context; Sonnet 5 (claude-sonnet-5) liegt dazwischen bei 3 $/15 $, mit einem Einführungspreis von 2 $/10 $ bis zum 31. August 2026. Konkret: Ein 2.000-Token-Log-Ausschnitt mit einer 500-Token-Antwort kostet auf Opus etwa 0,0225 $ und auf Haiku 0,0045 $. Beginnen Sie mit Opus, während Sie die Qualität der Ausgaben bewerten, und testen Sie dieselben Prompts anschließend auf Haiku — bei einfachen Transformationen mit hohem Volumen ist das Ergebnis oft bei einem Fünftel des Preises ununterscheidbar. Überprüfen Sie die aktuellen Zahlen auf der Pricing-Seite, bevor Sie diese fest in ein Budget einplanen.

Batches für Aufgaben mit Zeitverzug. Die Batches API verarbeitet Anfragen asynchron zu 50 % der Standardpreise, und die meisten Batches sind innerhalb einer Stunde abgeschlossen. Nächtliche Zusammenfassungen, Backfills, Massenklassifizierungen — alles, was keine sofortige menschliche Antwort erfordert, gehört in die Batches.

Prompt Caching für wiederholten Kontext. Wenn jeder Aufruf denselben großen System-Prompt oder ein Runbook erneut sendet, markieren Sie diesen als cachebar:

response = client.messages.create(
    model="claude-opus-4-8",
    max_tokens=1000,
    system=[{
        "type": "text",
        "text": RUNBOOK_TEXT,  # the same 30K tokens on every call
        "cache_control": {"type": "ephemeral"},
    }],
    messages=[{"role": "user", "content": question}],
)
print(response.usage.cache_read_input_tokens)  # non-zero from the second call on

Cache-Writes kosten etwa das 1,25-fache des Input-Preises, Cache-Reads etwa das 0,1-fache bei einer TTL von 5 Minuten — der zweite Aufruf innerhalb des Zeitfensters ist also bereits durch den ersten gedeckt. Es gibt zwei Fallstricke. Der gecachte Präfix muss ein modellspezifisches Minimum erreichen — einige tausend Token bei Opus — daher wird ein kurzer System-Prompt nicht automatisch gecacht. Und wenn cache_read_input_tokens bei identischen Aufrufen bei Null bleibt, ändert sich etwas in Ihrem Präfix bei jeder Anfrage (ein Zeitstempel ist hierfür die häufigste Ursache).

Beachten Sie, was als Input zählt. System-Prompts, Tool-Definitionen und — bei mehrstufigen Konversationen — der gesamte Verlauf, der in jedem Schritt erneut gesendet wird, werden alle als Input-Token berechnet. Eine Chat-Schleife, die den Verlauf nie kürzt, verursacht quadratisch steigende Kosten. Die vollständige Abrechnungslogik sollte verstanden werden, bevor Sie konversationelle Anwendungen entwickeln: wie sich die Claude-Token-Nutzung und Abrechnung tatsächlich zusammensetzen.

Ausführung unter systemd

Der Vorteil der Verwendung von environment-files: Ein Timer, der jeden Morgen eine Zusammenfassung der Fehler von gestern erstellt.

# /etc/systemd/system/log-digest.service
[Unit]
Description=Daily error-log digest via the Claude API

[Service]
Type=oneshot
User=explain
Group=systemd-journal
EnvironmentFile=/etc/claude-explain.env
ExecStart=/bin/sh -c 'journalctl -p err --since yesterday | /opt/explain/venv/bin/python /opt/explain/explain.py >> /var/log/log-digest.txt'
# /etc/systemd/system/log-digest.timer
[Unit]
Description=Run the log digest every morning

[Timer]
OnCalendar=06:15
Persistent=true

[Install]
WantedBy=timers.target
sudo useradd -r -s /usr/sbin/nologin explain
sudo touch /var/log/log-digest.txt && sudo chown explain /var/log/log-digest.txt
sudo systemctl daemon-reload
sudo systemctl enable --now log-digest.timer
sudo systemctl start log-digest.service   # test it once, right now

Beachten Sie den Vorteil von EnvironmentFile=: systemd liest die Datei mit Root-Besitz und Mode-600, bevor der Wechsel zum unprivilegierten Benutzer explain erfolgt. Dadurch erhält der Prozess die Variable, während der Benutzer die Key-Datei nicht lesen kann. Die Gruppe systemd-journal gewährt den Zugriff auf die Logs. Testen Sie dies mit einem manuellen systemctl start und lesen Sie journalctl -u log-digest.service — warten Sie nicht bis 06:15 Uhr, um einen Tippfehler zu finden. Wenn dieses Muster komplexer als eine Shell-Pipeline wird, lässt sich derselbe Ansatz (Key in environment-file) direkt auf Claude-gestützte n8n-Workflows auf demselben System übertragen.

Fehlerursachen und die entsprechenden Fehlermeldungen

401 bei einem funktionierenden Key. Die Fehlermeldung lautet:

anthropic.AuthenticationError: Error code: 401 - {'type': 'error', 'error': {'type': 'authentication_error', 'message': 'invalid x-api-key'}, 'request_id': 'req_011CSHoEeqs5C35K2UUqR7Fy'}

Wenn der Key in Ihrer Shell funktioniert, der Dienst aber mit 401 antwortet, wurde der Key nicht an den Dienst übermittelt. Beachten Sie, dass systemd .bashrc nicht ausliest; prüfen Sie, ob EnvironmentFile= auf den korrekten Pfad zeigt. Weitere Ursachen: Anführungszeichen in der env-Datei (ANTHROPIC_API_KEY="sk-ant-..." — systemd entfernt Anführungszeichen, aber der . file Ihres Shell-Wrappers behält sie im Wert, falls die Anführungszeichen falsch gesetzt wurden), abschließende Leerzeichen oder ein Key, der letzte Woche in der Console widerrufen wurde.

404 durch einen Tippfehler beim Modell. Die häufigste Variante ist die Verwendung eines Datums-Suffixes bei einer aktuellen Modell-ID:

anthropic.NotFoundError: Error code: 404 - {'type': 'error', 'error': {'type': 'not_found_error', 'message': 'model: claude-opus-4-8-20260115'}, 'request_id': 'req_011CSJqymAvNw4bT3qmDdMbA'}

IDs der aktuellen Generation sind exakt so zu schreiben wie angegeben — claude-opus-4-8, claude-haiku-4-5, claude-sonnet-5. Kopieren Sie diese aus der Modell-Dokumentation und nicht aus dem Gedächtnis oder aus alten Tutorials.

429 rate_limit_error. Der Fehlertyp-String ist rate_limit_error und die Response enthält einen retry-after Header mit der Wartezeit in Sekunden. Das SDK hat bereits zwei Retries mit Backoff durchgeführt, bevor die Exception erscheint. Anhaltende 429-Fehler bedeuten, dass Ihre dauerhafte Rate Ihr Kontingent tatsächlich überschreitet — fassen Sie die Aufgaben in Batches zusammen oder verteilen Sie sie zeitlich, anstatt die Retry-Schleife zu verkürzen.

Es wird das Objekt statt des Textes ausgegeben. Die Ausgabe sieht aus wie [TextBlock(citations=None, text='...', type='text')]. Sie haben response.content ausgegeben, anstatt die Blöcke zu iterieren und .text aus denen zu lesen, bei denen block.type == "text" vorliegt. Jedes SDK-Beispiel oben führt dies korrekt aus; kopieren Sie die Schleife.

error: externally-managed-environment. Sie haben pip install gegen das System-Python von Ubuntu 24.04 ausgeführt. Verwenden Sie ein venv — nutzen Sie niemals --break-system-packages auf einem Server, dessen Stabilität wichtig ist.

Abgebrochene Antworten. response.stop_reason == "max_tokens" bedeutet, dass das Modell das Output-Limit während der Generierung erreicht hat. Dies entspricht dem Design; erhöhen Sie das Limit gezielt.

Sobald Ihre erste App funktioniert, ermöglicht der Aufbau eines AI-Agents mit Claude die Umwandlung dieser API-Aufrufe in einen Agenten, der Tools nutzt.

FAQ

Wie hoch sind die Kosten für einen Test der Claude API?

Die Kosten sind für ein solches Tool sehr gering. Stand Juli 2026 kostet Opus 4.8 $5 pro Million Input-Token und $25 pro Million Output-Token. Eine typische Log-Diagnose — einige tausend Token als Input, einige hundert als Output — kostet etwa zwei Cent. Bei Haiku 4.5 ($1/$5) liegen die Kosten bei unter einem halben Cent. Ein Monat mit täglichen Zusammenfassungen kostet weniger als ein Kaffee. Das Risiko liegt nicht im Preis pro Aufruf, sondern in Endlosschleifen und unbegrenzten max_tokens. Deshalb werden beide Werte in diesem Guide explizit festgelegt.

Gibt es eine kostenlose Version der Claude API?

Stand Juli 2026 gibt es keine dauerhafte kostenlose Version. Laut der Preisdokumentation von Anthropic erhalten neue Benutzer ein kleines Kontingent an Gratis-Guthaben zum Testen der API — ein einmaliger Testlauf, dessen genauer Betrag in der Console bei der Registrierung angezeigt wird — danach muss das Konto aufgeladen werden. Wenn das Ziel Grenzkosten von Null pro Anfrage statt höchster Qualität ist, ist die Alternative die Selbsthostung eines Open-Weight-Modells mit Ollama, wobei RAM statt Token bezahlt wird.

Wie schütze ich meinen API-Key auf einem Server?

Niemals im Code, niemals in git, niemals über .bashrc exportieren und niemals in eine Shell eingeben, in der die Historie ihn speichert. Speichern Sie den Key in einer Datei, die dem Root-User gehört und 600-Berechtigungen hat. Laden Sie den Key pro Prozess — ein Wrapper-Skript für die interaktive Nutzung, EnvironmentFile= für systemd — und verwenden Sie pro Server oder Projekt nur einen Key. So ist das Widerrufen eines kompromittierten Keys ein gezielter Eingriff und keine Amputation. Wenn der Key jemals auf einer Paste-Seite oder in einem Git-Commit erscheint, widerrufen Sie ihn sofort in der Console; das Löschen des Commits verhindert das Leck nicht.

Mit welchem Claude-Modell sollte ich beginnen?

Beginnen Sie mit claude-opus-4-8, während Sie bewerten, ob die Ausgaben für eine Weiterentwicklung ausreichen. Sie müssen die Idee bei voller Qualität beurteilen; bei geringem Volumen ist der Kostenunterschied minimal. Sobald der Prompt steht, führen Sie Ihre realen Inputs mit claude-haiku-4-5 aus; für Zusammenfassungen, Klassifizierungen und Log-Triage ist es oft genauso gut wie bei einem Fünftel des Preises. Wechseln Sie basierend auf Messwerten zu Haiku oder Sonnet, nicht standardmäßig.