Lokalna AI

Gemma 4 lokalnie na Mac Mini M4 — od zera do własnej domeny

Analiza systemowa

Jest pewien szczególny rodzaj satysfakcji, gdy patrzysz, jak duży model językowy odpowiada na twój prompt, i wiesz — z pełną pewnością — że te tokeny nigdy nie opuściły budynku. Żadnego klucza API, żadnego rozliczanego zużycia, żadnego zewnętrznego serwera logującego twoje zapytania. Tylko model, maszyna i lokalna sieć.

Niedawno postawiłem to wszystko na Mac Mini M4 (2025, 16 GB RAM) z systemem macOS 26 Tahoe. Poniżej znajdziesz wierną rekonstrukcję tego, co dokładnie zrobiłem — łącznie ze ślepymi zaułkami. Jeśli masz podobną konfigurację, powinieneś przejść tę drogę od początku do końca.

Ten przewodnik zakłada, że swobodnie poruszasz się w terminalu i w podstawowych komendach powłoki. Wcześniejsze doświadczenie z Ollamą czy Dockerem nie jest potrzebne.


Dlaczego Gemma 4 — i który wariant?

Rodzina Gemma 4 od Google, wydana na początku 2026 roku, wnosi do lokalnych wdrożeń coś naprawdę ciekawego: architekturę Mixture-of-Experts (MoE) w przystępnym wydaniu. Flagowe modele są duże (26B i więcej), ale warianty MoE aktywują tylko ułamek parametrów na jedną inferencję — co przekłada się na mniejsze obciążenie pamięci RAM, niż sugerowałaby surowa liczba parametrów.

Tak wygląda ta rodzina pod kątem zastosowań lokalnych:

ModelRozmiar pobieraniaWymagany RAMKontekstUwagi
gemma4:2b~2 GB4 GB+128KSzybki, ograniczona jakość
gemma4:4b~3 GB6 GB+128KDobry do lekkich zadań
gemma4:e4b9.6 GB12 GB+128KMoE, multimodalny, ten przewodnik
gemma4:26b~18 GB24 GB+128KNajlepsza jakość, potrzeba więcej RAM

Przy 16 GB RAM gemma4:e4b to właściwy wybór. To wariant MoE „Efficient 4B” — wbrew nazwie bije mocno ponad swoją wagę, obsługuje wejście multimodalne i wygodnie mieści się w zapasie pamięci maszyny. Model 26B teoretycznie zmieści się na 16 GB, ale nie zostawia praktycznie żadnego oddechu dla systemu i pozostałych procesów.


Krok 1 — Instalacja Homebrew

Jeśli zaczynasz na świeżym macOS, prawdopodobnie Homebrew jeszcze tam nie ma. Sprawdź:

brew --version

Jeśli zobaczysz command not found, zainstaluj go:

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

Na Apple Silicon musisz jeszcze dodać go do zmiennej PATH — instalator nie zawsze robi to automatycznie:

echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.zprofile
eval "$(/opt/homebrew/bin/brew shellenv)"

Jeśli pominiesz krok z PATH i otworzysz nowe okno terminala, Homebrew będzie wyglądał, jakby zniknął. Na tym się na chwilę potknąłem.


Krok 2 — Instalacja Ollamy i uruchomienie usługi

Ollama to warstwa uruchomieniowa, która zarządza pobieraniem modeli, ich przechowywaniem i inferencją. Instalacja przez Homebrew utrzymuje aktualizacje w czystości:

brew install ollama

Następnie uruchom ją jako usługę działającą w tle, tak by startowała automatycznie przy logowaniu:

brew services start ollama
==> Successfully started `ollama` (label: homebrew.mxcl.ollama)

Ollama działa teraz jako lokalny serwer na porcie 11434. Możesz to sprawdzić przez curl http://localhost:11434 — powinno odpowiedzieć Ollama is running.


Krok 3 — Pobranie modelu

Tu kryje się drobny haczyk. Tag modelu, który początkowo wpisałem (gemma4:27b), nie istnieje w rejestrze Ollamy. Poprawny tag dla naszego docelowego modelu to:

ollama pull gemma4:e4b

To pobiera około 9.6 GB. W zależności od łącza spodziewaj się od 5 do 30 minut. Gdy skończy, potwierdź, że model jest dostępny:

ollama list

Krok 4 — Pierwszy test w terminalu

Zanim dołożysz jakąkolwiek warstwę interfejsu, warto sprawdzić, czy model faktycznie działa. Najszybszy test zdrowia:

ollama run gemma4:e4b "What is the capital of Poland?"
The capital of Poland is Warsaw.

