commit 652fba50c1a7c12f30373c02a28a9865b16ac32f Author: Petar Cubela Date: Fri Jul 10 09:57:37 2026 +0200 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..e69de29 diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..e69de29 diff --git a/ansible/.DS_Store b/ansible/.DS_Store new file mode 100644 index 0000000..a8a155c Binary files /dev/null and b/ansible/.DS_Store differ diff --git a/ansible/LICENSE b/ansible/LICENSE new file mode 100644 index 0000000..f348d77 --- /dev/null +++ b/ansible/LICENSE @@ -0,0 +1,5 @@ +Author: Petar Cubela +Company: Softbox GmbH +Date: 2024-12-04 + +Bla bla legal advise bla bla trademark, intellectual property and such bla bla diff --git a/ansible/README.md b/ansible/README.md new file mode 100644 index 0000000..3c0c478 --- /dev/null +++ b/ansible/README.md @@ -0,0 +1,3 @@ +# Buero Templates for used software deployments + +In this repository I collect all ansible playbooks used during my work. diff --git a/ansible/TODO.md b/ansible/TODO.md new file mode 100644 index 0000000..ee6b607 --- /dev/null +++ b/ansible/TODO.md @@ -0,0 +1,13 @@ +## todo + +### Modifications + +- [ ] Build ansible-role-lamp +- [ ] Build seperate ansible-role-owncloud depending on ansible-role-lamp +- [ ] Build seperate ansible-role-nextcloud depending on ansible-role-lamp + +## LAMP Stack + +- [ ] Build with option to choose between apache and nginx +- [ ] Build with option to choose different databases +- [ ] Build with option to choose different php versions diff --git a/ansible/ansible.cfg b/ansible/ansible.cfg new file mode 100644 index 0000000..bd3d219 --- /dev/null +++ b/ansible/ansible.cfg @@ -0,0 +1,8 @@ +[defaults] +nocows = 1 +host_key_checking = false +inventory = ./hosts.ini +ansible_python_interpreter = /usr/bin/python3 + +[ssh_connections] +pipelining = true diff --git a/ansible/group_vars/all.yml b/ansible/group_vars/all.yml new file mode 100644 index 0000000..ecb2be2 --- /dev/null +++ b/ansible/group_vars/all.yml @@ -0,0 +1,64 @@ +--- +# generic settings +main_username: sbxadmin +main_groupname: "{{ main_username }}" +main_uid: "1000" +main_gid: "{{ main_uid }}" + +# weareinteractive.environment +environment_config: { "PUID": "{{ main_gid }}", "PGID": "{{ main_gid }}" } + +global_env_vars: + - "PUID={{ main_uid }}" + - "PGID={{ main_gid }}" + - "TZ={{ ntp_timezone }}" + +# geerlingguy.ntp +ntp_timezone: "Europe/Berlin" + +# geerlingguy.nfs +#nfs_exports: [ "/home/public *(rw,sync,no_root_squash)" ] + +# geerlingguy.security +security_ssh_port: 22 +security_ssh_password_authentication: "yes" +security_ssh_permit_root_login: "no" +security_ssh_usedns: "no" +security_ssh_permit_empty_password: "no" +security_ssh_challenge_response_auth: "no" +security_ssh_gss_api_authentication: "no" +security_ssh_x11_forwarding: "no" +security_ssh_allowed_users: + - "{{ main_username }}" +security_ssh_allowed_groups: [] +security_sudoers_passwordless: + - "{{ main_username }}" +security_autoupdate_enabled: false +security_autoupdate_blacklist: [] +security_autoupdate_reboot: false +security_autoupdate_reboot_time: "03:00" +security_autoupdate_mail_to: "service@softbox.de" +security_autoupdate_mail_on_error: false +security_fail2ban_enabled: true +security_fail2ban_custom_configuration_template: "jail.local.j2" +### +#packages +package_list: + - bash-completion + - htop + - apt-transport-https + - network-manager + - vim + - curl + - xclip + - net-tools + - rsync + - smartmontools + - parted + - mlocate + - cpp + - gcc + - make + - psmisc + #- linux-headers-$(uname -r) + - open-vm-tools diff --git a/ansible/group_vars/nextcloud.yml b/ansible/group_vars/nextcloud.yml new file mode 100644 index 0000000..589db83 --- /dev/null +++ b/ansible/group_vars/nextcloud.yml @@ -0,0 +1,4 @@ +hostname: cloud +#.phytron.de +php_version: 8.2 +domain_base: "phytron.de" diff --git a/ansible/group_vars/sftp.yml b/ansible/group_vars/sftp.yml new file mode 100644 index 0000000..187cb09 --- /dev/null +++ b/ansible/group_vars/sftp.yml @@ -0,0 +1,43 @@ +--- +# generic settings +main_username: sbxadmin +main_groupname: "{{ main_username }}" +main_uid: "1000" +main_gid: "{{ main_uid }}" + +# weareinteractive.environment +environment_config: { "PUID": "{{ main_gid }}", "PGID": "{{ main_gid }}" } + +global_env_vars: + - "PUID={{ main_uid }}" + - "PGID={{ main_gid }}" + - "TZ={{ ntp_timezone }}" + +# geerlingguy.ntp +ntp_timezone: "Europe/Berlin" + +# geerlingguy.nfs +#nfs_exports: [ "/home/public *(rw,sync,no_root_squash)" ] + +# geerlingguy.security +security_ssh_port: 22 +security_ssh_password_authentication: "no" +security_ssh_permit_root_login: "no" +security_ssh_usedns: "no" +security_ssh_permit_empty_password: "no" +security_ssh_challenge_response_auth: "no" +security_ssh_gss_api_authentication: "no" +security_ssh_x11_forwarding: "no" +security_ssh_allowed_users: + - "{{ main_username }}" +security_ssh_allowed_groups: [] +security_sudoers_passwordless: + - "{{ main_username }}" +security_autoupdate_enabled: true +security_autoupdate_blacklist: [] +security_autoupdate_reboot: reboot +security_autoupdate_reboot_time: "03:00" +security_autoupdate_mail_to: "service@softbox.de" +security_autoupdate_mail_on_error: true +security_fail2ban_enabled: true +security_fail2ban_custom_configuration_template: "jail.local.j2" diff --git a/ansible/hosts.ini b/ansible/hosts.ini new file mode 100644 index 0000000..e9537fa --- /dev/null +++ b/ansible/hosts.ini @@ -0,0 +1,9 @@ +#[snipeit] +#10.0.101.15 ansible_user=root ansible_port=22 +# + +[nextcloud] +192.168.66.66 ansible_user=sbxadmin ansible_port=22 + +[sftp] +192.168.66.68 ansible_user=sbxadmin ansible_port=22 diff --git a/ansible/justfile b/ansible/justfile new file mode 100644 index 0000000..b2c4923 --- /dev/null +++ b/ansible/justfile @@ -0,0 +1,18 @@ +#!/usr/bin/env -S just --justfile + +# Ansible playbook against specific host +run HOST *TAGS: + ansible-playbook -b run.yml --limit {{HOST}} {{TAGS}} + +# docker compose against remote host via Ansible +compose HOST *V: + ansible-playbook run.yml --limit {{HOST}} --tags compose {{V}} + + +# optionally use --force to force reinstall all requirements +reqs *FORCE: + ansible-galaxy install -r requirements.yml {{FORCE}} + +# just vault (encrypt/decrypt/edit) +vault ACTION: + EDITOR=nvim ansible-vault {{ACTION}} group_vars/secrets.yml diff --git a/ansible/playbooks/shutdown.yml b/ansible/playbooks/shutdown.yml new file mode 100644 index 0000000..8691d4b --- /dev/null +++ b/ansible/playbooks/shutdown.yml @@ -0,0 +1,9 @@ +--- +- name: Shutdown k3s_cluster + hosts: k3s_cluster + gather_facts: true + tasks: + - name: Shutdown the nodes (and wait one 1 min) + become: true + community.general.shutdown: + delay: 60 diff --git a/ansible/playbooks/update.yml b/ansible/playbooks/update.yml new file mode 100644 index 0000000..9a3e785 --- /dev/null +++ b/ansible/playbooks/update.yml @@ -0,0 +1,29 @@ +--- +- hosts: + - all + become: true + + tasks: + - name: Perform a dist-upgrade. + ansible.builtin.apt: + upgrade: dist + update_cache: yes + + - name: Install essential packages + package: + name: "{{ package_list }}" + state: present + + - name: Check if a reboot is required. + ansible.builtin.stat: + path: /var/run/reboot-required + get_checksum: no + register: reboot_required_file + + - name: Reboot the server (if required). + ansible.builtin.reboot: + when: reboot_required_file.stat.exists == true + + - name: Remove dependencies that are no longer required. + ansible.builtin.apt: + autoremove: yes diff --git a/ansible/requirements.yml b/ansible/requirements.yml new file mode 100644 index 0000000..5a4c875 --- /dev/null +++ b/ansible/requirements.yml @@ -0,0 +1,8 @@ +--- +roles: + #- name: geerlingguy.pip + - name: geerlingguy.docker + - name: geerlingguy.nfs + - name: geerlingguy.security + - name: geerlingguy.ntp + - name: ironicbadger.docker_compose_generator diff --git a/ansible/roles/nextcloud/defaults/main.yml b/ansible/roles/nextcloud/defaults/main.yml new file mode 100644 index 0000000..d302d73 --- /dev/null +++ b/ansible/roles/nextcloud/defaults/main.yml @@ -0,0 +1,5 @@ +site_conf: cloud.conf +php_version: "8.4" +mysql_db_name: nextcloud +mysql_db_user: nextcloud +web_root: "/var/www/nextcloud" diff --git a/ansible/roles/nextcloud/handlers/main.yml b/ansible/roles/nextcloud/handlers/main.yml new file mode 100644 index 0000000..af398e8 --- /dev/null +++ b/ansible/roles/nextcloud/handlers/main.yml @@ -0,0 +1,5 @@ +--- +- name: restart apache + service: + name: apache2 + state: restarted diff --git a/ansible/roles/nextcloud/tasks/apache.yml b/ansible/roles/nextcloud/tasks/apache.yml new file mode 100644 index 0000000..5cc6b76 --- /dev/null +++ b/ansible/roles/nextcloud/tasks/apache.yml @@ -0,0 +1,35 @@ +- name: Set hostname + ansible.builtin.hostname: + name: "{{ hostname }}" + +- name: "Enable recommended Apache Modules." + apache2_module: "name={{ item }} state=present" + with_items: + - dir + - env + - headers + - mime + - rewrite + - setenvif + notify: restart apache + +- name: Add Apache virtualhost for Nextcloud + template: + src: "templates/{{ site_conf }}.j2" + dest: "/etc/apache2/sites-available/{{ site_conf }}" + owner: root + group: root + mode: 0644 + notify: restart apache + +- name: Enable the Nextcloud site. + command: > + a2ensite {{ site_conf }} + creates="/etc/apache2/sites-enabled/{{ site_conf }}" + notify: restart apache + +- name: Disable the default site. + command: > + a2dissite 000-default + removes=/etc/apache2/sites-enabled/000-default.conf + notify: restart apache diff --git a/ansible/roles/nextcloud/tasks/dependencies.yml b/ansible/roles/nextcloud/tasks/dependencies.yml new file mode 100644 index 0000000..320532c --- /dev/null +++ b/ansible/roles/nextcloud/tasks/dependencies.yml @@ -0,0 +1,72 @@ +--- +- name: Get software for apt repository management. + apt: + state: present + name: + - python3-apt + - python3-pycurl + - python3-pymysql + - gnupg2 + +#- name: Add ondrej repository for later versions of PHP. +# apt_repository: +# repo: "ppa:ondrej/php" +# update_cache: yes + +#sudo dpkg -l | grep php | tee packages.txt +#sudo apt install apt-transport-https lsb-release ca-certificates wget -y +#sudo wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg +#sudo sh -c 'echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/php.list' +#sudo apt update + +- name: "Install Apache, MySQL, PHP, and other dependencies." + apt: + state: present + name: + - acl + - git + - curl + - wget + - unzip + - openssl + - redis-server + - mariadb-server + - libpcre3-dev + - apache2 + - "libapache2-mod-php" + - "php{{ php_version }}" + - "php{{ php_version }}-imagick" + - "php{{ php_version }}-common" + - "php{{ php_version }}-curl" + - "php{{ php_version }}-gd" + - "php{{ php_version }}-imap" + - "php{{ php_version }}-intl" + #- "php{{ php_version }}-json" + - "php{{ php_version }}-mbstring" + - "php{{ php_version }}-gmp" + - "php{{ php_version }}-bcmath" + - "php{{ php_version }}-mysql" + - "php{{ php_version }}-ssh2" + - "php{{ php_version }}-xml" + - "php{{ php_version }}-zip" + - "php{{ php_version }}-apcu" + - "php{{ php_version }}-redis" + - "php{{ php_version }}-ldap" + #- "php{{ php_version }}-smbclient" + - php-phpseclib + - bzip2 + - rsync + - jq + - inetutils-ping + - ldap-utils + - smbclient + - cron + +#- name: Disable the firewall (since this is behind a firewall) +# service: name=ufw state=stopped + +- name: "Start Apache, MySQL, and PHP." + service: "name={{ item }} state=started enabled=yes" + with_items: + - apache2 + - mysql diff --git a/ansible/roles/nextcloud/tasks/main.yml b/ansible/roles/nextcloud/tasks/main.yml new file mode 100644 index 0000000..7dce4ad --- /dev/null +++ b/ansible/roles/nextcloud/tasks/main.yml @@ -0,0 +1,24 @@ +--- +- name: Install LAMP stack dependencies + include_tasks: + file: dependencies.yml + +- name: Configure Apache. + include_tasks: + file: apache.yml + +- name: Configure PHP. + include_tasks: + file: php.yml + +- name: Configure MySQL. + include_tasks: + file: mysql.yml + +- name: Create occ helper script. + include_tasks: + file: occ.yml + +- name: Download Nextcloud. + include_tasks: + file: nextcloud.yml diff --git a/ansible/roles/nextcloud/tasks/mysql.yml b/ansible/roles/nextcloud/tasks/mysql.yml new file mode 100644 index 0000000..db06d08 --- /dev/null +++ b/ansible/roles/nextcloud/tasks/mysql.yml @@ -0,0 +1,16 @@ +- name: Create a MySQL database. + community.mysql.mysql_db: + name: "{{ mysql_db_name }}" + state: present + login_unix_socket: /run/mysqld/mysqld.sock + +- name: Create a MySQL db user. + community.mysql.mysql_user: + name: "{{ mysql_db_user }}" + password: "{{ mysql_passwd }}" + login_user: "root" + login_password: "{{ mysql_passwd }}" + priv: "{{ mysql_db_user }}.*:ALL" + host: localhost + state: present + login_unix_socket: /run/mysqld/mysqld.sock diff --git a/ansible/roles/nextcloud/tasks/nextcloud.yml b/ansible/roles/nextcloud/tasks/nextcloud.yml new file mode 100644 index 0000000..c78af24 --- /dev/null +++ b/ansible/roles/nextcloud/tasks/nextcloud.yml @@ -0,0 +1,13 @@ +--- +- name: Download Nextcloud source. + ansible.builtin.get_url: + url: https://download.nextcloud.com/server/releases/latest.tar.bz2 + dest: "/tmp/nextcloud-complete-latest.tar.bz2" + owner: www-data + +- name: Extract the archive. + ansible.builtin.unarchive: + src: "/tmp/nextcloud-complete-latest.tar.bz2" + dest: "/var/www/" + owner: www-data + remote_src: yes diff --git a/ansible/roles/nextcloud/tasks/occ.yml b/ansible/roles/nextcloud/tasks/occ.yml new file mode 100644 index 0000000..f53ad67 --- /dev/null +++ b/ansible/roles/nextcloud/tasks/occ.yml @@ -0,0 +1,7 @@ +- name: Create a helper script for running occ commands. + template: + src: "templates/occ.j2" + dest: "/usr/local/bin/occ" + owner: root + group: root + mode: 0755 diff --git a/ansible/roles/nextcloud/tasks/php.yml b/ansible/roles/nextcloud/tasks/php.yml new file mode 100644 index 0000000..dbcab3f --- /dev/null +++ b/ansible/roles/nextcloud/tasks/php.yml @@ -0,0 +1,16 @@ +--- +- name: Adjust OpCache memory setting. + lineinfile: + dest: "/etc/php/{{ php_version }}/apache2/conf.d/10-opcache.ini" + regexp: "^opcache.memory_consumption" + line: "opcache.memory_consumption = 96" + state: present + notify: restart apache + +#- name: Adjust smbclient setting. +# template: +# src: "templates/smbclient.ini.j2" +# dest: "/etc/php/7.4/mods-available/smbclient.ini" +# owner: root +# group: root +# notify: restart apache diff --git a/ansible/roles/nextcloud/templates/cloud.conf.j2 b/ansible/roles/nextcloud/templates/cloud.conf.j2 new file mode 100644 index 0000000..f87a0b6 --- /dev/null +++ b/ansible/roles/nextcloud/templates/cloud.conf.j2 @@ -0,0 +1,17 @@ + +ServerName {{ hostname }}.{{ domain_base }} +DirectoryIndex index.php index.html +DocumentRoot {{ web_root }} + + Options FollowSymLinks MultiViews + AllowOverride All + Require all granted + + + Dav off + + + #SetEnv HOME {{ web_root }} + #SetEnv HTTP_HOME {{ web_root }} + + diff --git a/ansible/roles/nextcloud/templates/occ.j2 b/ansible/roles/nextcloud/templates/occ.j2 new file mode 100644 index 0000000..20f6ed4 --- /dev/null +++ b/ansible/roles/nextcloud/templates/occ.j2 @@ -0,0 +1,4 @@ +#!/bin/bash + +cd /var/www/nextcloud || exit +sudo -E -u www-data /usr/bin/php /var/www/nextcloud/occ "$@" diff --git a/ansible/run.yml b/ansible/run.yml new file mode 100644 index 0000000..96a82cf --- /dev/null +++ b/ansible/run.yml @@ -0,0 +1,52 @@ +--- +#- hosts: owncloud +# become: yes +# vars_files: +# - "vars/vault.yml" +# +# pre_tasks: +# - name: Update apt cache. +# apt: +# update_cache: true +# cache_valid_time: 3600 +# when: ansible_os_family == 'Debian' +# +# roles: +# - role: geerlingguy.security +# #- role: geerlingguy.ntp ## NEEDED? +# - role: owncloud + +- hosts: nextcloud + become: yes + vars_files: + - "vars/vault.yml" + + pre_tasks: + - name: Update apt cache. + apt: + update_cache: true + cache_valid_time: 3600 + when: ansible_os_family == 'Debian' + + roles: + # - role: geerlingguy.security + - role: nextcloud + - role: smtp_nextcloud + tags: mail + + +- hosts: sftp + become: yes + vars_files: + - "vars/vault.yml" + + pre_tasks: + - name: Update apt cache. + apt: + update_cache: true + cache_valid_time: 3600 + when: ansible_os_family == 'Debian' + + roles: + - role: geerlingguy.security + tags: base diff --git a/ansible/vars/vault.yml b/ansible/vars/vault.yml new file mode 100644 index 0000000..6a9e7d6 --- /dev/null +++ b/ansible/vars/vault.yml @@ -0,0 +1,14 @@ +$ANSIBLE_VAULT;1.1;AES256 +31353435633062366461353231666566366662373733656337356339626234313966366139613161 +3533646266393033316330323737303638303162356161610a393337313837653835396162633030 +30313066326337393831643833663237643966383163363866386133373264373933633133653462 +6636376563336433640a356231363764363834626431616435633436306662313932313164623733 +62383062653166613661303939346135643661646630386532306161393365393133626164303337 +31623962623931353365346365623333386638313266356131326565613730303338643863396237 +39353261616339356563393236633232646361326234333533643338656331623732636432383434 +63653963336333366462366562633631336636643935646632323031666366633136383732643733 +63366433363136666131386434333431333062363238633064646336626463623730616238646136 +31333839623538306161393862306231656466613231326165666562616432363136396332646533 +30663130336438623463336333343830656138316236353963373833386434393337356262313934 +63323030323837373066323337363633636236353931643636643337393161303965613438363638 +3532 diff --git a/server/phy-z-dmz-sftp01/manuals/20260204-add-new-user.md b/server/phy-z-dmz-sftp01/manuals/20260204-add-new-user.md new file mode 100644 index 0000000..748ae89 --- /dev/null +++ b/server/phy-z-dmz-sftp01/manuals/20260204-add-new-user.md @@ -0,0 +1,62 @@ +# Add new Users to SFTP Server + +## Introduction + +We configured a SFTP server with a shared chroot jail and such that the server can only be authenticated via public key exchange. + +The shared SFTP root folder is at `/sftp`: +```bash +root@z-sftp-01:~# ls -al /sftp/ +total 16 +drwxr-xr-x 4 root root 4096 Jan 30 15:16 . +drwxr-xr-x 19 root root 4096 Feb 4 00:00 .. +drwxrwx--- 2 root sftpusers 4096 Jan 30 15:47 data +drwxrwx--- 2 root sftpusers 4096 Jan 30 15:23 uploads +``` + +The server can only be reached via sftp by users which are members of the `sftpusers` group; while these users are not able to login via ssh. Only users which are in `admins` group can access the server via ssh and this also only via public key authentication. + + +## New User + + +### User Creation + +We create the user on the server: + +```bash +useradd -m -s /sbin/nologin +``` + +The option `-m` explicitly creates a home folder (under `/home`) for the user which is not created when using the option `-s` and giving the user the `/sbin/nologin` shell. + +And add the user to the correct group: + +```bash +usermod -aG sftpusers +``` + +### SSH authentication + +Create a ssh key pair for the user with the command, + +```bash +ssh-keygen -o -a 100 -t ed25519 -f ~/.ssh/ -C +``` +which can be done in an arbitrary Unix shell supporting `ssh-keygen`. + +In order for the user to be able to authenticate via public key exchange we have to create a `/home//.ssh/authorized_keys` file with proper permissions: + +```bash +mkdir /home//.ssh +touch /home//.ssh/authorized_keys +chown -R : /home//.ssh +chmod 700 /home//.ssh +chmod 600 /home//.ssh/authorized_keys +``` + +Take the content of the public key file an insert into the proper authorized_key file + +```bash +cat ~/.ssh/.pub | tee -a ~/.ssh/authorized_keys +``` diff --git a/server/phy-z-srv-gpu01/20260706-hardware-assessment.md b/server/phy-z-srv-gpu01/20260706-hardware-assessment.md new file mode 100644 index 0000000..25bb89a --- /dev/null +++ b/server/phy-z-srv-gpu01/20260706-hardware-assessment.md @@ -0,0 +1,90 @@ +# Hardware Assessment — GPU Server für LLM-Workloads + +Date: 2026-07-06 +Status: Draft for internal review +Budget: ~50.000 € + +## TL;DR + +Die Beobachtung vom Bestandsserver (CPU < 10 %, RAM < 150 GB, GPUs zeitweise +voll ausgelastet) ist typisch: **LLM-Inference ist fast reine GPU-Last.** +Downscaling von CPU und RAM ist richtig. Bei der GPU empfehle ich statt einer +halben H100-NVL-Konfiguration die **NVIDIA RTX PRO 6000 Blackwell Server +Edition (96 GB)** — mehr VRAM als eine H100 NVL, in Single-GPU-Inference- +Benchmarks gleichauf oder schneller, für etwa **ein Drittel des Preises** +(~9–10 k€ statt ~31 k€). Gesamtsystem landet grob bei **20–25 k€ inkl. +Support** — deutlich unter Budget. + +## 1. Einordnung des Bestandsservers + +Die Referenz-Konfiguration (DL380a Gen11, 2× Xeon 6526Y, 512 GB RAM, +2× H100 NVL) ist für den Inference-Use-Case überdimensioniert: + +- **CPU < 10 %**: erwartbar — bei GPU-Inference macht die CPU nur + Tokenizing, Scheduling und I/O. 2× 16 Kerne sind unnötig. +- **RAM < 100–150 GB**: davon ist erfahrungsgemäß ein großer Teil + Page-Cache. Echter Bedarf: Modell-Staging + Services, deutlich unter 128 GB. +- **2× H100 NVL**: NVLink-Pärchen lohnt sich nur, wenn ein Modell über beide + GPUs gespannt wird (Tensor-Parallel). Für Modelle ≤ 96 GB unnötig. + +## 2. GPU-Empfehlung + +| | RTX PRO 6000 Blackwell SE | H100 NVL | L40S | +|---|---|---|---| +| VRAM | **96 GB GDDR7** | 94 GB HBM3 | 48 GB GDDR6 | +| Speicherbandbreite | 1.792 GB/s | 3.900 GB/s | 864 GB/s | +| FP8/FP4 | ✅ / ✅ (Blackwell) | ✅ / ❌ | ❌ / ❌ | +| NVLink | ❌ (hier irrelevant, 1 GPU) | ✅ | ❌ | +| Straßenpreis (ca.) | **~9–10 k€** | ~31 k€ | ~8 k€ | + +- Benchmarks 2026 zeigen die RTX PRO 6000 bei Single-GPU-LLM-Inference + **gleichauf bis vor der H100** bei ~28 % niedrigeren Kosten pro Token + ([cloudrift.ai](https://www.cloudrift.ai/blog/benchmarking-rtx6000-vs-datacenter-gpus), + [openmetal.io](https://openmetal.io/resources/blog/comparing-the-nvidia-rtx-pro-6000-vs-h100-for-ai-inference/)). +- Gegenüber der in den Notizen angesetzten 48-GB-Karte (L40S-Klasse): + doppelter VRAM und > 2× Bandbreite für ähnliches Geld — 96 GB erlauben + 70B-Modelle in FP8 bzw. viel KV-Cache für parallele Nutzer + ([gpuperhour.com](https://gpuperhour.com/compare/l40s-vs-rtx-pro-6000-blackwell)). +- H100 NVL nur dann, wenn später auf 2 GPUs mit Tensor-Parallelität erweitert + werden soll — dafür gibt es hier kein Anzeichen. + +⚠️ Mit dem Distributor klären, welche HPE-Plattform (DL380 Gen11/Gen12 bzw. +DL380a) für die RTX PRO 6000 Blackwell SE qualifiziert ist. + +## 3. Empfohlene Konfiguration (angelehnt an das Referenz-Angebot) + +| Komponente | Referenz-Server | Empfehlung neu | Begründung | +|---|---|---|---| +| Chassis | DL380a Gen11 | DL380 Gen11/Gen12 mit GPU-Kit (oder DL380a) | 1 GPU braucht kein 4-GPU-Chassis | +| CPU | 2× Xeon 6526Y (32C) | **1× Xeon 16C** (z. B. 6526Y o. kleiner) | CPU-Last < 10 % beobachtet | +| RAM | 512 GB (8× 64 GB) | **128 GB (8× 16 GB)** | Alle 8 Kanäle belegt (Bandbreite), Upgrade-Pfad auf 256 GB frei | +| Boot-SSD | 2× 960 GB NVMe | 2× 960 GB NVMe (RAID 1) | unverändert | +| Daten-SSD | — | **+ 2× 3,84 TB NVMe (RAID 1)** | Modelle + Vektor-Index der Datei-Suche | +| NIC | 2× 25 GbE + 4× 1 GbE | 1× 25/10 GbE SFP28 + 1 GbE (Mgmt) | Indizierung zieht die SMB-Shares übers Netz — 1 GbE wäre der Flaschenhals | +| GPU | 2× H100 NVL 94 GB | **1× RTX PRO 6000 Blackwell SE 96 GB** | s. o. | +| PSU | 4× 1800–2200 W | 2× 1800 W (redundant) | 1 GPU à 600 W | +| iLO Adv + Support | 5 J. | 5 J. Tech Care Essential | unverändert | + +**Grobe Kostenschätzung:** Server-Basis + CPU + RAM + Storage ≈ 10–12 k€, +GPU ≈ 9–10 k€, Support ≈ 4–6 k€ → **~23–28 k€**. Es bleibt Budget für +Einrichtung/Software-Dienstleistung (RAG-Pipeline!) und ggf. eine zweite GPU +später — das Chassis dafür gleich mit einplanen (Riser/Netzteile). + +## 4. Passt eine GPU für "viele Nutzer"? + +Ja, für den beschriebenen Fall (Nicht-Power-User, Chat + Datei-Suche): + +- Nicht-Power-User erzeugen wenig gleichzeitige Last; realistisch sind + 5–20 parallele Anfragen selbst bei 100+ angebundenen Usern. +- vLLM mit einem 20–32B-Modell in FP8 auf 96 GB bedient das komfortabel; + ein 70B-Modell geht ebenfalls, mit weniger Parallelitäts-Headroom. +- Wachstumspfad: zweite RTX PRO 6000 nachrüsten (zwei unabhängige + vLLM-Instanzen bzw. Modell-Replikation — kein NVLink nötig). + +## Quellen + +- [RTX PRO 6000 vs H100/H200/L40S LLM Inference Benchmarks (cloudrift.ai)](https://www.cloudrift.ai/blog/benchmarking-rtx6000-vs-datacenter-gpus) +- [RTX PRO 6000 Pricing July 2026 (Thunder Compute)](https://www.thundercompute.com/blog/nvidia-rtx-pro-6000-pricing) +- [L40S vs RTX PRO 6000 (gpuperhour)](https://gpuperhour.com/compare/l40s-vs-rtx-pro-6000-blackwell) +- [RTX PRO 6000 vs H100 for AI Inference (OpenMetal)](https://openmetal.io/resources/blog/comparing-the-nvidia-rtx-pro-6000-vs-h100-for-ai-inference/) +- [RTX PRO 6000 Benchmarks: 30B AWQ, 70B FP8, Cost per Mtok (Spheron)](https://www.spheron.network/blog/rent-nvidia-rtx-pro-6000/) diff --git a/server/phy-z-srv-gpu01/20260706-software-assessment.md b/server/phy-z-srv-gpu01/20260706-software-assessment.md new file mode 100644 index 0000000..33be9f7 --- /dev/null +++ b/server/phy-z-srv-gpu01/20260706-software-assessment.md @@ -0,0 +1,119 @@ +# Software Assessment — GPU Server für LLM-Workloads + +Date: 2026-07-06 +Status: Draft for internal review + +## TL;DR + +**LM Studio ist als Server-Dienst für viele Benutzer nicht geeignet.** Es ist ein +Desktop-Tool für Einzelnutzer. Empfehlung: **vLLM** als Inference-Server + +**Open WebUI** als Benutzeroberfläche (Multi-User, LDAP). Für die Datei-Suche +über SMB-Shares wird zusätzlich eine RAG-/Enterprise-Search-Komponente +benötigt — das ist der eigentlich anspruchsvolle Teil des Projekts, nicht das +LLM-Hosting. + +## 1. Ist LM Studio als Server-Dienst geeignet? + +Kurz: **Nein**, nicht für den Multi-User-Betrieb. + +Was LM Studio inzwischen kann: + +- Headless-Betrieb ohne GUI über den `llmster`-Daemon (offiziell dokumentiert: + [lmstudio.ai/docs/app/api/headless](https://lmstudio.ai/docs/app/api/headless)) +- OpenAI-kompatible lokale API +- Seit 2025 auch für kommerzielle Nutzung kostenlos + +Warum es trotzdem ungeeignet ist: + +| Anforderung | LM Studio | +|---|---| +| Multi-User / Benutzerverwaltung | ❌ Keine — die API ist für einen lokalen Einzelnutzer gedacht, ohne Benutzerkonten | +| LDAP/AD-Anbindung | ❌ Nicht vorhanden | +| Gleichzeitige Anfragen vieler Nutzer | ❌ llama.cpp-Backend, kein Continuous Batching wie vLLM — Durchsatz bricht bei Parallelität ein | +| Modell-Verwaltung im Betrieb | ⚠️ Modell-Laden ist exklusiv; Wechsel unterbricht den Dienst | +| RAG / Suche über Netzlaufwerke | ❌ Nur lokale Datei-Anhänge im Chat, keine Index-Pipeline | + +Fazit: LM Studio bleibt sinnvoll als **lokales Tool für Power-User am +Arbeitsplatz**, aber der Server braucht einen echten Inference-Stack. + +## 2. Empfohlener Software-Stack + +``` +[User-Browser] ──► Open WebUI (Auth via LDAP/AD, Chat-UI, RAG) + │ OpenAI-kompatible API + ▼ + vLLM (Inference-Server, Continuous Batching) + ▼ + 1× GPU (96 GB VRAM) + +[SMB-Shares] ──► Index-Pipeline (Embedding + Vektor-DB) ──► RAG-Abfragen +``` + +### Inference: vLLM + +- De-facto-Standard für Multi-User-LLM-Serving: Continuous Batching, + PagedAttention, hoher Durchsatz bei vielen gleichzeitigen Nutzern +- OpenAI-kompatible API → jedes Frontend (auch LM Studio-Clients der + Power-User) kann sich verbinden +- Läuft als Docker-Container, gut automatisierbar + +### Frontend: Open WebUI + +- Multi-User mit Rollen/Gruppen, **native LDAP-Anbindung** (deckt die + Anforderung "Alle User angebunden (LDAP?)" aus den Notizen ab) +- Chat-UI im ChatGPT-Stil — geeignet für Nicht-Power-User +- Eingebaute RAG-Funktion ("Knowledge Bases"): Dokumente hochladen und + durchsuchen + +### Datei-Suche über SMB-Shares — der kritische Punkt + +"Suchmaschine für eigene Daten" heißt: die Shares müssen **indiziert** werden +(Embedding-Modell + Vektor-Datenbank), nicht nur per Chat angehängt. Optionen: + +1. **Open WebUI Knowledge Bases** — seit v0.9.6 mit offiziellem Sync-Tool + `oikb`: gemountete Verzeichnisse (→ SMB-Shares) werden inkrementell in + Knowledge Bases gespiegelt. Details: `20260707-deep-dive.md` §4.3. +2. **Onyx (ehem. Danswer)** — dediziertes Enterprise-Search-Produkt, + Konnektoren für Datei-Quellen, eigene Benutzer-/Rechteverwaltung, + nutzt das lokale LLM via OpenAI-API. Passender für den Vollausbau. +3. Eigene Pipeline (gemountete Shares + Embedding-Job + Qdrant/pgvector) — + maximale Kontrolle, mehr Aufwand. + +⚠️ **Offener Punkt, vor Angebot klären:** Müssen Suchergebnisse die +NTFS-/Share-Berechtigungen respektieren (User A darf Dokumente von Abteilung B +nicht sehen)? **Permission-Trimming ist in keiner der Standard-Lösungen +trivial** und bestimmt maßgeblich Aufwand und Produktwahl. Wenn ja, ist Onyx +oder eine kommerzielle Lösung fast zwingend; wenn die Shares ohnehin für alle +lesbar sind, reicht der einfache Stack. + +### Modelle (bei 96 GB VRAM) + +- Start: ein 20–32B-Instruct-Modell (z. B. Qwen3-32B oder gpt-oss-20b) in + FP8 — schnell, viel KV-Cache-Headroom für viele parallele Nutzer, gutes + Deutsch +- Option: 70B-Klasse in FP8 oder gpt-oss-120b (MXFP4, ~63 GB) passt auf die + eine Karte, wenn mehr Qualität gewünscht ist — auf Kosten des Durchsatzes +- Zusätzlich ein Embedding-Modell für die Suche (z. B. multilingual-e5 oder + bge-m3, klein, läuft nebenher auf derselben GPU) + +### Betrieb + +- Ubuntu Server 24.04 LTS, NVIDIA-Treiber + Container Toolkit +- Alles als Docker Compose (vLLM, Open WebUI, Vektor-DB) → reproduzierbar, + einfache Updates +- Backup nur für Konfiguration + Vektor-DB nötig; Modelle sind wiederbeschaffbar + +## 3. Offene Fragen an den Kunden + +1. Wie viele Benutzer insgesamt / gleichzeitig? (bestimmt Modellgröße) +2. Datenvolumen und Dateitypen auf den Shares? (Office, PDF, Scans/OCR?) +3. Müssen Berechtigungen der Shares in der Suche durchgesetzt werden? (s. o.) +4. Nur Chat + Suche, oder auch API-Zugriff für Anwendungen/Skripte? + +## Quellen + +- [LM Studio Docs — Headless/llmster](https://lmstudio.ai/docs/app/api/headless) +- [Top 20 Tools to Run LLMs Locally in 2026 (iunera)](https://www.iunera.com/kraken/enterprise-ai/top-20-tools-to-run-llms-locally-in-2026-ollama-anythingllm-open-webui-lm-studio-vllm-and-every-real-alternative-compared/) +- [Open WebUI Overview (glukhov.org)](https://www.glukhov.org/llm-hosting/llm-frontends/open-webui-overview-quickstart-and-alternatives/) +- [LM Studio Complete Guide 2026 (codersera)](https://codersera.com/blog/lm-studio-complete-guide-2026/) +- [Open WebUI + LM Studio Integration (markaicode)](https://markaicode.com/integrate/open-webui-with-lm-studio/) diff --git a/server/phy-z-srv-gpu01/20260707-deep-dive.md b/server/phy-z-srv-gpu01/20260707-deep-dive.md new file mode 100644 index 0000000..3f9e518 --- /dev/null +++ b/server/phy-z-srv-gpu01/20260707-deep-dive.md @@ -0,0 +1,427 @@ +# Deep Dive — GPU-Auswahl, Inference-Backend & Anbindung der SMB-Wissensbasis + +Date: 2026-07-07 +Status: Entscheidungsgrundlage für Kundengespräch +Basiert auf: `20260706-hardware-assessment.md`, `20260706-software-assessment.md` + +--- + +## 0. Executive Summary + +| Entscheidung | Empfehlung | Konfidenz | +|---|---|---| +| GPU | **RTX PRO 6000 Blackwell Server Edition (96 GB)** statt H100 NVL | Hoch — durch mehrere unabhängige Benchmarks gedeckt | +| LM Studio als Server | **Nein** — Desktop-Tool, kein Mehrbenutzer-Server | Hoch | +| Inference-Backend | **vLLM** (ggf. Ollama zusätzlich für Power-User-Experimente) | Hoch | +| Frontend | **Open WebUI** (LDAP/AD, Gruppen, Knowledge Bases) | Hoch | +| SMB-Anbindung | **Phase 1: Open WebUI Knowledge + offizielles Sync-Tool `oikb`**; Phase 2: Onyx nur falls Skalierung/Berechtigungen es erzwingen | Mittel — hängt von offenen Fragen ab (§6) | + +--- + +## 1. GPU: RTX PRO 6000 Blackwell SE vs. H100 NVL + +Der Kunde hat die H100 genannt. Das ist verständlich („die KI-GPU"), aber die +H100 ist eine **Hopper-Karte von 2022/23** und für verteiltes Training bzw. +Multi-GPU-Inference gebaut. Die RTX PRO 6000 Blackwell Server Edition (2025) +ist **zwei Architektur-Generationen neuer** und von NVIDIA explizit als +Enterprise-Inference-Karte positioniert. + +### 1.1 Daten im Vergleich + +| | RTX PRO 6000 Blackwell SE | H100 NVL | +|---|---|---| +| Architektur | Blackwell (2025) | Hopper (2022/23) | +| VRAM | **96 GB GDDR7, ECC** | 94 GB HBM3, ECC | +| Speicherbandbreite | 1,79 TB/s | **3,9 TB/s** | +| FP8 / FP4 (NVFP4) | ✅ / **✅** | ✅ / ❌ | +| MIG (GPU-Partitionierung) | ✅ bis 4 Instanzen ([NVIDIA](https://www.nvidia.com/en-us/data-center/rtx-pro-6000-blackwell-server-edition/)) | ✅ bis 7 Instanzen | +| vGPU-Support | ✅ (vGPU 19.0, [NVIDIA Blog](https://developer.nvidia.com/blog/nvidia-vgpu-19-0-enables-graphics-and-ai-virtualization-on-nvidia-blackwell-gpus/)) | ✅ | +| NVLink | ❌ (nur PCIe Gen5) | ✅ (Paarweise) | +| Leistungsaufnahme | 600 W (passiv, Server-Kühlung) | ~400 W | +| Formfaktor | PCIe FHFL Dual-Slot, OEM-qualifiziert (u. a. [Lenovo](https://lenovopress.lenovo.com/lp2263-thinksystem-nvidia-rtx-pro-6000-blackwell-server-edition-pcie-gen5-gpu), HPE) | PCIe Dual-Slot | +| Straßenpreis | **~9–10 k€** | ~31 k€ (lt. Referenz-Angebot) | + +### 1.2 Benchmark-Evidenz (der Kern der Argumentation) + +Mehrere **unabhängige** Quellen, alle mit vLLM als Serving-Stack: + +1. **Single-GPU-Durchsatz:** RTX PRO 6000 schlägt sogar die H100 SXM + (3.140 vs. 2.987 tok/s) bei **28 % niedrigeren Kosten pro Token** + ([cloudrift.ai](https://www.cloudrift.ai/blog/benchmarking-rtx6000-vs-datacenter-gpus)). +2. **Unter Parallellast** (unser Szenario!): stärkste Skalierung aller + getesteten Karten; auf Qwen-32B vor A100 **und** H100 + ([databasemart vLLM-Benchmark](https://www.databasemart.com/blog/vllm-gpu-benchmark-pro6000)). +3. **Bei 100 gleichzeitigen Requests**: bis zu **1,63× höherer Durchsatz als + die H100** ([Akamai-Benchmark](https://www.akamai.com/blog/cloud/benchmarking-nvidia-rtx-pro-6000-blackwell-akamai-cloud)). +4. Kostenanalyse pro Million Token: [Spheron](https://www.spheron.network/blog/rent-nvidia-rtx-pro-6000/), + unabhängige Tests: [HOSTKEY](https://huggingface.co/blog/HOSTKEY/nvidia-rtx-6000-blackwell-server-edition-tests-ben), + Vergleich: [OpenMetal](https://openmetal.io/resources/blog/comparing-the-nvidia-rtx-pro-6000-vs-h100-for-ai-inference/). + +Warum schlägt GDDR7 hier HBM3? Die H100 spielt ihre Bandbreite erst bei +Multi-GPU-Tensor-Parallelität über NVLink aus. Bei **einer** Karte limitiert +meist Compute/KV-Cache-Management — und da ist Blackwell schlicht neuer +(mehr FP8/FP4-Durchsatz, größere L2-Caches, besserer Scheduler). + +### 1.3 Wann wäre die H100 trotzdem richtig? (Ehrlichkeit fürs Gespräch) + +- **Multi-GPU-Modelle**: Modelle > 96 GB über 2+ GPUs gespannt → NVLink + gewinnt deutlich (8× H100 SXM ≈ 3× Durchsatz von 8× RTX PRO 6000). +- **Training/Fine-Tuning im Dauerbetrieb** über mehrere Karten. +- **Extreme Kontextlängen + sehr hohe Batchgrößen** (Bandbreiten-limitiert). + +**Keiner dieser Punkte trifft hier zu**: 1 GPU, reine Inference, ≤ 20 +gleichzeitige Anfragen, Modelle ≤ 96 GB. Selbst der Wachstumspfad (zweite +RTX PRO 6000, zwei unabhängige vLLM-Replikate) braucht kein NVLink. + +### 1.4 Argumentationslinie für den Kunden (Kurzform) + +1. „Die H100 ist eine 2022er-Architektur am Ende ihres Zyklus; die RTX PRO + 6000 ist NVIDIAs aktuelle Enterprise-Inference-Karte (Blackwell, 2025)." +2. „Für genau unser Szenario — eine Karte, viele gleichzeitige Chat-Anfragen — + ist sie in unabhängigen Benchmarks **gleich schnell bis 1,6× schneller**." +3. „Mehr Speicher (96 vs. 94 GB), ECC, MIG, vGPU — alle Enterprise-Merkmale + vorhanden, OEM-qualifiziert (HPE/Lenovo/Dell)." +4. „**Ein Drittel des Preises.** Die Differenz (~21 k€) finanziert die + eigentliche Wertschöpfung — die Such-Pipeline — oder eine zweite GPU." +5. Einziger technischer Trade-off: kein NVLink und höhere Leistungsaufnahme + (600 W) — beides für diesen Use Case irrelevant bzw. vom Chassis abgedeckt. + +⚠️ Vor Angebot prüfen: HPE-Qualifizierung der Karte für das konkrete Chassis +(DL380 Gen12 / DL380a) und vBIOS-Stand für MIG. + +### 1.5 Alternativen — vollständig geprüft (Stand Juli 2026) + +Re-Evaluation gegen das gesamte Feld, nicht nur gegen die H100: + +| Kandidat | VRAM | Preis (ca.) | Bewertung für unseren Fall | +|---|---|---|---| +| **RTX PRO 6000 Blackwell SE** | 96 GB | **~9–10 k€** | ✅ Empfehlung — s. §1.2, aber Risiken in §1.6 beachten | +| H100 NVL | 94 GB | ~26–30 k€ | Ausgereifteste Software-Basis (Hopper/SM90), sonst in allen Benchmarks unterlegen; 3× Preis. **Der risikoärmste, teuerste Weg.** | +| H200 NVL | 141 GB | ~30–42 k€ ([IntuitionLabs](https://intuitionlabs.ai/articles/nvidia-ai-gpu-pricing-guide), [JarvisLabs](https://jarvislabs.ai/blog/h200-price)) | 45 GB mehr VRAM als nötig; Preis wie H100+15–20 %. Nur sinnvoll bei Modellen > 96 GB — nicht unser Fall. | +| L40S | 48 GB | ~8 k€ | Halber Speicher, weniger als halber Durchsatz (864 GB/s, Ada 2022, kein FP4), kaum billiger. Von der RTX PRO 6000 obsolet gemacht. | +| 2× RTX PRO 5000 Blackwell | 2×48 GB | ~9 k€ | Gleicher Gesamt-VRAM, aber Tensor-Parallel über PCIe (Overhead), doppelte Komplexität, gleiche SM120-Risiken. Kein Vorteil. | +| RTX 5090 (Consumer) | 32 GB | ~2,5 k€ | Kein ECC, keine OEM-/Server-Qualifizierung, EULA-Grauzone im Rechenzentrum, 32 GB zu klein. Nein. | +| AMD MI300X | 192 GB | ~15–18 k€ ([gpucost](https://gpucost.org/gpu/mi300x)) | Auf dem Papier attraktiv (192 GB!), ROCm/vLLM inzwischen First-Class ([AMD](https://rocm.blogs.amd.com/software-tools-optimization/vllm-omni/README.html)). Aber: **OAM-Modul, keine PCIe-Einzelkarte** — existiert praktisch nur in 8-GPU-Plattformen, nicht im ProLiant-2U. Dazu ROCm-Betriebsrisiko ohne AMD-Erfahrung im Team. Scheidet formfaktorbedingt aus. | + +Fazit der Re-Evaluation: Die Empfehlung **hält**. Die einzige echte +Alternative ist die H100 NVL als „konservative Versicherung" zum 3-fachen +Preis — alle anderen Kandidaten scheitern an Formfaktor, Speicher oder +Preis-Leistung. + +### 1.6 Risiken der RTX PRO 6000 SE — ehrlich benannt (wichtig!) + +Die Karte ist neue Architektur (Blackwell/SM120), und 2025 bis Anfang 2026 +gab es dokumentierte Kinderkrankheiten: + +- **Kernel-Kompatibilität**: SM120 ist nicht abwärtskompatibel zu + Hopper-Kerneln; exotische Modellarchitekturen liefen anfangs nicht + (z. B. [DeepSeek-Serie](https://github.com/vllm-project/vllm/issues/26211), + [NVFP4-Kernel](https://github.com/vllm-project/vllm/issues/23497)). + Mainstream-Modelle (Llama, Qwen, Mistral, gpt-oss) sind davon nicht + betroffen. +- **Reset-Bug bei Virtualisierung** (VM-Passthrough): GPU nach VM-Shutdown + in unrecoverable state; ab Treiber 580+ weitgehend behoben. → **Bare-Metal + betreiben** (ohnehin empfohlen). +- Vereinzelte Berichte über GPU-Resets unter Dauerlast und ein + [offenes vLLM-Issue (03/2026)](https://github.com/vllm-project/vllm/issues/36327) — + letzteres betrifft `--tensor-parallel-size 4`, also **Multi-GPU, nicht + unsere Single-GPU-Konfiguration**. + +**Warum das Risiko tragbar ist (Stand Juli 2026):** + +1. NVIDIA führt die Karte offiziell in den + [vLLM-Release-Notes](https://docs.nvidia.com/deeplearning/frameworks/vllm-release-notes/rel-25-09.html) + (funktionaler Support, CUDA 13.0) und stellt einen eigenen + [vLLM-Container für RTX](https://build.nvidia.com/rtx/vllm) bereit. +2. Systemhäuser liefern inzwischen **vLLM-vorvalidierte Server mit genau + dieser Karte** aus ([VRLA Tech](https://vrlatech.com/running-vllm-on-your-own-hardware-the-production-guide-for-2026/)). +3. HPE-qualifizierte Karte + Support-Vertrag = Hardware-Risiko abgedeckt. + +**Absicherung im Projekt:** aktueller Treiber (≥ 580/581), NVIDIA-vLLM- +Container statt Eigenbau, Bare-Metal, Mainstream-Modell, und die Pilotphase +(§4.7) als **Burn-in-Test** nutzen — 2 Wochen Dauerlast vor Produktivsetzung. +Falls der Kunde maximale Risikoaversion über Preis stellt: H100 NVL als +dokumentierte Alternative anbieten und die Differenz transparent machen +(~20 k€ „Versicherungsprämie" für ausgereiftere Software-Basis). + +--- + +## 2. Warum LM Studio (llmster) kein Server ist — Argumentation + +LM Studio ist bei den Mitarbeitern bekannt und beliebt — das Argument muss +also respektvoll sein: **das Tool ist gut, aber es löst eine andere Aufgabe.** + +| Server-Anforderung | LM Studio / llmster | Server-Stack (vLLM + Open WebUI) | +|---|---|---| +| Benutzerkonten & Login | ❌ keine Benutzerverwaltung | ✅ LDAP/AD, Rollen, Gruppen | +| Wer darf was (Modelle, Daten)? | ❌ ein API-Key für alle | ✅ RBAC pro Gruppe/Ressource | +| 10–20 gleichzeitige Anfragen | ❌ llama.cpp-Engine, Anfragen stauen sich | ✅ Continuous Batching | +| Zentrale Wissensbasis (SMB) | ❌ nur lokale Datei-Anhänge pro Chat | ✅ zentrale, gepflegte Indizes | +| Audit/Protokollierung | ❌ | ✅ | +| Betrieb (Updates, Monitoring, HA) | ⚠️ Desktop-App-Zyklus | ✅ Container, Standard-Ops | + +Kernsatz fürs Gespräch: *„llmster macht aus LM Studio einen Dienst ohne +Bildschirm — aber nicht ohne die Einzelnutzer-Architektur. Es fehlt alles, +was aus einem laufenden Modell einen Firmendienst macht: Anmeldung, +Berechtigungen, Parallelität, zentrale Datenanbindung."* + +Wichtig: Die Mitarbeiter **verlieren nichts** — Open WebUI fühlt sich wie +ChatGPT an (einfacher als LM Studio), und Power-User können LM Studio lokal +weiterverwenden oder per API-Key direkt gegen den Server arbeiten. + +--- + +## 3. Inference-Backend: vLLM vs. Ollama + +Beide sprechen die OpenAI-API und funktionieren mit Open WebUI. Der +Unterschied liegt in Architektur und Zielgruppe. + +### 3.1 Ist vLLM wirklich effizienter? Ja — deutlich, sobald parallel + +Aktuelle Benchmarks (2025/26): + +- Bei **50 gleichzeitigen Nutzern**: vLLM ~920 tok/s gesamt, Ollama + plateauiert bei ~155 tok/s; je nach Test **20–29× mehr Durchsatz** und + 8–19× niedrigere P95-Latenz ([runaihome](https://runaihome.com/blog/vllm-vs-ollama-when-each-wins-2026/), + [tech-insider](https://tech-insider.org/vllm-vs-ollama-2026/)). +- Peer-reviewte Studie: Ollama erreicht **Engpass bei ~10 gleichzeitigen + Nutzern**, 13–30 % Timeouts unter Last; vLLM 100 % Erfolgsquote + ([MDPI Applied Sciences](https://doi.org/10.3390/app16115435)). +- Bei **einem einzelnen Nutzer** ist Ollama minimal schneller beim ersten + Token (~45 vs. ~82 ms TTFT) — irrelevant für einen Firmenserver + ([Red Hat Benchmark](https://developers.redhat.com/articles/2025/08/08/ollama-vs-vllm-deep-dive-performance-benchmarking), + [SitePoint](https://www.sitepoint.com/ollama-vs-vllm-performance-benchmark-2026/)). + +### 3.2 Der Modellwechsel-Trade-off, korrekt dargestellt + +| | Ollama | vLLM | +|---|---|---| +| Modellwechsel | ✅ automatisch, lädt/entlädt on-the-fly | ⚠️ 1 Modell pro Instanz, Wechsel = Neustart (1–2 min) | +| Mehrere Modelle parallel | ⚠️ ja, aber teilen sich GPU unkontrolliert | ✅ mehrere Instanzen mit fester VRAM-Zuteilung | +| Durchsatz unter Last | ❌ s. o. | ✅ | + +Die Flexibilität von Ollama ist im Firmenbetrieb **weniger wert, als sie +klingt**: Nicht-Power-User wollen kein Modell wählen — sie wollen, dass es +funktioniert. Ein ungeplanter Modellwechsel entlädt zudem das Modell der +anderen 15 aktiven Nutzer (Kaltstart-Latenz für alle). + +**Empfehlung — kein Entweder-oder:** + +``` +GPU (96 GB, via MIG oder VRAM-Quoten aufteilbar) +├── vLLM #1: Haupt-Chatmodell (fest, z. B. Qwen3-32B FP8) ~40 GB +├── vLLM #2: Embedding-Modell für die Suche ~4 GB +└── optional Ollama: Spielwiese für Power-User Rest +``` + +Open WebUI kann mehrere Backends gleichzeitig einbinden — die Normalnutzer +sehen nur „Firmen-Assistent", Power-User sehen zusätzlich die +Ollama-Modelle. Damit ist die Kundenfrage („Flexibilität vs. Effizienz") +keine Entscheidung mehr, sondern eine Konfiguration. + +### 3.3 Lastabschätzung (100 Mitarbeiter) + +Erfahrungswerte für interne Chat-Assistenten: ~30–60 % registrieren sich, +davon ~10–20 % gleichzeitig aktiv in Spitzen → **5–15 parallele Anfragen**. +Das bedient eine RTX PRO 6000 mit einem 32B-FP8-Modell unter vLLM komfortabel +(vgl. Benchmarks oben: brauchbare Latenz noch bei 50–100 parallelen Requests +mit kleineren Modellen). + +--- + +## 4. Anbindung der Wissensbasis (SMB-Shares) — der Deep Dive + +### 4.1 Was technisch passieren muss (unabhängig vom Produkt) + +Ein LLM kann nicht „auf den Share schauen". Die Pipeline ist immer: + +``` +SMB-Share ──mount──► Server (read-only, Service-Account) + │ + ▼ +Extraktion (PDF, Office, E-Mail…; OCR für Scans) + ▼ +Chunking + Embedding (Embedding-Modell auf der GPU) + ▼ +Vektor-Datenbank (Index) ← periodischer Sync (cron) + ▼ +Retrieval zur Laufzeit: Frage → relevante Chunks → LLM antwortet mit Quellen +``` + +Die Produktfrage ist nur: **wer betreibt diese Pipeline und wie gut?** + +### 4.2 Option A — LM Studio: scheidet aus + +Kein zentraler Index möglich. Jeder Nutzer müsste Dateien manuell in seinen +Chat ziehen (RAG pro Sitzung, wenige Dateien). Für „Suchmaschine über die +Firmendaten" schlicht das falsche Werkzeug — unabhängig von der Serverfrage. + +### 4.3 Option B — Open WebUI Knowledge + offizielles Sync-Tool `oikb` ⭐ + +Seit **v0.9.6** hat Open WebUI eine offizielle Lösung genau für unseren Fall +([Docs](https://docs.openwebui.com/features/knowledge-base-sync/), +[GitHub open-webui/oikb](https://github.com/open-webui/oikb)): + +- **`oikb`** (CLI, [PyPI](https://pypi.org/project/oikb/)) synchronisiert ein + Verzeichnis — also einen **auf dem Server gemounteten SMB-Share** — in eine + Knowledge Base: inkrementell per SHA-256-Diff, nur neue/geänderte Dateien + werden neu embedded, Löschungen werden nachgezogen, Ordnerstruktur wird + gespiegelt. Ein unveränderter 10.000-Dateien-Bestand re-synct in Sekunden. +- Läuft als **Cron/systemd-Timer pro Share** → vollautomatisch, kein + Nutzer-Zutun. +- **Berechtigungen**: Knowledge Bases sind per Gruppe zugreifbar; Open WebUI + synchronisiert **Gruppen direkt aus LDAP/AD** + ([LDAP-Doku](https://docs.openwebui.com/features/authentication-access/auth/ldap/)). + Damit lässt sich die Share-Struktur abbilden: + + ``` + \\fs01\konstruktion ──oikb──► KB "Konstruktion" ──► AD-Gruppe Konstruktion + \\fs01\vertrieb ──oikb──► KB "Vertrieb" ──► AD-Gruppe Vertrieb + \\fs01\allgemein ──oikb──► KB "Allgemein" ──► alle + ``` + +- **Nutzererlebnis Normies**: Vorkonfigurierte „Modelle" in Open WebUI + (z. B. „Konstruktions-Assistent" = Chatmodell + KB Konstruktion fest + verdrahtet). Der Nutzer wählt den Assistenten und fragt auf Deutsch — + kein RAG-Wissen nötig, Antworten mit Quellenangabe (Datei + Passage). +- **Power-User**: können eigene Knowledge Bases anlegen, per `#` gezielt + Kollektionen in den Chat holen, oder per API-Key direkt gegen vLLM arbeiten + (IDE-Integration, Skripte). + +**Grenzen (ehrlich einplanen):** + +1. **Berechtigungsgranularität = Share/Ordner-Ebene**, nicht NTFS-Datei-ACL. + Wer Zugriff auf die KB „Konstruktion" hat, kann alles darin erfragen. +2. **Skala**: praktikabel bis in den Bereich von einigen zehntausend + Dokumenten pro Kollektion; bei sehr großen Shares selektiv syncen + (Unterordner, Dateitypen-Filter). Für den DB-Unterbau bei Wachstum + **pgvector statt Default** einplanen ([Scaling-Doku](https://docs.openwebui.com/getting-started/advanced-topics/scaling/)). +3. **Extraktionsqualität** hängt von den Dateitypen ab: Office/PDF gut; + **gescannte PDFs brauchen OCR** (Tika/Docling als Extraktions-Engine + konfigurieren); CAD/proprietäre Formate bleiben außen vor. + +### 4.4 Option C — Onyx (ehem. Danswer) als dedizierte Such-Anwendung + +[Onyx](https://github.com/onyx-dot-app/onyx) ist ein spezialisiertes +Enterprise-Search-Produkt mit 50+ Konnektoren, darunter ein **File Connector +für lokale/Netzlaufwerke** ([Connector-Doku](https://docs.onyx.app/overview/core_features/connectors)) — +SMB-Anbindung also wie bei Option B über einen Mount, aber mit produktisierter +Crawling-/Index-Pipeline. + +- **Stärken**: bessere Such-Ergonomie (hybride Suche, Reranking), skaliert + auf große Bestände, Konnektoren für spätere Quellen (SharePoint, Wiki, + E-Mail…), eigenes Berechtigungsmodell. +- **Schwächen für unseren Fall**: + - **Document-Level Permission Sync ist Enterprise Edition** (kostenpflichtig) + und primär für Cloud-Quellen (SharePoint, Google Drive) gebaut — für + SMB-NTFS-ACLs gibt es auch hier **keine fertige Lösung**. + - **Zweite Anwendung** mit eigener UI, eigener Nutzerverwaltung, eigenem + Betrieb (mehrere Container, Vespa-Index, Worker) — spürbar mehr + Betriebsaufwand als Option B. + - Zwei UIs für die Nutzer (Chat in Open WebUI, Suche in Onyx) oder man + ersetzt Open WebUI ganz durch Onyx' Chat — dann verliert man dessen + Flexibilität (Multi-Backend, Power-User-Features). + +### 4.5 Option D — Eigenbau-Pipeline (Qdrant/pgvector + eigener Indexer) + +Maximale Kontrolle (eigenes ACL-Modell, beliebige Formate/OCR, Anbindung an +Open WebUI über dessen Pipelines/Tools-API) — aber man betreibt und wartet +eine Individualsoftware. Nur gerechtfertigt, wenn **Datei-genaue +NTFS-Berechtigungen** harte Anforderung sind; dann als Projekt kalkulieren +(mehrere Wochen Entwicklung + laufende Pflege). + +### 4.6 Entscheidungsmatrix + +| Kriterium | B: Open WebUI + oikb | C: Onyx | D: Eigenbau | +|---|---|---|---| +| Aufwand Einführung | **niedrig** (Tage) | mittel (Wochen) | hoch | +| Betriebsaufwand | **niedrig** (1 Stack) | mittel (2 Stacks) | hoch | +| Berechtigungen | Share/Ordner-Ebene via AD-Gruppen | ähnlich; Datei-Ebene nur EE + nicht für SMB | frei gestaltbar | +| Suchqualität große Bestände | gut bis ~10⁴–10⁵ Docs | **sehr gut, skaliert** | je nach Bau | +| Normie-Tauglichkeit | **sehr gut** (ein UI, Assistenten) | gut | je nach Bau | +| Power-User | **sehr gut** (API, eigene KBs, Ollama) | mittel | gut | +| Kosten | Open Source | OSS; Permissions = EE-Lizenz | Entwicklungszeit | + +### 4.7 Empfehlung: Phasenmodell + +- **Phase 1 (Pilot, ~4–6 Wochen):** vLLM + Open WebUI + LDAP + `oikb` auf + 1–2 ausgewählte Shares (read-only Service-Account). Misst reale Nutzung, + Suchqualität und die tatsächliche Parallellast — mit minimalem Invest. +- **Phase 2 (Entscheid nach Pilot):** Bleiben = Ausbau Option B (mehr Shares, + pgvector, OCR). Nur bei nachgewiesenem Bedarf (sehr große Bestände, harte + Berechtigungsanforderungen) → Onyx bzw. Eigenbau ergänzen. Die + Investition aus Phase 1 (Server, vLLM, LDAP, Mounts) bleibt vollständig + erhalten — Onyx würde denselben vLLM-Endpunkt nutzen. + +Das Phasenmodell ist auch das Verkaufsargument: kein Big-Bang, Budget bleibt +unter Kontrolle, und die GPU-Ersparnis aus §1 finanziert die Pilotphase. + +--- + +## 5. Gesamtbild (Zielarchitektur Phase 1) + +``` + ┌────────────────────────────────────────────┐ + Mitarbeiter ────────►│ Open WebUI (LDAP/AD-Login, Gruppen) │ + (Browser) │ ├─ „Firmen-Assistent" + KB je Abteilung │ + │ └─ Power-User: API-Keys, eigene KBs │ + └───────┬────────────────────────┬───────────┘ + Power-User ─────────────────►│ OpenAI-API │ Retrieval + (Skripte, IDE, LM Studio ▼ ▼ + lokal als Client) vLLM #1 Chat 32B FP8 Vektor-DB (pgvector) + vLLM #2 Embeddings ▲ + ┌──────────────────────┐ │ oikb-Sync (cron) + │ RTX PRO 6000 96 GB │ SMB-Mounts (ro) + └──────────────────────┘ ▲ + \\fs01\... Shares +``` + +## 6. Offene Fragen an den Kunden (vor Angebotslegung) + +1. **Berechtigungen** (kritischster Punkt): Genügt Zugriffssteuerung auf + Share-/Ordner-Ebene via AD-Gruppen — oder müssen Datei-genaue NTFS-ACLs + durchgesetzt werden? (Letzteres = Eigenbau-Anteil, deutlich teurer.) +2. **Datenbestand**: Wie viele Shares, wie viel Volumen, welche Dateitypen? + Anteil gescannter Dokumente (OCR-Bedarf)? CAD-Daten relevant? +3. **Nutzerkreis**: Wie viele der ~100 Mitarbeiter sollen initial angebunden + werden? Gibt es Abteilungen mit Priorität? +4. **H100-Motivation**: Steht hinter dem H100-Wunsch eine konkrete Anforderung + (Training? Zukunftspläne?) oder Markenwahrnehmung? → bestimmt, wie viel + der Argumentation aus §1.4 nötig ist. +5. **Virtualisierung**: Soll die GPU ggf. in eine VM-Umgebung (vGPU/MIG, + Lizenzthema) oder Bare-Metal-Betrieb (empfohlen, einfacher)? +6. **Sprache**: Dokumente überwiegend Deutsch? (Modellwahl: Qwen3/Mistral/ + Llama sind mehrsprachig solide; Embedding-Modell muss multilingual sein, + z. B. bge-m3.) + +## 7. Quellen + +**GPU:** +[NVIDIA RTX PRO 6000 Blackwell SE](https://www.nvidia.com/en-us/data-center/rtx-pro-6000-blackwell-server-edition/) · +[cloudrift.ai Benchmark](https://www.cloudrift.ai/blog/benchmarking-rtx6000-vs-datacenter-gpus) · +[Akamai Benchmark](https://www.akamai.com/blog/cloud/benchmarking-nvidia-rtx-pro-6000-blackwell-akamai-cloud) · +[databasemart vLLM-Benchmark](https://www.databasemart.com/blog/vllm-gpu-benchmark-pro6000) · +[HOSTKEY Tests](https://huggingface.co/blog/HOSTKEY/nvidia-rtx-6000-blackwell-server-edition-tests-ben) · +[OpenMetal RTX PRO 6000 vs H100](https://openmetal.io/resources/blog/comparing-the-nvidia-rtx-pro-6000-vs-h100-for-ai-inference/) · +[Spheron Cost/Mtok](https://www.spheron.network/blog/rent-nvidia-rtx-pro-6000/) · +[Lenovo Product Guide](https://lenovopress.lenovo.com/lp2263-thinksystem-nvidia-rtx-pro-6000-blackwell-server-edition-pcie-gen5-gpu) · +[NVIDIA vGPU 19.0](https://developer.nvidia.com/blog/nvidia-vgpu-19-0-enables-graphics-and-ai-virtualization-on-nvidia-blackwell-gpus/) · +[MIG auf RTX PRO 6000 (Medium)](https://medium.com/@sangjinn/maximize-your-gpu-efficiency-configuring-4-nvidia-mig-instances-on-the-rtx-pro-6000-blackwell-1c9b3714af61) + +**vLLM vs Ollama:** +[Red Hat Benchmark](https://developers.redhat.com/articles/2025/08/08/ollama-vs-vllm-deep-dive-performance-benchmarking) · +[MDPI-Studie](https://doi.org/10.3390/app16115435) · +[runaihome Konkurrenz-Zahlen](https://runaihome.com/blog/vllm-vs-ollama-when-each-wins-2026/) · +[tech-insider](https://tech-insider.org/vllm-vs-ollama-2026/) · +[SitePoint](https://www.sitepoint.com/ollama-vs-vllm-performance-benchmark-2026/) + +**Open WebUI / RAG:** +[Knowledge-Doku](https://docs.openwebui.com/features/workspace/knowledge/) · +[Knowledge Base Sync / oikb](https://docs.openwebui.com/features/knowledge-base-sync/) · +[oikb GitHub](https://github.com/open-webui/oikb) · +[LDAP-Doku](https://docs.openwebui.com/features/authentication-access/auth/ldap/) · +[Scaling-Doku](https://docs.openwebui.com/getting-started/advanced-topics/scaling/) + +**Onyx:** +[Onyx GitHub](https://github.com/onyx-dot-app/onyx) · +[Connector-Übersicht](https://docs.onyx.app/overview/core_features/connectors)