Domowe AI 24/7 bez prądożernego serwera: Open WebUI na NAS + Wake-on-LAN
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.
Krok 1: przygotuj PC do budzenia
Wake-on-LAN zawodzi zwykle przez ustawienia Windowsa, a nie przez sieć. Trzy rzeczy do sprawdzenia:
- Karta sieciowa: Menedżer urządzeń → karta Ethernet → Zaawansowane: „Wake on Magic Packet” = Enabled. W zakładce Zarządzanie energią zaznacz „Zezwalaj temu urządzeniu na wznawianie” i „Tylko magic packet”. Bez tej opcji komputer budzi każdy ruch w sieci.
- Szybkie uruchamianie (Fast Startup) wyłącz. Z nim „wyłączony” komputer jest w półhibernacji i często nie reaguje na WoL.
- Hibernację wyłącz, jeśli chcesz usypiać skryptem. Inaczej polecenie uśpienia potrafi zahibernować komputer, a z tego stanu budzi się dłużej.
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
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)
- Aplikacje z opcją „nie usypiaj podczas pracy” zgłaszają blokadę EXECUTION i potrafią trzymać ją całą noc. Wyłącz takie ustawienie albo zamknij aplikację.
- Windows i tak potrafi nie zasnąć bez żadnej widocznej blokady. Pewniej jest usypiać komputer własnym zadaniem w Harmonogramie zadań, uruchamianym co minutę, gdy spełnione są warunki:
- użytkownik nic nie robi od X minut,
- Ollama nie ma załadowanego modelu (
GET /api/pszwraca pustą listę), powercfg /requestsnic nie zgłasza.
- Pułapka z bezczynnością: zadanie działające jako SYSTEM nie widzi aktywności myszy i klawiatury.
quserdla sesji konsoli zawsze pokazuje „none”, więc nasz pierwszy skrypt liczył zero minut i nigdy nie usypiał. Działa mały licznik w sesji użytkownika (funkcjaGetLastInputInfo), który co minutę zapisuje czas bezczynności do pliku, a zadanie usypiające tylko go czyta. - Daj komputerowi chwilę po obudzeniu, np. 15 minut, zanim skrypt w ogóle rozważy uśpienie. Inaczej uśnie, zanim budzik zdąży przekazać pierwsze pytanie.
# 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
- Pierwsze pytanie po przerwie: ~20–30 s (wstanie komputera + załadowanie modelu). Kolejne odpowiedzi od razu, ~40–60 tok/s.
- Prąd (przy 1 zł/kWh): PC 24/7 ~100 zł/mies., PC usypiany ~15–20 zł/mies. NAS i tak działa całą dobę.
- Gdy PC nie wstanie (odłączony, wyłączona listwa), budzik po limicie czasu zwraca błąd 503. W Home Assistant albo n8n możesz wtedy przełączyć się na model w chmurze jako zapasowy.
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 ›Podsumowanie
- Ciężkie AI na usypianym PC, czat i budzik na energooszczędnym NAS-ie 24/7.
- Wake-on-LAN: tylko magic packet, Fast Startup i hibernacja wyłączone, kontener budzika w
--network host. - Open WebUI z
ENABLE_SIGNUP=false; admina zakładasz, zanim wystawisz go w sieci. - Nie ufaj samemu „uśpij po 30 min”: sprawdź
powercfg /requestsi usypiaj własnym zadaniem.
Zobacz też: Home Assistant za reverse proxy (nginx) oraz n8n + AI: opisywanie alarmów.