LibreChat — alternativa Open WebUI za lokalne modele

U tekstu o Open WebUI postavljen je veb sloj iznad Ollame. Radi dobro i za većinu postavki je i dalje prvi izbor — ali nije jedini, i za pojedine firme nije ni najsrećniji.

LibreChat je najozbiljnija alternativa. Ovaj tekst objašnjava po čemu se razlikuje, kada ima smisla preći i kako se postavlja uz lokalni model.

Pitanje licence, bez zabluda

Prvo da se raščisti jedna stvar koja se pogrešno prepričava.

Open WebUI je besplatan i za velike firme. Nema plaćanja po korisniku, nema pretplate, nema ograničenja broja naloga. Od verzije 0.6.6 postoji jedna klauzula: u postavkama sa preko pedeset korisnika u tridesetodnevnom periodu ne smeš da ukloniš ili zameniš njihovo brendiranje — ime, logo, vizuelne oznake. Ispod tog praga i to slobodno menjaš.

Praktično, to znači sledeće:

Situacija Open WebUI
Interna upotreba, bilo koliko korisnika Besplatno
Do 50 korisnika, uz svoj logo Besplatno
Preko 50 korisnika, uz svoj logo Traži licencu
Ugradnja u sopstveni proizvod Traži licencu

Ostaje jedna stvarna posledica: ta licenca nije OSI-odobrena. Firme koje imaju politiku da se koristi isključivo softver sa priznatih otvorenih licenci tu naiđu na zid, bez obzira na to što ništa ne plaćaju.

LibreChat je pod MIT licencom, bez ijedne klauzule. Ako te pravna služba pita, to je razlika koja ti rešava razgovor.

Po čemu se razlikuju

Open WebUI LibreChat
Licenca Sopstvena, uz zaštitu brenda MIT
Baza SQLite ili PostgreSQL MongoDB, obavezno
Broj kontejnera Jedan Četiri do pet
Podešavanje Kroz interfejs Kroz librechat.yaml
Više provajdera odjednom Da Da, sa boljim prebacivanjem
RAG Ugrađen, jednostavniji Zaseban servis, pgvector
Pretraga razgovora Osnovna Meilisearch
Prijava kroz SSO Da Da, sa više gotovih provajdera
Podrazumevani port 8080 u kontejneru 3080

Razlika u broju kontejnera nije sitnica. Open WebUI je jedan proces i jedan fajl baze; LibreChat je mali stack. To donosi mogućnosti, ali i više toga što treba nadgledati i za šta treba praviti kopije.

Kada preći

  • Politika firme traži OSI-odobrenu licencu
  • Radiš sa više provajdera uporedo i često prebacuješ između njih
  • Treba ti prijava kroz postojeći identitetski sistem
  • Podešavanje mora da stoji u fajlu pod verzijom, ne u bazi

Kada ostati na Open WebUI

  • Jedan model, nekoliko korisnika
  • Hoćeš najmanje delova koje treba održavati
  • Ugrađeni RAG ti je dovoljan
  • Već radi i nema stvarnog razloga za promenu

Instalacija

Za razliku od Open WebUI, ovde se kreće od repozitorijuma jer su compose fajlovi deo projekta:

$ cd /opt
$ sudo git clone https://github.com/danny-avila/LibreChat.git
$ cd LibreChat
$ sudo cp .env.example .env

Podrazumevani .env radi odmah, ali dve stvari promeni pre prvog pokretanja:

$ sudo nano .env
# Nasumične vrednosti, obavezno promeniti
CREDS_KEY=32 bajta u heksadecimalnom obliku
CREDS_IV=16 bajtova u heksadecimalnom obliku
JWT_SECRET=nasumičan niz
JWT_REFRESH_SECRET=nasumičan niz

# Registracija
ALLOW_REGISTRATION=true
ALLOW_SOCIAL_LOGIN=false

Vrednosti se prave lako:

$ openssl rand -hex 32   # CREDS_KEY
$ openssl rand -hex 16   # CREDS_IV
$ openssl rand -hex 32   # JWT_SECRET

Ove ključeve obavezno promeni. Njima se šifruju korisnički API ključevi u bazi; podrazumevane vrednosti iz primera zna svako ko je otvorio repozitorijum.

