Runbook / reference architecture

Homelab, który da się odtworzyć.

Kompletna kolejność budowy małej prywatnej infrastruktury: router jest granicą sieci, NAS utrzymuje usługi, PC dostarcza GPU, a Caddy wystawia tylko świadomie wybrane usługi.

Bezpieczeństwo: adresy, domeny i sekrety są przykładami. Zastąp YOUR_… własnymi wartościami. Nie publikuj .env, kluczy SSH, tokenów OAuth ani baz haseł.

ETAP 0 — PLANUJ PRZED INSTALACJĄ

Adresacja, sprzęt i dane wejściowe

Najpierw zarezerwuj stałe adresy. NAS i PC nie mogą raz dostawać innego adresu z DHCP, a innym razem mieć wpis statyczny. Poniższa tabela jest wzorcem; końcówki możesz zachować, ale całą podsieć dopasuj do swojego LAN.

ElementAdres / nazwaRola
Router172.16.1.1DHCP, DNS, VPN, firewall, NAT.
NAS172.16.1.12Docker, dane trwałe, monitoring i usługi domowe.
PC z GPU172.16.1.34Modele lokalne, Open WebUI, ComfyUI; nie publiczny serwer.
AP172.16.1.25Przykładowe źródło sysloga i monitoringu.
Domenaexample.netRekord A/AAAA kieruje na YOUR_WAN_IP.
YOUR_DOMAIN=example.net
YOUR_WAN_IP=203.0.113.10
YOUR_EMAIL=admin@example.net
YOUR_PASSWORD=use-a-long-unique-password
YOUR_TOKEN=generate-a-long-random-token
YOUR_SSH_PUBLIC_KEY=ssh-ed25519 AAAA... laptop

Każda usługa ma osobne hasło/token. Sekrety trzyma menedżer haseł; dokumentacja i Git zawierają wyłącznie nazwy zmiennych.

ETAP 1 — ROUTER JEST GRANICĄ

MikroTik: LAN, DNS, VPN i tylko dwa porty z Internetu

Zanim zmienisz cokolwiek, zapisz eksport oraz backup. Wykonuj zmiany z drugą otwartą sesją administracyjną — w razie błędu nie odetniesz sobie dostępu.

/export file=before-homelab
/system backup save name=before-homelab

Stałe adresy i nazwy wewnętrzne

Adresy usług przydziel jako statyczne lease DHCP albo ustaw poza pulą DHCP. Lokalne nazwy rozwiązuj na routerze:

/ip dns static add name=home.example.net address=172.16.1.12 ttl=1h comment="Homepage"
/ip dns static add name=ai.example.net address=172.16.1.34 ttl=1h comment="Open WebUI"

VPN zamiast wystawiania paneli

DSM, Grafana, Open WebUI i panel routera powinny być dostępne przez WireGuard, nie przez port-forward. Klucze generuj lokalnie; poniżej są wyłącznie pola do uzupełnienia.

/interface wireguard add name=wg-home listen-port=YOUR_WG_PORT private-key="YOUR_ROUTER_WG_PRIVATE_KEY"
/ip address add address=10.77.0.1/24 interface=wg-home
/interface wireguard peers add interface=wg-home public-key="YOUR_CLIENT_WG_PUBLIC_KEY" allowed-address=10.77.0.2/32
/ip firewall filter add chain=input action=accept protocol=udp dst-port=YOUR_WG_PORT comment="WireGuard"
/ip firewall filter add chain=forward action=accept in-interface=wg-home dst-address=172.16.1.0/24 comment="VPN to LAN"

Publiczny ruch: Caddy na NAS

Jedynie HTTP/HTTPS przekieruj do Caddy. To wystarcza dla strony, muzyki i certyfikatów Let's Encrypt; aplikacje administracyjne pozostają w LAN/VPN.

/ip firewall nat add chain=dstnat action=dst-nat protocol=tcp in-interface-list=WAN dst-port=80 to-addresses=172.16.1.12 to-ports=18080 comment="Caddy HTTP"
/ip firewall nat add chain=dstnat action=dst-nat protocol=tcp in-interface-list=WAN dst-port=443 to-addresses=172.16.1.12 to-ports=18443 comment="Caddy HTTPS"

Dla tej samej domeny w LAN użyj split DNS lub hairpin NAT. Split DNS jest prostszy w utrzymaniu: rekord wewnętrzny domeny wskazuje bezpośrednio na NAS.

