Generative KIs werden immer ausgereifter und lassen sich mittlerweile vielseitig einsetzen. Leider befinden sich die bekannten Anbieter fast alle in den USA, womit es schwierig ist, deren LLM datenschutzkonform einzusetzen. Eine Alternative ist das Setup einer LLM auf einem eigenen Server. Die nachfolgende Anleitung beschriebt, wie man die freien LLM Phi-3 und Orca 2 auf einem einfachen Linux-Server in Docker-Containern laufen lassen kann. Dazu benötigt der Server nichtmal eine GPU, da beide LLM problemlos auf einer normalen CPU laufen können.
Als Basis werden wir Ollama verwenden. Damit man nicht auf den Komfort eines Web-Interface verzichten muss, werde ich auch darauf eingehen, wie man Open WebUI nutzen kann um ein komfortables Web-Interface zur Verfügung zu haben.
Da das Setup mittels docker-compose mit den aus den Projekten stammenden Images bei mir nur zu Problemen führte, habe ich mich entschieden ein Custom Setup zu erstellen. Mir fehlte einfach die Zeit zum debuggen. So war das Setup unkomplizierter und schneller zu bewerkstelligen. Hier ist also die Anleitung, wie das Setup funktioniert.
Schaut man sich außerdem die Dockerfiles von Open WebUI und Ollama an (oder lässt diese mal testweise als Container laufen), stellt man fest, dass die Prozesse darin mit root-Rechten laufen. Das ist aus Sicht der IT-Sicherheit natürlich eher nicht ratsam. Es gibt keinen Grund, dass diese Prozesse mit root-Rechten laufen müssen, auch wenn sie in Docker-Containern isoliert sind.
Wie Docker unter Linux eingerichtet wird, werde ich an dieser Stelle nicht beschreiben. Dafür gibt es genug Anleitungen im Internet. Ich gehe also im Folgenden davon aus, dass eine funktionierende Docker-Umgebung bereits zur Verfügung steht.
Als erstes benötigen wir also Ollama. Hierfür nutzen wir folgendes Dockerfile:
# als Basis benutzen wir ein aktuelles Debian GNU/Linux FROM debian:stable ENV TERM xterm ENV OLLAMA_HOST "0.0.0.0" # sicherstellen, dass das Basis-System aktuell ist RUN apt-get update && \ apt-get -y upgrade RUN apt-get -y install curl # mit diesem Befehl lässt sich Ollama unter Linux und macOS auch lokal einrichten RUN curl -fsSL https://ollama.com/install.sh | sh # Benutzer anlegen RUN groupadd -g 1000 ollama RUN useradd -g ollama -d /usr/share/ollama -u 1000 ollama RUN mkdir -p /usr/share/ollama RUN chown -R ollama:ollama /usr/share/ollama # Cleanup RUN apt-get clean && \ apt-get autoremove --yes && \ rm -rf /var/lib/{apt,dpkg,cache,log}/* # der Port, auf den die API bindet EXPOSE 11434 # hier werden die Daten von Ollama gespeichert VOLUME /usr/share/ollama # Container sollten niemals als root laufen, also verwenden wir runuser ENTRYPOINT runuser -l ollama -c 'OLLAMA_HOST=0.0.0.0 OLLAMA_ORIGINS='*' /usr/local/bin/ollama serve'
Das Image aus diesem Dockerfile erstellen wir, indem wir in den Ordner wechseln, in dem wir das Dockerfile abgelegt haben und folgenden Befehl ausführen:
docker build -t ollama .
Damit man nicht ständig seine LLM neu installieren muss, sollte man das im Dockerfile angegebene VOLUME auf dem Host-System einhängen. Wir erstellen also einen Ordner auf dem Host dafür:
mkdir -p /docker_data/ollama
Wie im Dockerfile zu sehen ist, wird Ollama mit dem Benutzer mit der UID 1000 ausgeführt. Der Ordner auf dem Host muss also diesem Benutzer gehören, damit der Prozess darin schreiben kann:
chown 1000:1000 /docker_data/ollama
Ich weise allen meinen Containern feste IP-Adressen zu, damit sie problemlos untereinander kommunizieren können, ohne dass ich sie extra miteinander verbinden muss. Dafür wird ein Docker-Netzwerk benötigt:
docker network create --subnet 172.10.0.0/16 bitNatürlich kann das Netzwerk auch anders benannt werden. Das muss dann aber beim Starten der Container entsprechend beachtet werden.
Jetzt kann der Container für Ollama auch schon gestartet werden.
docker run -d \ --name ollama \ -v /docker_data/ollama:/usr/share/ollama \ --restart always \ --network bit \ --ip 172.10.0.10 \ -p 127.0.0.1:11434:11434 \ ollamaTheoretisch kann man das Port-Binding an die 127.0.0.1 auch weglassen. Es kann aber ganz praktisch sein, wenn man die Ollama-API, z.B. für die Nutzung mit Skripten, auch über localhost erreichen kann.
Jetzt kann man Phi-3 bereits über das CLI nutzen. Hierfür führt man es einfach direkt im Container aus:
docker exec -it ollama ollama run phi3Bei der ersten Ausführung wird das Phi-3-LLM heruntergeladen und in
/usr/share/ollama/.ollama/models/
im Container gespeichert.
Auf die gleiche Weise kann auch das LLM Orca 2 hinzugefügt werden:
docker exec -it ollama ollama run orca2
Der erste Teil wäre somit geschafft. Nun benötigen wir noch Open WebUI als Webinterface. Auch dieses lassen wir natürlich in einem Docker-Container laufen.
Um das Image zu erstellen, nutzen wir folgendes Dockerfile:
FROM debian:stable WORKDIR / RUN apt-get update && \ apt-get -y upgrade RUN apt-get -y install git npm python3-pip python3-venv RUN git clone https://github.com/open-webui/open-webui.git WORKDIR /open-webui RUN python3 -m venv ./ COPY .env /open-webui/.env ENV PATH=/open-webui/bin:$PATH RUN npm i RUN npm run build RUN cd /open-webui/backend && /open-webui/bin/pip3 install -r requirements.txt -U RUN groupadd -g 1000 ollama RUN useradd -g ollama -d /usr/share/ollama -u 1000 ollama RUN chown -R ollama:ollama /open-webui RUN mkdir -p /usr/share/ollama RUN chown -R ollama:ollama /usr/share/ollama RUN apt-get clean && \ apt-get autoremove --yes && \ rm -rf /var/lib/{apt,dpkg,cache,log}/* \ rm -rf /root/.cache EXPOSE 8080/tcp VOLUME /open-webui/backend/data ENTRYPOINT runuser -l ollama -c 'PATH=/open-webui/bin:$PATH /open-webui/backend/start.sh'
Wie im Dockerfile zu sehen ist, wird die Datei .env
benötigt. In dieser wird festgelegt, unter welcher URL die Ollama-API erreichbar ist. Die Datei hat folgenden Inhalt:
# Ollama URL for the backend to connect # The path '/ollama' will be redirected to the specified backend URL OLLAMA_BASE_URL='http://172.10.0.10:11434' OPENAI_API_BASE_URL='' OPENAI_API_KEY='' # AUTOMATIC1111_BASE_URL="http://localhost:7860" # DO NOT TRACK SCARF_NO_ANALYTICS=true DO_NOT_TRACK=true # Use locally bundled version of the LiteLLM cost map json # to avoid repetitive startup connections LITELLM_LOCAL_MODEL_COST_MAP="True"
Auch hier wechseln wir wieder in den Ordner, in dem das Dockerfile und die Datei .env abgelegt sind, und erstellen das Image mit folgendem Befehl:
docker build -t ollama-webui .
Auch hier sollten ein paar Daten auf dem Host persistiert werden, damit man nicht ständig seine Benutzer neu anlegen muss. Wir erstellen also einen Ordner dafür auf dem Host-System und ändern die Rechte entsprechend:
mkdir -p /docker_data/ollama-webui-backend-data chown 1000:1000 /docker_data/ollama-webui-backend-data
Und schon kann auch der Container mit Open WebUI gestartet werden:
docker run -d \ --name ollama-webui \ -p 8080:8080 \ -e OLLAMA_BASE_URL=http://172.10.0.10:11434 \ -v /docker_data/ollama-webui-backend-data:/open-webui/backend/data \ --restart always \ --network bit \ --ip 172.10.0.20 \ --add-host=host.docker.internal:host-gateway \ ollama-webui
Der Start kann ggf. ein paar Sekunden dauern. Ein Blick in die Container-Logs
docker logs ollama-webuisollte nach einem erfolgreichen Start folgendes Banner zeigen:
INFO: Started server process [11] INFO: Waiting for application startup. ___ __ __ _ _ _ ___ / _ \ _ __ ___ _ __ \ \ / /__| |__ | | | |_ _| | | | | '_ \ / _ \ '_ \ \ \ /\ / / _ \ '_ \| | | || | | |_| | |_) | __/ | | | \ V V / __/ |_) | |_| || | \___/| .__/ \___|_| |_| \_/\_/ \___|_.__/ \___/|___| |_| v0.1.122 - building the best open-source AI user interface. https://github.com/open-webui/open-webuiMit curl kann auch bereits verifiziert werden. ob Open WebUI korrekt läuft:
curl 'http://172.10.0.20:8080'
Ggf. wollen wir den Server aber auch über das Internet nutzen. Ich nutze üblicherweise einen Nginx auf dem Host-System als Proxy-Server für meine Docker-Container. SSL-Zertifikate beziehe ich über Let's Encrypt.
Ich möchte an dieser Stelle nicht auf alle Details eines Nginx-Setups eingehen. Das würde etwas zu weit gehen, da dabei einiges zu beachten ist. Wer jedoch einen Server im Internet betreibt, sollte sich mit einem Webserver-Setup auskennen. Ist das nicht der Fall, empfehle ich einen Blick in meinen Blog-Beitrag zur Webserver-Sicherheit. Als Domain nehme ich für das Beispiel die Dummy-Domain ai.domain.tld.
Die Server-Konfiguration für den Nginx könnte z.B. so aussehen:
upstream web-ai { server 172.10.0.20:8080; } server { listen 80; server_name ai.domain.tld; return 301 https://$host$request_uri; } server { listen 443 ssl; server_name ai.domain.tld; ssl_ecdh_curve secp384r1; ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5:!ADH:!eNULL:!LOW:!EXP; ssl_prefer_server_ciphers on; ssl_session_timeout 10m; ssl_session_cache shared:SSL:10m; ssl_session_tickets off; ssl_stapling on; ssl_stapling_verify on; ssl_dhparam /etc/nginx/dhparams.pem; ssl_certificate /etc/letsencrypt/live/domain.tld//fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/domain.tld/privkey.pem; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; add_header X-Content-Type-Options nosniff; add_header Content-Security-Policy "default-src 'self' http: https: data: blob: 'unsafe-inline'" always; add_header X-XSS-Protection "1; mode=block"; add_header X-Frame-Options "SAMEORIGIN"; client_body_buffer_size 10M; client_header_buffer_size 10M; client_max_body_size 10M; large_client_header_buffers 2 10M; location / { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Host $host; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Port $server_port; proxy_ssl_server_name on; proxy_buffering off; proxy_set_header Origin ''; proxy_set_header Referer ''; limit_except GET HEAD POST { deny all; } proxy_pass http://web-ai; } # deny access to .htaccess and .git location ~ /\.ht { deny all; } location ~ /\.git { deny all; } }
Ist der Nginx korrekt eingerichtet, kann nun auf Open WebUI über die konfigurierte Domain zugegriffen werden. Der erste Benutzer, der angelegt wird, ist automatisch der Administrator. Weitere Benutzer können zwar angelegt werden, müssen jedoch vom Administrator explizit freigegeben werden. Nach dem Login zeigt sich dann auch, dass phi3
und orca2
bereits zur Verfügung stehen.
Viel Spaß!
Design based on Dracula UI