Jeśli widzisz spójną odpowiedź, model działa poprawnie. Możesz też wejść w sesję interaktywną, uruchamiając ollama run gemma4:e4b bez argumentu z promptem — wpisz /bye, żeby wyjść.

Na tym etapie masz już w pełni funkcjonalny lokalny LLM. Pozostałe kroki dotyczą tego, by nadać mu wygodny interfejs i udostępnić go poza samą lokalną maszyną.


Krok 5 — Instalacja Docker Desktop

Open WebUI — interfejs czatu w przeglądarce — jest dystrybuowany jako kontener Docker. Zainstaluj Docker Desktop przez Homebrew:

brew install --cask docker

Po instalacji uruchom Docker z Aplikacji przynajmniej raz. Musi działać w tle, zanim będziesz mógł wystartować jakiekolwiek kontenery. Poczekaj, aż ikona wieloryba na pasku menu przestanie się animować — to znaczy, że demon Dockera jest gotowy.


Krok 6 — Uruchomienie Open WebUI

Gdy Docker działa, jedna komenda pobiera i uruchamia Open WebUI, od razu połączony z twoją lokalną instancją Ollamy:

docker run -d \
  -p 3000:8080 \
  --add-host=host.docker.internal:host-gateway \
  -v open-webui:/app/backend/data \
  --name open-webui \
  --restart always \
  ghcr.io/open-webui/open-webui:main

Daj mu przy pierwszym uruchomieniu jakieś 60 sekund — pobiera obraz kontenera i się inicjalizuje. Następnie otwórz:

http://localhost:3000

Zostaniesz poproszony o utworzenie lokalnego konta administratora (imię, e-mail, hasło — nic z tego nie opuszcza twojej maszyny). Potem wybierz gemma4:e4b z listy modeli i możesz rozmawiać przez pełny interfejs w przeglądarce.

Open WebUI przechowuje historię rozmów w wolumenie Dockera open-webui. Jeśli wdrażasz to dla wielu użytkowników, wszystko w tym wolumenie to dane osobowe — warto przemyśleć politykę retencji, zanim udostępnisz dostęp.


Wewnątrz Open WebUI — jak dobrze skonfigurować

Kiedy już wylądujesz na http://localhost:3000, Open WebUI wita cię czystym interfejsem czatu. Ale prawdziwa wartość kryje się w panelu ustawień — jest tam znacznie więcej niż sugeruje domyślny widok.

Pierwsze logowanie i konto administratora

Pierwsze utworzone konto automatycznie staje się administratorem. Kolejne konta są domyślnie zwykłymi użytkownikami. Jeśli wdrażasz to dla innych, wejdź w Admin Panel → Settings → General i ustaw Default User Role na pending — to wymusza, by nowe rejestracje czekały na ręczne zatwierdzenie, zamiast dostawać dostęp od ręki.

Ta jedna zmiana sprawia, że interfejs nie jest otwarty dla każdego, kto natrafi na adres URL.

Połączenie z Ollamą

Open WebUI automatycznie wykrywa Ollamę pod http://host.docker.internal:11434, gdy uruchomisz go z flagą --add-host z naszej komendy Dockera. Zweryfikuj to w Admin Panel → Settings → Connections. Powinieneś zobaczyć Ollamę na liście z zielonym wskaźnikiem.

Jeśli pokazuje się jako rozłączona:

brew services restart ollama
# then refresh the browser

System prompty i presety modeli

W Workspace → Models możesz tworzyć nazwane presety — kombinację model + system prompt zapisaną jako odrębny „asystent”. Każdy preset pojawia się jako opcja do wyboru w interfejsie czatu.

Kilka praktycznych przykładów:

Name: Document Analyst
Model: gemma4:e4b
System prompt: You are a precise document analyst. When given text or a file,
extract key information, identify main arguments, and flag any ambiguities.
Respond in the same language as the input document.
Name: Code Reviewer
Model: gemma4:e4b
System prompt: You are an experienced software engineer performing code review.
Focus on correctness, readability, and potential edge cases. Suggest specific
improvements with brief explanations. Do not rewrite the entire code unless asked.

Po zapisaniu pojawiają się jako odrębne opcje na liście modeli — użytkownicy w ogóle nie muszą myśleć o system promptach.

RAG — dołączanie dokumentów do rozmów

Open WebUI ma wbudowany mechanizm Retrieval Augmented Generation. W Workspace → Knowledge wgrywasz dokumenty (PDF, DOCX, TXT, Markdown), które model może odpytywać w trakcie rozmowy.