ETAP 2 — NAJPIERW DANE TRWAŁE

Synology: struktura katalogów i Compose

Zainstaluj Container Manager, włącz SSH tylko dla konta administracyjnego z kluczem i przechowuj każdą usługę w osobnym katalogu. Kontener można odtworzyć; katalog z danymi musi przetrwać.

sudo mkdir -p /volume1/docker/{home-ai-public,homepage,monitoring,logging,vaultwarden,navidrome}
sudo mkdir -p /volume1/music
sudo chown -R YOUR_NAS_USER:users /volume1/docker

Na części instalacji DSM CPU CFS nie jest dostępne, więc zwykły wpis deploy.resources.limits.cpus może blokować start Compose. Najpierw przetestuj limity na własnym modelu; ograniczenia pamięci są bezpieczniejszym punktem startu.

services:
  example-service:
    image: vendor/image:PINNED_VERSION
    container_name: example-service
    restart: unless-stopped
    ports:
      - "172.16.1.12:PORT:CONTAINER_PORT"
    volumes:
      - ./data:/data
    environment:
      TZ: Europe/Warsaw
    mem_limit: 1g

W każdym katalogu trzymaj compose.yaml, .env.example i README. Prawdziwy .env ma ograniczone prawa i nie trafia do repozytorium.

cd /volume1/docker/homepage
sudo /var/packages/ContainerManager/target/usr/bin/docker compose up -d
sudo /var/packages/ContainerManager/target/usr/bin/docker compose ps
sudo /var/packages/ContainerManager/target/usr/bin/docker compose logs --tail=100

ETAP 3 — JEDNA BRAMA HTTPS

Caddy: reverse proxy i automatyczne certyfikaty

Caddy pobiera i odnawia certyfikaty sam, jeśli DNS wskazuje na WAN i router przekazuje 80/443. Katalog data jest krytyczny: zawiera stan certyfikatów i musi być objęty backupem.

services:
  caddy:
    image: caddy:2
    container_name: home-public
    restart: unless-stopped
    ports:
      - "172.16.1.12:18080:80"
      - "172.16.1.12:18443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - ./data:/data
      - ./config:/config
      - ./portfolio:/portfolio:ro
www.example.net {
    root * /portfolio/current
    encode gzip
    header {
        X-Content-Type-Options nosniff
        X-Frame-Options DENY
        Referrer-Policy strict-origin-when-cross-origin
        -Server
    }
    file_server
}
music.example.net {
    reverse_proxy 172.16.1.12:4533
}
example.net {
    redir https://www.example.net{uri} permanent
}

Dodaj w DNS A www.example.net → YOUR_WAN_IP i A music.example.net → YOUR_WAN_IP, potem:

docker compose up -d
docker logs --tail=150 home-public
curl -I https://www.example.net

Gdy TLS nie przechodzi, diagnozuj kolejno: DNS, dostępność WAN:80/443, NAT oraz konflikt portów. Nie wyłączaj walidacji certyfikatu „na próbę”.

ETAP 4 — JEDEN PUNKT STARTOWY

Homepage: katalog usług

Homepage jest startową stroną LAN, nie publicznym panelem administracyjnym. Karty mogą prowadzić do prywatnych adresów, jeśli użytkownik jest w LAN/VPN.

- AI:
    - Home AI:
        href: http://172.16.1.34:3002
        description: Lokalny agent i modele na GPU
    - ComfyUI:
        href: http://172.16.1.34:8188
        description: Generowanie obrazów
- Obserwowalność:
    - Grafana:
        href: http://172.16.1.12:3030
        description: Logi i trendy

ETAP 5 — WIDOCZNOŚĆ PRZED AUTOMATYZACJĄ

Uptime Kuma, MySpeed, Loki i Grafana

Uptime Kuma sprawdza dostępność (np. Internet co minutę i urządzenia LAN), MySpeed mierzy łącze, a Grafana/Loki odpowiadają na pytanie „co się działo?”. Oznacz logi etykietami source, device i severity.

MikroTik / AP ──syslog UDP──> Alloy ──> Loki ──> Grafana
NAS Docker logs ────────────> Alloy ──> Loki ──> Grafana

Na MikroTik rozdziel akcje sysloga według poziomu na osobne porty Alloy. Dzięki temu dashboard nie zgaduje krytyczności na podstawie tekstu.

