OpenCode 2.1 als Docker-Server mit lokalem Ollama-Modell betreiben
OpenCode 2.1 per Docker Compose mit Ollama betreiben: Server mit Weboberfläche und Basic Auth, Provider-Konfiguration für ein lokales Modell, Agentenauftrag auf CPU, Backup und Restore der Sitzungsdatenbank, Update von 2.1.2 auf 2.1.3 und echte Fehlerbilder aus dem Test.
Geprüft am 23.10.2026 · für OpenCode 2.1.3
WerbelinksMit * markierte Links sind Werbelinks: Bei einem Kauf erhalten wir eine Provision, der Preis bleibt gleich. Als Amazon-Partner verdiene ich an qualifizierten Verkäufen. Mehr dazu

OpenCode ist ein quelloffener Coding-Agent unter MIT-Lizenz, der Dateien liest, schreibt und Befehle ausführt. Mit über 220.000 Sternen auf GitHub gehört das Projekt zu den meistbeachteten Entwicklerwerkzeugen. Seit Version 2.1 liefert der eingebaute Server eine Weboberfläche mit. So läuft OpenCode headless im Heimnetz oder Firmen-LAN, und das Modell kommt aus einem lokalen Ollama statt aus einer Cloud-API. Diese Anleitung zeigt Aufbau, Passwortschutz, Backup mit Restore, Update und die Fehler aus dem Test.
Voraussetzungen
Der OpenCode-Container belegte im Test nur rund 170 MB RAM, den Bedarf bestimmt das Modell:
- Linux-Server oder Mini-PC mit x86_64 oder ARM64 (das Image gibt es für beide), mindestens 4, besser 8 CPU-Kerne.
- 16 GB RAM für
qwen3:4bauf CPU: Ollama belegte mit 16.384 Token Kontext und zwei geladenen Modellen knapp 8 GB,qwen3:4ballein 5,1 GB. - Rund 15 GB freien Speicher: Das Ollama-Image ist 8,4 GB groß,
qwen3:4b2,5 GB,qwen2.5-coder:3b1,9 GB, das OpenCode-Image knapp 400 MB. - Optional eine GPU mit 8 GB VRAM oder mehr: deutlich schnellere Antworten und Platz für Modelle mit 7 bis 14 Milliarden Parametern.
- Docker Engine mit Docker Compose Plugin, etwa auf Debian 12 oder Ubuntu 24.04. Die Grundinstallation beschreibt die Anleitung Docker Compose unter Linux als Selfhosting-Grundlage.
Getestet wurde auf einem Intel Core i7-12700T ohne GPU mit OpenCode 2.1.2 und 2.1.3 sowie Ollama 0.40.8.
Eckdaten
| Punkt | Wert |
|---|---|
| Image OpenCode | ghcr.io/anomalyco/opencode:2.1.3 (Tags ohne führendes v) |
| Image Ollama | ollama/ollama:0.40.8 |
| Port | 4096/TCP (Weboberfläche und API) |
| Volumes | ./projekt:/workspace, ./config:/root/.config/opencode, opencode-data:/root/.local/share/opencode, opencode-cache, ollama |
| Umgebung | OPENCODE_SERVER_PASSWORD (Benutzername fest opencode) |
| Modell im Test | qwen3:4b (Q4_K_M, 2,5 GB), CPU-Betrieb |
| Lizenz | MIT |
Schritt 1: OpenCode 1.x und 2.x unterscheiden
OpenCode 2 erscheint auf npm als @opencode/cli (2.1.3 vom 22. Oktober 2026), OpenCode 1 weiter als opencode-ai (1.19.4). Das Image ghcr.io/anomalyco/opencode führt beide als Tags. Die Befehle unterscheiden sich:
- In 1.x startet
opencode webdie Weboberfläche,opencode servenur die API. Die Healthcheck-Route heißt/global/health. - In 2.x gibt es
webnicht mehr.opencode serveliefert Weboberfläche und API zusammen aus, die API liegt unter/api/…, die OpenAPI-Beschreibung unter/openapi.json.
Die Server-Doku beschreibt teils noch 1.x. Diese Anleitung nutzt 2.1.3:
docker run --rm ghcr.io/anomalyco/opencode:2.1.3 --version
docker run --rm ghcr.io/anomalyco/opencode:1.19.4 --version
Verifizieren: Die Befehle geben opencode v2.1.3 beziehungsweise 1.19.4 aus.
Schritt 2: Projektordner, Compose-Datei und Passwort anlegen
Legen Sie einen Ordner mit den Unterordnern config (Konfiguration) und projekt (Arbeitsverzeichnis des Agenten) an und erzeugen Sie ein zufälliges Passwort:
mkdir -p /opt/opencode/{config,projekt} && cd /opt/opencode
printf 'OPENCODE_TAG=2.1.3\nOC_PASSWORD=%s\n' "$(openssl rand -base64 24)" > .env
chmod 600 .env
Die compose.yaml:
services:
ollama:
image: ollama/ollama:0.40.8
restart: unless-stopped
environment:
OLLAMA_CONTEXT_LENGTH: "16384"
OLLAMA_KEEP_ALIVE: "30m"
volumes:
- ollama:/root/.ollama
healthcheck:
test: ["CMD", "ollama", "list"]
interval: 30s
timeout: 10s
retries: 5
opencode:
image: ghcr.io/anomalyco/opencode:${OPENCODE_TAG}
restart: unless-stopped
command: ["serve", "--hostname", "0.0.0.0", "--port", "4096"]
working_dir: /workspace
environment:
OPENCODE_SERVER_PASSWORD: ${OC_PASSWORD}
ports:
- "4096:4096"
volumes:
- ./projekt:/workspace
- ./config:/root/.config/opencode
- opencode-data:/root/.local/share/opencode
- opencode-cache:/root/.cache/opencode
depends_on:
ollama:
condition: service_healthy
volumes:
ollama:
opencode-data:
opencode-cache:
Wichtig dabei:
- Der Entrypoint des Images ist
opencode, daher der Befehlserve.--hostname 0.0.0.0ist nötig, Standard ist127.0.0.1. - Der Agent arbeitet als
root, neue Dateien gehören daher root. Binden Sie nur den Arbeitsordner ein, nie Ihr Home-Verzeichnis oder den Docker-Socket. - Das Image enthält weder Python noch Compiler. Wer Tests ausführen lassen will, baut ein eigenes Image auf Basis des offiziellen.
OLLAMA_CONTEXT_LENGTHhebt den Kontext auf 16.384 Token, denn schon die Systemanweisung des Agenten umfasste im Test rund 4.600 Token.
Healthchecks und Secrets erklärt Docker Compose absichern: Secrets, Healthchecks, Non-Root.
Verifizieren: docker compose config --quiet gibt nichts aus, und ls -la zeigt compose.yaml, .env mit Rechten -rw-------, config/ und projekt/.
Schritt 3: Lokales Modell als Provider eintragen
OpenCode spricht Ollama über dessen OpenAI-kompatible Schnittstelle an. Legen Sie config/opencode.json an:
{
"$schema": "https://opencode.ai/config.json",
"model": "ollama/qwen3:4b",
"share": "disabled",
"autoupdate": false,
"provider": {
"ollama": {
"npm": "@ai-sdk/openai-compatible",
"name": "Ollama (lokal)",
"options": { "baseURL": "http://ollama:11434/v1" },
"models": {
"qwen3:4b": { "name": "Qwen3 4B" },
"qwen2.5-coder:3b": { "name": "Qwen2.5 Coder 3B" }
}
}
}
}
"share": "disabled" verhindert das Teilen von Sitzungen über den Herstellerdienst. Die Weboberfläche listet zwar Cloud-Anbieter, ohne hinterlegten Schlüssel bleibt es beim lokalen Modell.
Im Test gab qwen2.5-coder:3b den Werkzeugaufruf nur als JSON-Text aus, eine Datei entstand nicht; qwen3:4b rief das Schreibwerkzeug korrekt auf. Passende Modelle je Hardware zeigt der Ollama-Modellvergleich nach VRAM und Quantisierung, den Denkmodus erklärt Qwen3 lokal betreiben.
Verifizieren: python3 -m json.tool config/opencode.json gibt die Datei ohne Fehlermeldung aus.
Schritt 4: Stack starten und Modell laden
docker compose up -d --pull always
docker compose exec ollama ollama pull qwen3:4b
docker compose exec opencode opencode --version
docker compose logs opencode
Das Log des OpenCode-Containers zeigt nach wenigen Sekunden genau eine Zeile:
server listening on http://0.0.0.0:4096
Ohne OPENCODE_SERVER_PASSWORD erzeugt OpenCode 2 bei jedem Start ein neues Zufallspasswort und schreibt es als server password … ins Log. Setzen Sie es daher fest.
Verifizieren: docker compose ps zeigt ollama als healthy und opencode als Up, opencode --version meldet opencode v2.1.3, und docker compose exec ollama ollama list führt qwen3:4b mit 2.5 GB.
Schritt 5: Zugriffsschutz prüfen
Prüfen Sie die API ohne, mit falschem und mit richtigem Passwort (Benutzer opencode):
. ./.env
curl -s -o /dev/null -w '%{http_code}\n' http://localhost:4096/api/info
curl -s -o /dev/null -w '%{http_code}\n' -u opencode:falsch http://localhost:4096/api/info
curl -s -u "opencode:$OC_PASSWORD" http://localhost:4096/api/info
Im Test lautete die Antwort 401, 401 und dann:
{"version":"2.1.3","pid":1,"urls":["http://127.0.0.1:4096","http://172.18.0.3:4096"],"paths":{"tmp":"/tmp/opencode"},"capabilities":{"persistentPty":true}}
Zwei Testbefunde: Die alte Route /global/health antwortet in 2.x immer mit 200, weil dort die HTML-Startseite der Weboberfläche ausgeliefert wird. Ein Monitoring auf diese Route meldet also auch ohne Passwort Erfolg; nutzen Sie /api/info mit Zugangsdaten. Außerdem ignorierte 2.1.3 die dokumentierte Variable OPENCODE_SERVER_USERNAME: Benutzer admin bekam 401, opencode 200. In 1.19.4 antwortet /global/health ohne Passwort korrekt mit 401.
Basic Auth überträgt das Passwort nur Base64-kodiert: Port 4096 gehört nicht ins Internet. Für Zugriff von außen eignen sich ein VPN wie Headscale oder Tailscale oder ein Reverse Proxy mit TLS, etwa Caddy.
Verifizieren: Ohne und mit falschem Passwort kommt 401 mit {"_tag":"UnauthorizedError","message":"Authentication required"}, mit richtigem Passwort 200 und die Versionsangabe.
Schritt 6: Weboberfläche und ersten Agentenauftrag nutzen
Öffnen Sie http://SERVER-IP:4096 und melden Sie sich als opencode an. Die Oberfläche erscheint auf Deutsch.