$ sudo docker compose up -d
$ sudo docker compose ps

Diže se pet kontejnera: api, mongodb, meilisearch, vectordb i rag_api. Prvo podizanje traje nekoliko minuta zbog preuzimanja slika.

$ sudo docker compose logs -f api

Otvori http://localhost:3080 — port se razlikuje od Open WebUI, pa mogu da rade uporedo dok porediš.

Prvi napravljen nalog je administratorski. Napravi ga odmah, pre nego što bilo šta izložiš, i onda zatvori registraciju:

ALLOW_REGISTRATION=false
$ sudo docker compose down && sudo docker compose up -d

Povezivanje sa Ollamom

Ovo je deo koji se radi u fajlu, ne u interfejsu. Treba ti dva fajla.

Kačenje konfiguracije

$ sudo cp docker-compose.override.yml.example docker-compose.override.yml
$ sudo nano docker-compose.override.yml
services:
  api:
    volumes:
      - type: bind
        source: ./librechat.yaml
        target: /app/librechat.yaml
    ports:
      - "127.0.0.1:3080:3080"
    extra_hosts:
      - "host.docker.internal:host-gateway"

Vezivanje porta za 127.0.0.1 je isto pravilo kao svuda u serijalu — napolju stoji proxy, ne servis.

Definisanje modela

$ sudo nano librechat.yaml
version: 1.3.13
cache: true

endpoints:
  custom:
    - name: 'Ollama'
      apiKey: 'ollama'
      baseURL: 'http://host.docker.internal:11434/v1/'
      models:
        default: ['qwen3:27b-q4_K_M']
        fetch: true
      titleConvo: true
      titleModel: 'current_model'
      modelDisplayLabel: 'Lokalni model'
$ sudo docker compose down && sudo docker compose up -d

Tri stvari koje se ovde najčešće pogreše.

Kosa crta na kraju baseURL. Adresa mora da se završi sa /v1/. Bez kose crte pojedine putanje se sastavljaju pogrešno i dobijaš 404 bez jasnog objašnjenja.

Ključ mora postojati. Ollama ga ignoriše, ali LibreChat odbija konfiguraciju bez njega — otud doslovno ollama kao vrednost. Ako si postavio ključeve po tekstu o zaštiti API-ja, ovde ide pravi.

Adresa zavisi od toga gde Ollama radi.

Gde je Ollama baseURL
Na domaćinu, kao systemd servis http://host.docker.internal:11434/v1/
U kontejneru, ista mreža http://ollama:11434/v1/
Na drugom serveru https://ai.primer.rs/api/v1/

Vrednost fetch: true znači da LibreChat sam povlači spisak modela iz Ollame — ne moraš ih nabrajati ručno. Ako to zakaže, spisak u default ostaje kao rezerva.

Uz vLLM

    - name: 'vLLM'
      apiKey: '${VLLM_API_KEY}'
      baseURL: 'http://host.docker.internal:8000/v1/'
      models:
        default: ['qwen3']
        fetch: true
      titleConvo: true
      titleModel: 'qwen3'

Ključ ide u .env, ne u YAML:

VLLM_API_KEY=tajni-kljuc-ovde

Zapis ${IME} u konfiguraciji čita vrednost iz .env. To je razlog zbog kog librechat.yaml može da ide u git, a .env ne.

Provera

$ sudo docker compose logs api | grep -i 'custom endpoint\|error'

LibreChat prekida rad ako je konfiguracija neispravna, pa se greška vidi odmah po podizanju. Najčešći uzrok je uvlačenje u YAML-u — proveri pre nego što tražiš dalje:

$ python3 -c "import yaml,sys; yaml.safe_load(open('librechat.yaml'))" && echo OK

Ako se sve podiglo, u interfejsu se u padajućem meniju pojavljuje „Lokalni model". Postavi jedno pitanje i uporedo prati karticu:

$ ollama ps

Podešavanja koja vrede

$ sudo nano .env
# Adresa, obavezno tačna zbog CORS-a
DOMAIN_CLIENT=https://chat.primer.rs
DOMAIN_SERVER=https://chat.primer.rs