/system logging action add name=loki-error target=remote remote=172.16.1.12 remote-port=1515 remote-log-format=syslog
/system logging add topics=error action=loki-error
# Analogicznie: critical -> 1514, pozostałe -> 1516.
# Dopasuj topics do RouterOS i potwierdź /log print.
sum by (severity) (count_over_time({source="MikroTik"}[15m]))
topk(10, sum by (message) (count_over_time({source="MikroTik",severity="error"}[24h])))

Najpierw wyślij testowy wpis i znajdź go w Grafana Explore. Dopiero wtedy buduj wykresy: MikroTik/AP × critical/error/other oraz Top 10 komunikatów.

ETAP 6 — PC JAKO WARSTWA GPU

Windows, Docker Desktop, Ollama i Open WebUI

PC pozostaje prywatnym wykonawcą modeli. Docker Desktop uruchamia Open WebUI, Ollama udostępnia modele na 11434, a ComfyUI pracuje na tym samym GPU. Nie zakładaj, że duży model i generator obrazów zmieszczą się równocześnie w VRAM.

services:
  open-webui:
    image: ghcr.io/open-webui/open-webui:PINNED_VERSION
    container_name: home-ai-webui
    restart: unless-stopped
    ports:
      - "172.16.1.34:3002:8080"
    volumes:
      - ./data:/app/backend/data
    environment:
      OLLAMA_BASE_URL: http://host.docker.internal:11434
      WEBUI_AUTH: "True"
      ENABLE_SIGNUP: "False"
# PowerShell na PC
curl http://127.0.0.1:11434/api/tags
docker ps
docker logs --tail 100 home-ai-webui

Ustaw ograniczony czas trzymania modelu, np. OLLAMA_KEEP_ALIVE=5m, i jeden model na raz. RAM nie jest automatycznym zapasem VRAM: model nadal musi zostać przesłany do GPU.

ETAP 7 — AGENT MA NARZĘDZIA, NIE TELEPATIĘ

Integracje lokalnego agenta

Model bez narzędzi nie ma dostępu do Internetu, Gmaila ani SSH. Każde połączenie jest osobnym API z własnym tokenem i małym zakresem uprawnień.

  • PC Observer: odczyt systemu, sieci, usług, aplikacji i zatwierdzonych obszarów rejestru; bez dowolnych komend i bez zapisu.
  • SSH operator: osobne urządzenia NAS/router i rejestrowane polecenia. Odczyt jest domyślny; zmiany są jawne.
  • Gmail/Calendar: analiza skrzynki, szkice odpowiedzi oraz wydarzenia zgodnie z ustaloną regułą. Wysyłka pozostaje zatwierdzana.
  • WWW: ograniczony dostawca i polityka źródeł, aby odpowiedź dało się zweryfikować.
  • RAG: dokumenty są indeksowane fragmentami i pobierane do kontekstu na żądanie; nie są treningiem modelu i nie mogą zawierać sekretów.

ETAP 8 — ODTWARZANIE TO CZĘŚĆ WDROŻENIA

Backup, aktualizacje i test odbiorowy

Co archiwizować

  • Compose, Caddyfile, konfiguracje Homepage/Grafana/Alloy oraz eksport MikroTik.
  • Katalogi trwałe: Caddy data, Vaultwarden, Navidrome, Grafana i Loki.
  • Klucze oraz tokeny wyłącznie w menedżerze haseł lub szyfrowanym backupie.

Utrzymanie

  1. Przed aktualizacją wykonaj eksport routera, backup konfiguracji i sprawdź wolne miejsce.
  2. Aktualizuj jedną usługę: docker compose pull SERVICE, następnie docker compose up -d SERVICE.
  3. Sprawdź healthcheck, logi i stronę; w razie problemu wróć do poprzedniego przypiętego tagu.
  4. Raz w miesiącu odtwórz testowo jedną małą usługę na osobnym porcie.
# NAS
sudo /var/packages/ContainerManager/target/usr/bin/docker ps
curl -I http://172.16.1.12:3000
curl -I https://www.example.net

# PC
curl http://172.16.1.34:11434/api/tags
curl -I http://172.16.1.34:3002

# Router
/log print where topics~"error"
/ip firewall nat print where comment~"Caddy"

Po każdej zmianie testuj z LAN, przez VPN oraz — dla usług publicznych — z sieci komórkowej. Dokumentacja opisuje założenia; test potwierdza rzeczywistość.