Aufträge geben Sie in der Weboberfläche ein oder schicken sie per CLI an den Server. Die CLI übernimmt das Passwort aus der Umgebung, --auto genehmigt Werkzeugaufrufe ohne Rückfrage:
docker compose exec opencode opencode run --server http://127.0.0.1:4096 --auto \
--title "Marker-Session hallo.py" \
"Lege im Projektordner die Datei hallo.py an. Inhalt: eine Funktion begruessung(name), \
die 'Hallo, ' + name zurueckgibt, und darunter print(begruessung('S-EDV')). \
Nutze das write-Werkzeug und antworte danach kurz."
cat projekt/hallo.py
Die Ausgabe im Test:
> build · qwen3:4b
← Write hallo.py
Created file successfully: hallo.py
def begruessung(name):
return 'Hallo, ' + name
print(begruessung('S-EDV'))
Auf der CPU dauerte das 7 Minuten, davon über 5 Minuten Denkphase. Die Sitzung erscheint samt Diff in der Weboberfläche.

Qwen3 denkt standardmäßig lange nach. Einen zweiten Auftrag brach der Test nach über 20 Minuten Denkphase per POST /api/session/ID/interrupt ab. Unter Einstellungen und Anbieter steht „Ollama (lokal)“ als verbunden:

Verifizieren: cat projekt/hallo.py zeigt die neue Datei, und curl -s -u "opencode:$OC_PASSWORD" http://localhost:4096/api/session listet die Sitzung mit "outcome":"succeeded".
Schritt 7: Backup und Restore
Sitzungen und Nachrichten liegen in der SQLite-Datenbank opencode.db im Volume opencode-data, dazu kommen config und projekt. Cache und Modelle lassen sich neu laden. Sichern Sie bei gestopptem Server:
cd /opt/opencode && mkdir -p backup
docker compose stop opencode
docker run --rm -v opencode_opencode-data:/data:ro -v "$PWD/backup":/backup \
alpine tar czf /backup/opencode-data.tgz -C /data .
tar czf backup/opencode-config-projekt.tgz config projekt
docker compose start opencode
Den Volume-Namen (hier opencode_opencode-data) zeigt docker volume ls. Restore nach Totalverlust von Container, Volume, Konfiguration und Projektordner:
cd /opt/opencode
docker compose up -d --no-start opencode
docker run --rm -v opencode_opencode-data:/data -v "$PWD/backup":/backup \
alpine sh -c "rm -rf /data/* && tar xzf /backup/opencode-data.tgz -C /data"
rm -rf config projekt && tar xzf backup/opencode-config-projekt.tgz
docker compose up -d
Im Test lieferte GET /api/session nach dem Löschen [], nach dem Restore wieder beide Sitzungen samt Marker „Restore-Marker hallo.py (qwen3:4b)“, und projekt/hallo.py war zurück.
Verifizieren: curl -s -u "opencode:$OC_PASSWORD" http://localhost:4096/api/session | jq -r ".data[].title" zeigt dieselben Sitzungstitel wie vor dem Backup.
Schritt 8: Update per Image-Tag
Der Test begann mit 2.1.2 und wurde auf 2.1.3 gehoben:
cd /opt/opencode
sed -i 's/^OPENCODE_TAG=.*/OPENCODE_TAG=2.1.3/' .env
docker compose pull opencode
docker compose up -d opencode
docker compose exec opencode opencode --version
Compose meldete Recreate, danach opencode v2.1.3; Sitzungen und Dateien blieben erhalten. Im ersten Anlauf lief still weiter 2.1.2, weil die Shell OPENCODE_TAG per set -a; . ./.env exportiert hatte und das die geänderte .env überstimmte.
opencode upgrade ist im Container nicht sinnvoll, ein Wechsel ist immer ein neuer Tag, auch von 1.x auf 2.x (vorher Backup, Befehle aus Schritt 1 beachten). Neue Tags meldet etwa Diun, siehe Container-Updates nach Watchtower: Diun und WUD.
Verifizieren: docker compose ps zeigt das Image ghcr.io/anomalyco/opencode:2.1.3, und /api/info liefert "version":"2.1.3".
Troubleshooting
| Meldung | Ursache | Lösung |
|---|---|---|
Container in Restarting (1), im Log Unrecognized flag: --hostname in command opencode | Befehl web aus 1.x mit einem 2.x-Image | command: ["serve", "--hostname", "0.0.0.0", "--port", "4096"] |
Error: ConnectionRefused: Unable to connect. Is the computer able to access the url? | baseURL zeigt auf http://localhost:11434/v1; im Container ist das der OpenCode-Container selbst | Dienstnamen verwenden: http://ollama:11434/v1 |
Error: Server at http://127.0.0.1:4096 rejected the password | CLI mit falschem OPENCODE_SERVER_PASSWORD | Gleiches Passwort wie der Server setzen |
Modell antwortet mit JSON-Text {"name": "write", ...}, keine Datei entsteht | Modell beherrscht Werkzeugaufrufe nicht zuverlässig (im Test qwen2.5-coder:3b) | Modell mit sauberem Tool-Calling wählen, etwa qwen3:4b oder größer |
| Nach dem Update weiter alte Version | Exportierte Shell-Variable OPENCODE_TAG überstimmt .env | Neue Shell oder unset OPENCODE_TAG, dann docker compose up -d |
Logs liegen unter /root/.local/share/opencode/log/. Bei langsamen Antworten zeigt docker compose logs ollama die Token-Rate (tg = … t/s), ollama ps zeigt, ob CPU oder GPU rechnet.
Häufige Fragen
Wie schnell ist das auf einer CPU?
Im Test rund 3 bis 4 Token pro Sekunde, ein kurzer Dateiauftrag dauerte 7 Minuten. Für interaktives Arbeiten reicht das nicht. Welche Grafikkarte sich lohnt, zeigt die Anleitung GPU für lokale KI auswählen.
Betrifft mich die gemeldete MCP-Lücke?
Laut The Hacker News konnte ein bösartiger MCP-Server beim Anmelden per opencode mcp auth Code ausführen, nur unter Windows und WSL, in 1.0.137 bis 1.18.32; behoben in 1.18.33. Ein Linux-Container mit 2.1.3 ist nicht betroffen. Binden Sie trotzdem nur vertrauenswürdige MCP-Server ein, siehe MCP-Server mit Caddy absichern.
Worin unterscheidet sich OpenCode von OpenHands?
OpenCode ist ein einzelnes Binary und arbeitet direkt im eingebundenen Ordner. Die Alternative zeigt OpenHands mit Docker selbst hosten, ein neues offenes Coding-Modell die Meldung zu Recursive Flint.
Fazit
OpenCode 2.1 läuft mit zwei Containern als passwortgeschützter Server mit lokalem Modell, ohne dass Code das Haus verlässt. Backup und Restore sind einfach, weil der Zustand in einer SQLite-Datenbank, der Konfiguration und dem Projektordner steckt. Die Grenze ist das Modell: Kleine Modelle auf CPU sind langsam und scheitern teils am Werkzeugaufruf. Testen Sie Ihr Modell zuerst mit einem einfachen Dateiauftrag und achten Sie beim Wechsel zwischen 1.x und 2.x auf die geänderten Befehle.
Weiterführende Anleitungen und Quellen
- OpenHands: KI-Coding-Agent mit Docker selbst hosten
- Qwen3 lokal betreiben mit Ollama und vLLM
- Ollama-Modelle nach VRAM und Quantisierung auswählen
- OpenCode auf GitHub
- OpenCode-Doku: Server
- OpenCode-Doku: Provider und Ollama
- OpenCode-Doku: Logs und Datenablage
- heise: OpenCode 2.1
- The Hacker News: MCP-Lücke unter Windows und WSL


