PSSStudio
AI · Open WebUI · Wake-on-LAN

Domowe AI 24/7 bez prądożernego serwera: Open WebUI na NAS + Wake-on-LAN

Aktualizacja: październik 2026 · czas czytania ~11 min

Masz już lokalny model na komputerze z kartą graficzną (jeśli nie, zacznij od tego poradnika). Problem: taki PC na biegu jałowym pobiera 120–150 W. Trzymany 24/7 kosztuje ~100 zł prądu miesięcznie, a przez większość doby nikt z AI nie korzysta. Rozwiązanie: komputer z kartą śpi, a mały, energooszczędny NAS czuwa. Kiedy ktoś zada pytanie, NAS budzi komputer przez Wake-on-LAN, czeka ~20–30 s i przekazuje rozmowę. Po kwadransie ciszy komputer sam zasypia. U nas to zeszło do kilkunastu złotych miesięcznie.

Architektura. NAS (24/7, Docker): Open WebUI (czat w przeglądarce) + budzik (pośrednik API Ollamy z Wake-on-LAN). PC z kartą (Windows): Ollama, uśpienie S3, budzenie pakietem magic packet. Ten sam budzik obsłuży Home Assistant, n8n i każdą aplikację, która rozmawia z API Ollamy.

Krok 1: przygotuj PC do budzenia

Wake-on-LAN zawodzi zwykle przez ustawienia Windowsa, a nie przez sieć. Trzy rzeczy do sprawdzenia:

powercfg /a                 # czy dostępny jest stan S3 (uśpienie)
powercfg /h off             # wyłącza hibernację (i Fast Startup razem z nią)
powercfg /devicequery wake_armed   # karta sieciowa musi być na liście

Krok 2: budzik, czyli pośrednik z Wake-on-LAN

Budzik udaje Ollamę. Przyjmuje te same zapytania API, sprawdza, czy PC odpowiada, w razie potrzeby wysyła magic packet, czeka i przekazuje zapytanie dalej, strumieniując odpowiedź token po tokenie. Wystarczy sama biblioteka standardowa Pythona (wersja uproszczona, bez kontroli dostępu):

import http.client, os, socket, time
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer

PC, PORT = os.environ["PC_HOST"], 11434          # np. 192.168.1.50
MAC = bytes.fromhex(os.environ["PC_MAC"].replace(":", ""))
BCAST = os.environ.get("BROADCAST", "192.168.1.255")

def pc_up():
    try:
        c = http.client.HTTPConnection(PC, PORT, timeout=2)
        c.request("GET", "/api/version")
        return c.getresponse().status == 200
    except OSError:
        return False

def wake(limit=150):
    pkt = b"\xff" * 6 + MAC * 16
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
    t0 = time.time()
    while time.time() - t0 < limit:
        s.sendto(pkt, (BCAST, 9))
        time.sleep(5)
        if pc_up():
            return True
    return False

class H(BaseHTTPRequestHandler):
    protocol_version = "HTTP/1.0"                    # koniec odpowiedzi = zamknięcie połączenia
    def proxy(self):
        body = self.rfile.read(int(self.headers.get("Content-Length") or 0)) or None
        if not pc_up() and not wake():
            self.send_error(503, "PC z AI nie dal sie obudzic")
            return
        up = http.client.HTTPConnection(PC, PORT, timeout=600)
        up.request(self.command, self.path, body=body,
                   headers={"Content-Type": self.headers.get("Content-Type", "application/json")})
        r = up.getresponse()
        self.send_response(r.status)
        for k, v in r.getheaders():
            if k.lower() not in ("transfer-encoding", "connection", "content-length"):
                self.send_header(k, v)
        self.end_headers()
        while chunk := r.read1(65536):               # streaming token po tokenie
            self.wfile.write(chunk)
            self.wfile.flush()
    do_GET = do_POST = do_DELETE = proxy

ThreadingHTTPServer(("0.0.0.0", 11435), H).serve_forever()

Uruchom go w kontenerze z --network host. Magic packet to broadcast w sieci lokalnej i z domyślnej sieci mostkowej Dockera nie wyjdzie:

docker run -d --name ai-budzik --restart unless-stopped --network host \
  -e PC_HOST=192.168.1.50 -e PC_MAC=AA:BB:CC:DD:EE:FF \
  -v /srv/ai/budzik.py:/budzik.py:ro python:3.12-alpine python /budzik.py

W wersji produkcyjnej dodaj listę dozwolonych adresów (port nie może być otwarty dla całego internetu) i blokadę, żeby kilka równoczesnych zapytań nie budziło komputera kilka razy.

Krok 3: Open WebUI na NAS

Open WebUI daje czat jak ChatGPT: konta dla domowników, historię rozmów, wgrywanie dokumentów i wyszukiwanie w internecie. Kierujemy go na budzik, a nie bezpośrednio na PC:

docker run -d --name open-webui --restart unless-stopped \
  -p 3000:8080 --memory 1.5g \
  -e OLLAMA_BASE_URL=http://192.168.1.10:11435 \
  -e ENABLE_SIGNUP=false \
  -e ANONYMIZED_TELEMETRY=false \
  -v /srv/ai/open-webui:/app/backend/data \
  ghcr.io/open-webui/open-webui:main
Bezpieczeństwo: pierwsze konto zostaje administratorem. Zanim wystawisz Open WebUI w sieci (a tym bardziej w internecie przez reverse proxy), zaloguj się i załóż konto admina. Do tego czasu ogranicz port w zaporze do swojego komputera. Konta domowników zakładaj ręcznie w panelu admina; rejestracja jest wyłączona (ENABLE_SIGNUP=false).

Na słabym NAS-ie (kilka GB RAM) wyłącz w Open WebUI wbudowany model do embeddingu i ustaw embedding przez Ollamę (np. nomic-embed-text). Wtedy ciężka praca przy dokumentach też trafia na PC z kartą.

Krok 4: usypianie, które naprawdę działa

Budzenie to połowa sukcesu. U nas komputer przez dwie noce z rzędu w ogóle nie zasnął, mimo ustawionego uśpienia po 30 minutach. Co go trzymało i jak to znaleźć:

powercfg /requests          # kto blokuje uśpienie (uruchom jako administrator)
# samo uśpienie (S3), gdy hibernacja jest wyłączona:
rundll32.exe powrprof.dll,SetSuspendState 0,1,0

Ile to kosztuje i jak działa w praktyce

Sprzęt na serwer, który czuwa

Energooszczędny mini-PC lub NAS pod Dockera

Do Open WebUI i budzika wystarczy mini-PC z procesorem typu N100 i 8–16 GB RAM. Pobiera kilka watów, a obsłuży też Home Assistanta, AdGuarda i Nextclouda.

Zobacz mini-PC N100 ›
Link afiliacyjny — prowizja dla nas, cena dla Ciebie bez zmian.

Podsumowanie

Zobacz też: Home Assistant za reverse proxy (nginx) oraz n8n + AI: opisywanie alarmów.