# Registracija zatvorena posle prvog naloga
ALLOW_REGISTRATION=false
ALLOW_EMAIL_LOGIN=true

# Ograničenja
LIMIT_CONCURRENT_MESSAGES=true
CONCURRENT_MESSAGE_MAX=2
LIMIT_MESSAGE_IP=true
MESSAGE_IP_MAX=40
MESSAGE_IP_WINDOW=1

# Veličina priloga
FILE_UPLOAD_SIZE_LIMIT=50

Vrednosti DOMAIN_* moraju odgovarati stvarnoj adresi preko koje pristupaš. Ako se razlikuju, interfejs se učita ali prijava ne radi — greška koja izgleda kao pokvarena baza, a nije.

Ograničenja su ovde korisnija nego kod Open WebUI, jer ih LibreChat sprovodi sam. To ne zamenjuje ograničenja na proxy-ju, ali je dodatni sloj bliži korisniku.

Reverse proxy

Ista pravila kao za Open WebUI, samo drugi port:

server {
    listen 443 ssl;
    http2 on;
    server_name chat.primer.rs;

    ssl_certificate     /etc/letsencrypt/live/chat.primer.rs/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/chat.primer.rs/privkey.pem;

    client_max_body_size 50M;

    location / {
        proxy_pass http://127.0.0.1:3080;

        proxy_set_header Host $host;
        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_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        proxy_buffering off;
        proxy_read_timeout 600s;
    }
}

Bez proxy_buffering off nema postepenog ispisa; bez WebSocket zaglavlja poruke ne stižu. Detaljno u tekstu o proxy-ju.

Rezervne kopije

Ovde je najveća praktična razlika u odnosu na Open WebUI. Nema jednog SQLite fajla — podaci su u MongoDB, a prilozi na disku.

$ sudo tee /opt/LibreChat/kopija.sh > /dev/null <<'SKRIPTA'
#!/bin/bash
set -euo pipefail
cd /opt/LibreChat
ODREDISTE=/backup/librechat
DATUM=$(date +%F)
mkdir -p "$ODREDISTE"

docker compose exec -T mongodb mongodump --archive --gzip \
    > "$ODREDISTE/mongo-$DATUM.gz"

tar -czf "$ODREDISTE/prilozi-$DATUM.tar.gz" ./uploads ./images 2>/dev/null || true
cp .env "$ODREDISTE/env-$DATUM"
cp librechat.yaml "$ODREDISTE/yaml-$DATUM" 2>/dev/null || true

find "$ODREDISTE" -mtime +30 -delete
SKRIPTA

$ sudo chmod 755 /opt/LibreChat/kopija.sh
0 4 * * * /opt/LibreChat/kopija.sh

Vraćanje:

$ docker compose exec -T mongodb mongorestore --archive --gzip --drop \
    < /backup/librechat/mongo-2026-08-24.gz

Fajl .env mora u kopiju. Bez ključeva CREDS_KEY i CREDS_IV šifrovani sadržaj u vraćenoj bazi je neupotrebljiv. Kopiju drži zaštićenu, jer sadrži sve tajne.

Zakazivanje pokriva tekst o cronu.

Ažuriranje

$ cd /opt/LibreChat
$ sudo ./kopija.sh
$ sudo docker compose down
$ sudo git pull
$ sudo docker compose pull
$ sudo docker compose up -d

Korak sa git pull je obavezan, za razliku od Open WebUI — compose fajlovi i primeri konfiguracije dolaze iz repozitorijuma i menjaju se uz nove verzije.

Ako si menjao docker-compose.yml, git pull će se sudariti sa tvojim izmenama. Zato izmene idu isključivo u docker-compose.override.yml, koji projekat ne dira.

Šta još dobijaš

Nekoliko stvari koje su razrađenije nego u Open WebUI.

Poređenje modela. Isto pitanje kroz dva modela uporedo, u istom prozoru — korisno kad biraš šta da hostuješ, uz merenja iz teksta o benchmarku.