Do dokumentu odwołujesz się w czacie przedrostkiem # — wpisz #, a nazwa dokumentu podpowie się automatycznie. Model pobiera odpowiednie fragmenty, zanim odpowie. Przy kontekście 128K Gemmy 4 radzi sobie z zaskakująco długimi dokumentami źródłowymi, nie tracąc spójności.

Wszystkie wgrane dokumenty przechowywane są w wolumenie Dockera open-webui. Zrób jego kopię zapasową, jeśli dokumenty mają znaczenie. Na macOS wolumeny Dockera znajdują się w ~/Library/Containers/com.docker.docker/Data/vms/0/.

Zarządzanie użytkownikami w skrócie

FunkcjaGdzie to znaleźć
Zatwierdzanie oczekujących użytkownikówAdmin Panel → Users
Nadanie użytkownikowi roli adminaAdmin Panel → Users → edit role
Całkowite wyłączenie rejestracjiAdmin Panel → Settings → General → przełącznik „New User Signup”
Eksport historii rozmówUser menu → Settings → Account → Export Data
Ustawienie domyślnego modelu dla nowych użytkownikówAdmin Panel → Settings → Interface

Udostępnienie poza lokalną sieć

Uruchomienie Open WebUI na localhost:3000 jest w porządku dla jednej maszyny. Ale w momencie, gdy chcesz mieć do niego dostęp z innego urządzenia — telefonu na transmisji komórkowej, laptopa w kawiarni, zdalnie łączącego się współpracownika — musisz wystawić go do internetu.

Naiwne podejście to przekierowanie portów na routerze. Nie rób tego. Wystawiłbyś usługę webową bezpośrednio do publicznego internetu, bez żadnej dodatkowej warstwy ochrony.

Właściwe podejście: Cloudflare Tunnel.


Cloudflare Tunnel — jak to działa

Cloudflare Tunnel tworzy szyfrowane połączenie wychodzące (i tylko wychodzące) z twojego Maca do sieci brzegowej Cloudflare. Ruch płynie tak:

User browser → ai.yourdomain.com (Cloudflare) → Tunnel → Mac Mini → Open WebUI

Twój Mac nigdy nie otwiera portu przychodzącego. Nie ma reguły firewalla do skonfigurowania, nie ma dynamicznego DNS do ogarnięcia, nie ma adresu IP do wystawienia. Cloudflare terminuje HTTPS na swoim brzegu, więc twoja własna domena automatycznie dostaje ważny certyfikat TLS.

Demon tunelu (cloudflared) działa lokalnie, wychodzi na zewnątrz do Cloudflare, a Cloudflare kieruje ruch z powrotem przez to trwałe połączenie.


Konfiguracja Cloudflare Tunnel — krok po kroku

Wymagania wstępne:

  • Domena dodana do Cloudflare (musi używać Cloudflare jako serwera nazw — to jedyny twardy wymóg)
  • Darmowe konto Cloudflare

Instalacja cloudflared

brew install cloudflared

Uwierzytelnienie w Cloudflare

cloudflared tunnel login

To otwiera okno przeglądarki. Zaloguj się i wybierz domenę, której chcesz użyć. Plik certyfikatu zostaje zapisany w ~/.cloudflared/cert.pem.

Utworzenie tunelu

cloudflared tunnel create gemma-local

To rejestruje nazwany tunel i tworzy plik z danymi uwierzytelniającymi w ~/.cloudflared/<TUNNEL-UUID>.json. Zanotuj UUID wypisany w outputcie — będzie potrzebny za chwilę.

Utworzenie pliku konfiguracyjnego

nano ~/.cloudflared/config.yml

Wklej to, podstawiając własny UUID tunelu i nazwę użytkownika:

tunnel: YOUR-TUNNEL-UUID
credentials-file: /Users/YOUR-USERNAME/.cloudflared/YOUR-TUNNEL-UUID.json

ingress:
  - hostname: ai.yourdomain.com
    service: http://localhost:3000
  - service: http_status:404

Blok ingress mówi Cloudflare: kieruj żądania do ai.yourdomain.com na localhost:3000. Końcowa linia catch-all jest wymagana — obsługuje wszystkie żądania, które nie pasują do żadnej reguły.

Utworzenie rekordu DNS

cloudflared tunnel route dns gemma-local ai.yourdomain.com

To dodaje rekord CNAME w twoim DNS-ie Cloudflare, wskazujący ai.yourdomain.com na tunel. Nie trzeba ręcznie zaglądać do panelu Cloudflare.

Test tunelu

Najpierw uruchom go ręcznie:

cloudflared tunnel run gemma-local

