Lokale LLMs sind einfach zu benutzen – allerdings mit der Einschränkung, dass der Nutzer am gleichen Rechner arbeiten muss, wo auch das LLM läuft. Natürlich, daher heißt es auch lokales LLM.

Aber was, wenn ich gerne die Datensicherheit eines lokalen LLM haben möchte, auch wenn ich mal ohne meinen Rechner unterwegs bin?

Das Problem ist: Fähige Modelle benötigen Rechenleistung in solchem Maße wie es weder ein durchschnittlicher Homeserver noch ein Smartphone haben. In meinem Falle ist tatsächlich nur mein Arbeitsnotebook leistungsfähig genug, ein 70b Modell zu betreiben.

Wer also sein eigenes LLM hosten und von überall nutzen möchte, kommt aktuell nicht drum herum, sich ein wenig Gedanken um das Setup zu machen. Der Gedanke, ein selbst gehostetes LLM immer und überall nutzen zu können, und die Sicherheit zu haben, dass eingegebene Daten niemals die eigene Infrastruktur verlassen, haben mich angetrieben, solch ein Setup aufzusetzen. Darum soll es in diesem Beitrag gehen – und Spoiler: OpenWebUI als HomeScreen-App auf dem Smartphone kommt schon sehr nah an die ChatGPT UX ran :)

Wir kümmern uns also um folgende Grundprobleme:

Übersicht des Setups

Diagram showing a MacBook connected to a server via VPN. The server uses Traefik to route requests to a web service, 'https://myai.cool.domain', and a specified fallback API. Labeled paths illustrate these connections.
Gesamtübersicht des Setups

Im Allgemeinen ist das Setup so aufgebaut, dass ein fester Server für das Ausliefern der öffentlichen Oberfläche und API verantwortlich ist. Diese Oberfläche (samt API) wird mit OpenWebUI realisiert. Das LLM allerdings läuft auf dem einzigen Rechner mit genug Ressourcen, den ich besitze, und das ist ein mobiles MacBook.

Auf dem MacBook ist Ollama so eingerichtet, dass es automatisch beim Booten gestartet wird, und auch Anfragen aus dem Netzwerk (VPN) annimmt. Die Verbindung zwischen MacBook und Server wird per VPN realisiert. Solange das MacBook also eingeschaltet ist, und mit dem Internet verbunden ist, kann OpenWebUI über das VPN die LLM auf dem MacBook benutzen.

Das Praktische ist, dass OpenWebUI die Anbindung mehrerer LLM-Provider erlaubt. Es wäre also denkbar, Fallbacks zu implementieren, falls das eigene Gerät mal nicht eingeschaltet sein sollte.


Wesentliche Schritte

Wir schauen uns hier einmal Schritt für Schritt an, was alles für dieses Setup eingerichtet werden muss:

Wireguard VPN zwischen MacBook und Server aufsetzen

1. Server-Konfiguration (Ubuntu):

sudo apt update
sudo apt install wireguard

Erstelle den privaten und öffentlichen Schlüssel:

wg genkey | tee privatekey | wg pubkey > publickey

Beispielkonfiguration /etc/wireguard/wg0.conf:

[Interface]
PrivateKey = <ServerPrivateKey>

Address = 10.0.0.1/24

ListenPort = 51820


[Peer]
PublicKey = <MacBookPublicKey>

AllowedIPs = 10.0.0.2/32

Sollte der Server hinter einer Firewall stehen, müssen wir spätestens jetzt noch dafür sorgen, dass der Server eingehende UDP-Datenpakete auf Port 51820 akzeptiert.

Dann Wireguard starten und aktivieren:

sudo systemctl enable wg-quick@wg0
sudo systemctl start wg-quick@wg0

2. MacBook-Konfiguration:

Installiere die Wireguard-App aus dem AppStore. Erstelle eine neue Konfiguration:

[Interface]
PrivateKey = <MacBookPrivateKey>

Address = 10.0.0.2/24


[Peer]
PublicKey = <ServerPublicKey>

Endpoint = <your.server.com>:51820

AllowedIPs = 10.0.0.0/24

PersistentKeepalive = 25

Sobald die Verbindung steht, sollte das MacBook unter der IP 10.0.0.2 aus Sicht des Servers erreichbar sein.


Ollama auf dem MacBook aufsetzen

Die Installation von Ollama kann entweder mit Homebrew gemacht werden:

brew install --cask ollama

… oder ihr ladet Ollama als Mac App von der Website herunter.

Automatischer Start mit launchctl:

Nun müssen wir dafür sorgen, dass Ollama bei jedem Start des Rechners mit den richtigen Einstellungen geladen wird.

Dafür erstellt ihr folgende Datei: ~/Library/LaunchAgents/com.user.ollama.plist

Der Inhalt sieht so aus:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.user.ollama</string>

    <key>ProgramArguments</key>
    <array>
        <string>/usr/local/bin/ollama</string>
        <string>serve</string>
    </array>

    <key>EnvironmentVariables</key>
    <dict>
        <key>OLLAMA_HOST</key>
        <string>0.0.0.0</string>
        <key>OLLAMA_CONTEXT_LENGTH</key>
        <string>10240</string>
        <key>OLLAMA_KEEP_ALIVE</key>
        <string>60m0s</string>
        <key>OLLAMA_NEW_ENGINE</key>
        <string>false</string>
    </dict>

    <key>RunAtLoad</key>
    <true/>

    <key>KeepAlive</key>
    <true/>

    <key>StandardOutPath</key>
    <string>/tmp/ollama.out</string>
    <key>StandardErrorPath</key>
    <string>/tmp/ollama.err</string>
</dict>
</plist>

OLLAMA_HOST belegen wir mit 0.0.0.0, damit Ollama nicht nur per localhost, sondern auch über die sonstigen IPs des Rechners erreichbar ist, also auch über die IP die der Rechner im VPN hat.

OLLAMA_CONTEXT_LENGTH bestimmt die maximale Kontextlänge

OLLAMA_KEEP_ALIVE bestimmt wie lange ein Modell nach Nutzung im Speicher geladen bleibt

OLLAMA_NEW_ENGINE entscheidet ob die neue Engine zum Laden von Modellen verwendet werden soll. Diese soll Vorteile bei der Ladegeschwindigkeit und dem Speicherverbrauch haben, funktioniert aber noch nicht mit jedem Modell. Mistral Small 3.1 funktionierte bei mir Stand heute z.B. nur mit der alten Engine.

Jetzt können wir Ollama mit folgendem Befehl starten, und launchctl sorgt dafür, dass dies auch jedes Mal automatisch passiert, wenn ihr euch auf eurem MacBook einloggt.

launchctl load ~/Library/LaunchAgents/com.user.ollama.plist

Bis hier haben wir schon viel geschafft! Unser Macbook und der Server sind per VPN verbunden, und der Server kann über das VPN auf unser Ollama zugreifen. Jetzt brauchen wir „nur” noch die Oberfläche mit der wir unser LLM nutzen wollen. Dies sehen wir im nächsten Abschnitt.


OpenWebUI per Docker hinter Traefik aufsetzen

Installiere Docker und docker-compose.

docker-compose.yml:

services:

  openwebui:

    image: ghcr.io/open-webui/open-webui:latest

    restart: always

    environment:

      - 'OLLAMA_BASE_URL=http://10.0.0.2:11434' # VPN-IP und Port für Ollama auf dem MacBook

    labels:

      - "traefik.enable=true"

      - "traefik.http.services.ai-web.loadbalancer.server.port=8080"

      - "traefik.http.routers.ai-web.rule=Host(`myai.cool.domain`)"

      - "traefik.http.routers.ai-web.entrypoints=websecure"

      - "traefik.http.routers.ai-web.tls.certresolver=letsencrypt"

    networks:

      - web

    volumes:

      - openwebui-data:/app/backend/data


networks:

  web:

    external: true


volumes:

  openwebui-data:

Traefik muss natürlich entsprechend konfiguriert sein – etwa mit einem docker-compose.yml, das Port 443 bereitstellt, ACME aktiviert hat und die web-Netzwerk-Bridge nutzt.

Mit docker-compose up -d ist die OpenWebUI dann öffentlich erreichbar – durch Traefik geschützt und mit HTTPS versehen. Die Authentifizierung erfolgt durch die OpenWebUI selbst.


Fazit

Mit etwas initialem Aufwand lässt sich ein selbstgehostetes LLM-Setup aufbauen, das nahezu dieselbe Usability wie ChatGPT, Claude und Konsorten bietet – und dabei volle Kontrolle über die Daten und Infrastruktur ermöglicht. Dank OpenWebUI wirkt das Frontend professionell und mobilfreundlich, während Wireguard für eine stabile, sichere Verbindung zwischen mobilem LLM-Host und öffentlicher Oberfläche sorgt.

Ich hoffe das Setup ist für euch nützlich, oder inspiriert euch zu neuen Ideen!