Agenti i MCP. Podrška za protokol iz teksta o MCP-u je ugrađena, sa podešavanjem serverâ u istom YAML fajlu. Ista upozorenja odatle važe neizmenjeno — alati koji samo čitaju, spisak dozvoljenih vrednosti, bez izvršavanja bez potvrde.

Pretraga kroz istoriju. Meilisearch pretražuje sve razgovore, što na godinu dana upotrebe postane primetna razlika.

Podešavanje pod verzijom. Ceo librechat.yaml ide u git. Kod Open WebUI podešavanja žive u bazi, pa se ne mogu pregledati kao izmena u kodu.

Šta je slabije

Više delova. Pet kontejnera umesto jednog znači pet stvari koje mogu da otkažu i koje treba nadgledati po tekstu o monitoringu.

Teže na resursima. MongoDB i Meilisearch traže oko gigabajta memorije pre nego što iko išta upita.

RAG je zaseban servis. Moćniji, ali i još jedna stvar u lancu. Ako ti treba samo pitanje nad dokumentom, ugrađeni RAG u Open WebUI je jednostavniji, a za ozbiljnije sopstveno rešenje ionako gradiš sam.

Podešavanje kroz fajl. Prednost za tebe, prepreka za kolegu koji bi hteo sam da doda model.

Praktični scenariji

Scenario 1: model se ne pojavljuje u meniju

$ sudo docker compose logs api | tail -50

Redom: da li je librechat.yaml zakačen kroz override fajl, da li je YAML ispravan, da li adresa Ollame odgovara mestu gde ona radi.

Scenario 2: kontejner se odmah gasi

Neispravna konfiguracija — LibreChat namerno prekida rad umesto da radi sa polovičnim podešavanjima. Greška je u logu api.

Scenario 3: interfejs radi, prijava ne

Vrednosti DOMAIN_CLIENT i DOMAIN_SERVER ne odgovaraju adresi preko koje pristupaš.

Scenario 4: izmena u .env nema efekta

$ sudo docker compose down && sudo docker compose up -d

Compose čita .env samo pri pokretanju kontejnera. Obično restart ga ne osvežava.

Scenario 5: 404 na svaki zahtev ka modelu

Nedostaje kosa crta na kraju baseURL. Mora biti /v1/.

Scenario 6: git pull se sudara sa izmenama

Menjao si fajlove koji pripadaju projektu. Vrati ih u prvobitno stanje i sve svoje prebaci u docker-compose.override.yml.

Kratka referenca

  • Open WebUI je besplatan i preko 50 korisnika — licenca se tiče samo brendiranja
  • LibreChat je MIT — bez ijedne klauzule
  • git clone + cp .env.example .env + docker compose up -d
  • openssl rand -hex 32 — obavezno promeni CREDS_KEY i JWT_SECRET
  • Port 3080, ne 3000
  • Prvi nalog je administratorski; odmah zatim ALLOW_REGISTRATION=false
  • docker-compose.override.yml — jedino mesto za tvoje izmene
  • librechat.yaml — definicija modela; ide u git
  • baseURL mora se završiti sa /v1/
  • apiKey: 'ollama' — mora postojati iako se ne proverava
  • fetch: true — spisak modela se povlači sam
  • ${IME} u YAML-u čita vrednost iz .env
  • DOMAIN_CLIENT i DOMAIN_SERVER — netačni znače da prijava ne radi
  • mongodump --archive --gzip — kopija; uz nju obavezno .env
  • Posle izmene .env ide down pa up, ne restart

Vežba

  1. Postavi LibreChat na port 3080, uporedo sa postojećim Open WebUI, i napravi administratorski nalog.
  2. Poveži ga sa lokalnom Ollamom i potvrdi da se spisak modela povlači sam.
  3. Namerno izostavi kosu crtu na kraju baseURL i pogledaj kako greška izgleda.
  4. Dodaj drugi endpoint i uporedi isti upit kroz oba modela.
  5. Napravi kopiju baze, obriši kontejner sa podacima, pa je vrati.
  6. Postavi oba interfejsa iza proxy-ja na zasebnim imenima i odluči koji ostaje.

Povezano:

Comments

Popular posts from this blog

Početak u Linuxu — šta je i zašto se uči

Konverzija tipova podataka u Pythonu

groupadd