Otwórz https://ai.yourdomain.com w przeglądarce. Jeśli widzisz ekran logowania Open WebUI, działa — HTTPS z ważnym certyfikatem, obsłużone automatycznie przez Cloudflare. Naciśnij Ctrl+C, żeby zatrzymać.

Uruchomienie tunelu jako trwałej usługi

sudo cloudflared service install
sudo launchctl start com.cloudflare.cloudflared

Tunel startuje teraz automatycznie przy rozruchu, jeszcze zanim ktokolwiek się zaloguje. Sprawdź status:

sudo launchctl list | grep cloudflare

Blokowanie dostępu — Cloudflare Access

Twój Open WebUI jest teraz dostępny pod https://ai.yourdomain.com z dowolnego miejsca na świecie. Własne uwierzytelnianie Open WebUI to jedna warstwa ochrony — ale przy wrażliwych wdrożeniach Cloudflare Access dokłada drugą warstwę, przed samą aplikacją, zanim żądanie w ogóle dotrze do twojego Maca.

W panelu Cloudflare:

  1. Wejdź w Zero Trust → Access → Applications → Add an application
  2. Wybierz Self-hosted
  3. Ustaw domenę na ai.yourdomain.com
  4. W Policies utwórz regułę: Emails → is → your@email.com

Gdy to działa, każdy odwiedzający ai.yourdomain.com najpierw widzi stronę uwierzytelniania Cloudflare. Cloudflare wysyła jednorazowy kod na jego e-mail. Dopiero potem żądanie dociera do Open WebUI.

Jest to darmowe dla maksymalnie 50 użytkowników w darmowym planie Cloudflare Zero Trust.


Pełny obraz

Na tym etapie kompletny stos wygląda tak:

WarstwaKomponentRola
Runtime modeluOllama (usługa Homebrew)Zarządza modelami, obsługuje inferencję
Modelgemma4:e4bSam LLM, 9.6 GB na dysku
Interfejs webowyOpen WebUI (Docker)UI w przeglądarce, zarządzanie użytkownikami, RAG
Tunelcloudflared (usługa Homebrew)Bezpieczne połączenie wychodzące do Cloudflare
Brzeg / TLSCloudflareTerminacja HTTPS, DNS, opcjonalna bramka uwierzytelniania

Każdy komponent działa lokalnie. Jedyne połączenia wychodzące to: cloudflared utrzymujący tunel do Cloudflare oraz Ollama, która po pierwszym pobraniu modelu nie wykonuje już żadnych zapytań sieciowych.

Całkowity koszt miesięczny: zero — zakładając, że masz własną domenę (zwykle 10–15 €/rok) i korzystasz z darmowego planu Cloudflare.


Co zauważyłem po dłuższym używaniu

Opóźnienie odpowiedzi na M4 jest naprawdę dobre. Neural Engine dobrze radzi sobie z inferencją kwantyzowaną — typowe odpowiedzi zaczynają się streamować w ciągu 2–3 sekund, z utrzymaną przepustowością na poziomie 20–30 tokenów/sekundę dla wariantu e4b. To prędkość rozmowy.

Okno kontekstowe 128K jest realne i użyteczne. Testowałem je z długim PDF-em wklejonym jako tekst i model zachował spójne odwołania do treści z początku dokumentu przez całą swoją odpowiedź.

Jedna praktyczna uwaga: brew services start ollama oznacza, że Ollama działa w tle cały czas i restartuje się po ponownym uruchomieniu. Jeśli wolisz odpalać ją ręcznie, użyj brew services stop ollama i uruchamiaj na żądanie przez ollama serve.


Szybka ściąga do rozwiązywania problemów

Open WebUI pokazuje „Ollama disconnected”

brew services restart ollama
# then refresh the browser

Tunel Cloudflare nie chce wystartować — błąd danych uwierzytelniających

cloudflared tunnel login
# re-authenticate, then re-run the tunnel

ai.yourdomain.com zwraca błąd 502 Tunel działa, ale Open WebUI nie jest uruchomiony. Sprawdź Docker:

docker ps | grep open-webui
docker start open-webui

Kontener Open WebUI zatrzymał się po restarcie Maca Flaga --restart always to obsługuje — ale sam Docker Desktop musi być ustawiony tak, by startował przy logowaniu. Sprawdź Docker Desktop → Settings → General → Start Docker Desktop when you sign in.


Sprzęt: Mac Mini M4 2025, 16 GB RAM, macOS 26 Tahoe · Model: gemma4:e4b przez Ollamę · Interfejs: Open WebUI przez Docker · Tunel: Cloudflare