Wróć do bloga

rodzinal.pl — jak zbudowałem prywatną infrastrukturę dla rodziny na laptopie

Architektura self-hosted serwisów rodzinnych: Incus, WireGuard, HAProxy, Stalwart Mail, Nextcloud i Collabora — na ThinkPadzie P51 stojącym w domu.

rodzinal.pl to mój prywatny serwis rodzinny — poczta, chmura z edycją dokumentów, strona. Nie chciałem płacić za Google Workspace ani polegać na zewnętrznych dostawcach przy danych rodziny. Efekt: działający stack na laptopie ThinkPad P51 stojącym w domu, VPS we Francji jako punkt wejścia i failover przez kartę SIM.

W tym artykule opisuję architekturę od sprzętu po routing, z uzasadnieniem każdej decyzji projektowej.

Sprzęt — ThinkPad P51 jako serwer domowy

Laptop nie był przypadkowy. ThinkPad P51 to stacja robocza w formacie laptopa:

  • CPU: Intel Xeon E3-1505M (4 rdzenie, 8 wątków, 2.8–3.7 GHz)
  • RAM: 32 GB ECC
  • Dyski:
    • 2× Samsung 970 Pro NVMe w RAID-1 — dane i kontenery
    • 500 GB SSD — system operacyjny
  • Wbudowany adapter SIM — kluczowy element failover

Łączny koszt sprzętu (używany): ok. 2000 PLN jednorazowo. Zmierzone watomierzem zużycie w idle: 10W — jak mini-PC, dużo lepiej niż klasyczna wieża. Bonus: wbudowana bateria robi za UPS przy chwilowych przerwach prądu, a przy niskim obciążeniu wentylator się nie włącza.

RAID-1 na NVMe

Dwa dyski NVMe w RAID-1 zapewniają ochronę przed awarią nośnika bez wpływu na wydajność odczytu. Dane /var/lib/incus (kontenery i wolumeny) są na tej macierzy.

Obecnie: pełne szyfrowanie LUKS całych dysków. Docelowo planuję szyfrować tylko partycję z danymi Incusa (/var/lib/incus), a resztę systemu zostawić bez szyfrowania — żeby restart po awarii prądu nie wymagał ręcznego wpisywania hasła.

Topologia sieci

Internet
    │
    ▼
[VPS — FR] ←────── WireGuard VPN ──────► [ThinkPad P51 — PL]
 HAProxy (zewnętrzny)                      HAProxy (ruch zewnętrzny)
 GeoIP filtering                           HAProxy (most między-kontenerami)
                                           Kontenery Incus
                                              ├── www        (10.10.0.10)
                                              ├── cloud      (10.10.0.20)
                                              ├── mail       (10.10.0.30)
                                              ├── collabora  (10.10.0.40)
                                              └── roundcube  (10.10.0.50)

VPS od Contabo we Francji (~28 PLN/miesiąc) to punkt wejścia. Ma stały publiczny IP i przekazuje ruch do laptopa przez tunel VPN. Laptop w domu ma dynamiczne IP od ISP — dlatego VPN jest kluczowy.

WireGuard — prywatna sieć między VPS a domem

WireGuard łączy VPS (FR) z laptopem (PL) w prywatną sieć 10.0.0.0/24. Każde żądanie do rodzinal.pl docierające na VPS jest przez tunel przekazywane do kontenera na laptopie.

Dlaczego WireGuard:

  • Mała powierzchnia ataku (krótki codebase w porównaniu do OpenVPN)
  • Automatyczny reconnect po przerwie
  • Niskie opóźnienia dzięki UDP
  • Prosta konfiguracja na kluczach publicznych

VPS robi za koncentrator — nie trzyma żadnych danych, tylko przekazuje ruch.

GeoIP filtering — ograniczenie geograficzne dostępu

Na HAProxy (na VPS-ie) mam skonfigurowany filtr GeoIP. Ruch HTTPS wpuszczam tylko z czterech krajów:

  • PL — Polska (dom)
  • FR — Francja (lokalizacja VPS — potrzebne do wewnętrznych healthchecków)
  • AT — Austria (część rodziny)
  • IT — Włochy (część rodziny)

Żądania z innych krajów są odrzucane na poziomie load balancera — HAProxy zamyka połączenie TCP, zanim ruch w ogóle dotrze do tunelu VPN czy kontenerów. To mocno ogranicza ekspozycję na skanery, boty i brute-force.

HAProxy korzysta z bazy MaxMind GeoLite2 aktualizowanej automatycznie.

HAProxy — trzy poziomy routingu

HAProxy zewnętrzny (VPS)

Sprawdza GeoIP i przekazuje cały ruch TCP do laptopa przez WireGuard. HAProxy na VPS-ie działa w trybie TCP — nie terminuje TLS, nie routuje po SNI. Używa PROXY protocol, żeby prawdziwy IP klienta dotarł dalej. Ruch zablokowany przez GeoIP jest odrzucany na poziomie TCP (zamknięcie połączenia).

HAProxy wewnętrzny — routing ruchu zewnętrznego (laptop)

Pierwszy serwis HAProxy na laptopie nasłuchuje na interfejsie WireGuard, odbiera ruch z VPS i routuje go po SNI do konkretnych kontenerów Incusa po ich wewnętrznych adresach IP (10.10.0.x). Działa w trybie TCP z PROXY protocol — kontener dostaje prawdziwy IP klienta, nie adres HAProxy. TLS obsługują same kontenery — każdy z publicznym endpointem (www, cloud, mail, roundcube) ma własny certyfikat Let's Encrypt i sam go odnawia. Collabora nie ma certyfikatu publicznego — działa tylko wewnętrznie i go nie potrzebuje.

frontend https_in
  bind 10.0.5.2:443 accept-proxy
  mode tcp
  use_backend cloud_443     if { req.ssl_sni -i cloud.rodzinal.pl }
  use_backend mail_443      if { req.ssl_sni -i mail.rodzinal.pl }
  use_backend roundcube_443 if { req.ssl_sni -i m.rodzinal.pl }
  default_backend www_443

Dzięki temu kontenery nie mają bezpośredniego dostępu do internetu — cały ruch przychodzący przechodzi przez ten jeden punkt wejścia.

HAProxy wewnętrzny — most między kontenerami (laptop)

Drugi, osobny HAProxy robi coś zupełnie innego: jest mostem dla komunikacji między samymi kontenerami. Zamiast pozwolić kontenerom gadać ze sobą bezpośrednio po sieci Incusa, ruch między nimi przechodzi przez ten serwis.

Przykład: Nextcloud musi wysłać powiadomienie e-mail — nie łączy się bezpośrednio ze Stalwartem na 10.10.0.30, tylko przez wewnętrzny most HAProxy. To samo dotyczy Roundcube komunikującego się ze Stalwartem przez IMAP/SMTP, czy Nextclouda łączącego się z Collaborą.

Każde dozwolone połączenie między kontenerami jest jawnie zdefiniowane jako reguła. Jeśli kontener próbuje połączyć się z czymś, do czego nie ma reguły — ruch jest blokowany. Nawet kompromitacja jednego kontenera nie daje atakującemu swobodnego dostępu do pozostałych serwisów.

Kontenery Incus — izolacja serwisów

Zamiast stawiać wszystko bezpośrednio na hoście, każdy serwis żyje we własnym kontenerze systemowym Incus. Incus to następca LXD — aktywnie utrzymywany projekt open source.

KontenerIPSerwis
www10.10.0.10Strona rodzinal.pl
cloud10.10.0.20Nextcloud
mail10.10.0.30Stalwart Mail
collabora10.10.0.40Collabora (LibreOffice)
roundcube10.10.0.50Roundcube (webmail)

Każdy kontener to oddzielny system plików i przestrzeń procesów. Awaria jednego serwisu (np. crash Nextclouda) nie wpływa na pozostałe. Aktualizacje można robić per kontener, bez zatrzymywania całości.

Wolumeny z danymi są montowane do kontenerów z macierzy RAID-1.

Stalwart Mail — serwer pocztowy

Stalwart to nowoczesny serwer pocztowy napisany w Ruście — SMTP, IMAP i JMAP w jednym procesie. W porównaniu do klasycznego Postfix+Dovecot, Stalwart ma:

  • Wbudowaną obsługę SPF, DKIM, DMARC
  • Web UI do zarządzania kontami
  • Natywne JMAP (nowoczesny protokół synchronizacji poczty)

Konfiguracja DNS obejmuje:

  • Rekord MX wskazujący na VPS
  • SPF i DKIM dla domeny rodzinal.pl
  • DMARC z raportowaniem

Port 25 (SMTP) wychodzący jest odblokowany przez ISP — to często bywa problemem w sieciach domowych. Jednak nawet odblokowany port 25 nie wystarczy — wysyłanie poczty bezpośrednio z domowego IP skutkuje odrzucaniem wiadomości przez serwery odbiorców, bo adresy IP sieci domowych mają złą reputację u dostawców poczty.

Rozwiązanie: reguła iptables dodana przez WireGuard kieruje cały ruch wychodzący na port 25 przez VPS we Francji. Stalwart wysyła wiadomość, ale połączenie do serwera odbiorcy wychodzi z IP VPS-a — czystego adresu z puli datacenter. Domowe IP w ogóle nie jest widoczne dla zewnętrznych serwerów pocztowych.

Początkowo używałem portu 587 (SMTP z STARTTLS). Zmieniłem na 465 (SMTPS). Różnica jest istotna: STARTTLS na 587 zaczyna połączenie plaintextem i dopiero potem negocjuje szyfrowanie — teoretycznie możliwy jest atak downgrade wymuszający nieszyfrowane połączenie. Port 465 z implicit TLS szyfruje od pierwszego bajtu. Dla serwera rodzinnego, gdzie kontroluję konfigurację wszystkich klientów, 465 to prostszy i bezpieczniejszy wybór.

Konta użytkowników i grupy

Każda osoba w rodzinie ma własne konto w Stalwarcie — osobną skrzynkę pocztową i osobne dane logowania. Oprócz indywidualnych kont skonfigurowane są grupy dla wspólnych adresów e-mail (np. kontaktowy adres całej rodziny), na które wiadomości trafiają do wielu skrzynek jednocześnie.

Stalwart jako dostawca tożsamości

Stalwart obsługuje OAuth2/OIDC — działa jako Identity Provider dla całego stosu. Nextcloud i Roundcube uwierzytelniają użytkowników przez Stalwarta.

W praktyce: jedno konto = jeden login do poczty, chmury i webmaila. Użytkownik loguje się do Nextclouda tymi samymi danymi co do poczty — Nextcloud deleguje weryfikację do Stalwarta przez OAuth2 i dostaje potwierdzenie bez dotykania hasła.

Zalety tego podejścia:

  • Jedno źródło prawdy — konta zarządzane tylko w Stalwarcie
  • Zmiana hasła w jednym miejscu — obowiązuje od razu wszędzie
  • Brak lokalnych kont w Nextcloudzie i Roundcube — mniejsza powierzchnia ataku
  • Możliwość centralnego wyłączenia dostępu — dezaktywacja konta w Stalwarcie odcina użytkownika od wszystkich serwisów jednocześnie

Nextcloud + Collabora — chmura z edycją dokumentów

Nextcloud daje synchronizację plików, kalendarze i kontakty (CalDAV/CardDAV). Collabora to serwer LibreOffice Online — edycja .docx, .xlsx, .odt prosto w przeglądarce, zintegrowana z Nextcloudem. Collabora nie ma publicznego endpointu — działa tylko wewnętrznie i jest dostępna wyłącznie dla Nextclouda.

Kalendarze z Nextclouda synchronizuję z telefonami przez CalDAV — wystarczy dodać konto w ustawieniach telefonu. Poczta na telefonie idzie przez K-9 Mail, który łączy się ze Stalwartem po IMAP i SMTP. Roundcube to webmail — dostęp do poczty z przeglądarki bez instalowania czegokolwiek, przydatny gdy ktoś z rodziny jest na obcym komputerze. Roundcube ma podpiętą książkę adresową z Nextclouda przez plugin CardDAV — zmiana kontaktu w jednym miejscu widoczna jest wszędzie.

Na Nextcloudzie jest wspólna przestrzeń dyskowa dla całej rodziny — dokumenty, zdjęcia, co tam trzeba.

Do zastosowań domowych taki stack w zupełności wystarcza: poczta, chmura z edycją dokumentów, kalendarze i kontakty zsynchronizowane między telefonami i komputerami — bez polegania na zewnętrznych dostawcach.

Collabora i Nextcloud działają w oddzielnych kontenerach i komunikują się przez sieć wewnętrzną Incusa. Nextcloud łączy się z Collaborą przez wewnętrzny adres 10.10.0.40 — ruch nie wychodzi poza maszynę.

Dane Nextclouda (pliki, baza danych) są na wolumenie z RAID-1.

Failover przez kartę SIM

To jeden z ciekawszych elementów. ThinkPad P51 ma wbudowany adapter SIM, który pojawia się jako dodatkowy interfejs sieciowy (wwan0).

Problem z łącznością domową jest prosty: awaria ISP, reboot routera, przerwa prądu — VPN pada, serwisy niedostępne.

Rozwiązanie: metryki routingu w Linuksie.

# Kabel (ethernet) — niższa metryka = preferowana
ip route add default via 192.168.1.1 metric 100

# SIM — wyższa metryka = fallback
ip route add default via 10.128.0.1 metric 200

Kiedy interfejs ethernetowy traci link (router wyłączony, kabel odłączony), kernel automatycznie przełącza ruch na trasę z wyższą metryką (SIM). Kiedy link wraca — niższa metryka znów wygrywa i ruch wraca na kabel. Uwaga: jeśli ISP padnie, ale router domowy nadal działa i przydziela DHCP — ethernet ma link UP i failover nie nastąpi. Pełna automatyzacja tego scenariusza wymagałaby watchdoga sprawdzającego łączność z internetem.

WireGuard po przerwie wznawia tunel sam. Okno niedostępności przy przełączaniu: kilkanaście sekund.

Karta SIM na failover to koszt 25 PLN miesięcznie. Warto.

Powiadomienia SMS z kalendarza

Nextcloud trzyma kalendarze rodziny. Napisałem skrypt, który cyklicznie odpytuje CalDAV, pobiera nadchodzące eventy i wysyła SMS-y z przypomnieniem — kto, co i o której.

Ciekawostka: SMS nie idzie przez żadne zewnętrzne API ani bramkę. Wychodzi prosto przez modem ThinkPada P51 — tę samą kartę SIM T-Mobile, która robi za failover łączności. Modem jest widoczny jako urządzenie szeregowe, skrypt wysyła SMS-y komendami AT prosto do modemu.

Jedna karta SIM, dwie role: failover internetu i kanał powiadomień SMS. Zero dodatkowych kosztów, zero zewnętrznych zależności.

Backup

Backup ma cztery warstwy:

  1. RAID-1 — ochrona przed awarią nośnika, nie przed błędem logicznym ani utratą danych
  2. Lokalny backup na dysku systemowym — zaszyfrowana kopia danych kontenerów na partycji dysku 500 GB (tego samego co system operacyjny); chroni przed błędem logicznym i przypadkowym usunięciem
  3. Backup offsite na Contabo VPS — zaszyfrowane kopie przesyłane na serwer Contabo (6.5 EUR/miesiąc); chroni przed fizyczną utratą sprzętu
  4. Wewnętrzny backup Contabo — Contabo wykonuje własne snapshoty środowiska VPS niezależnie; dodatkowa warstwa bez żadnego dodatkowego kosztu

Kopie lokalna i offsite są szyfrowane przed transferem. Cel: możliwość odtworzenia środowiska na nowej maszynie bez utraty danych.

Podsumowanie kosztów

PozycjaKoszt
Sprzęt (ThinkPad P51, używany)~2000 PLN jednorazowo
Contabo VPS (punkt wejścia + backup offsite)~28 PLN/miesiąc (6.5 EUR)
Karta SIM (failover + SMS)25 PLN/miesiąc
Łącznie miesięcznie~53 PLN/miesiąc

Ten sam VPS Contabo robi dwie rzeczy: punkt wejścia dla ruchu (HAProxy, WireGuard) i miejsce na backup offsite — bez dodatkowych kosztów.

Prąd przy 10W to ok. 7 kWh miesięcznie — niecałe 5 PLN. Pomijalne.

Dla porównania: Google Workspace dla rodziny (6 kont) to ok. 360 PLN miesięcznie. Ta architektura kosztuje ponad 6× mniej, z pełną kontrolą nad danymi.

Zużycie zasobów

Aktualny stan przy pełnym obciążeniu produkcyjnym (wszystkie kontenery aktywne):

  • RAM: ~2 GB
  • Load average: 0.13 / 0.06 / 0.02

To spora zmiana w porównaniu do tego co było wcześniej. Używałem osobnych VM-ek z Mailcow zamiast Stalwarta — tamta konfiguracja zjadała ok. 18 GB RAM. Przejście na kontenery Incus + Stalwart zamiast pełnych VM + Mailcow zmniejszyło zużycie pamięci o ponad 80%.

VM-ki mają własne kernele i pełne systemy gościa — stąd ogromne narzuty. Kontenery Incus dzielą kernel hosta, co eliminuje sporą część tego kosztu. Stalwart w jednym procesie zastępuje cały stos Mailcow (Postfix, Dovecot, Rspamd, Redis, MySQL...).

Na ThinkPadzie z 32 GB RAM mam teraz 30 GB wolnych — sporo miejsca na przyszłe serwisy.

Zalety i wady

Self-hosting na własnym sprzęcie ma konkretne zalety i wady.

Zalety:

  • Pełna kontrola nad danymi — bez dostawcy chmurowego w środku
  • Niski koszt przy amortyzacji sprzętu
  • Nauka — każdy element wymaga zrozumienia
  • Możliwość customizacji, której SaaS nie daje

Wady:

  • Czas i wiedza do utrzymania — to nie jest zero-ops
  • Dostępność zależy od łącza domowego
  • Awaria sprzętu wymaga ręcznej interwencji
  • Bezpieczeństwo spoczywa wyłącznie na właścicielu

Dla rodziny, która rozumie kontekst i akceptuje te wymagania — sprawdza się. System chodzi od kilku miesięcy bez większych problemów.

Drugi węzeł — czy da się dodać laptop w innej lokalizacji?

WireGuard obsługuje wielu peerów — technicznie da się dodać drugi laptop (np. u rodziny w Austrii) jako kolejny węzeł w tej samej sieci VPN. VPS we Francji robiłby wtedy za koncentrator obu węzłów. HAProxy na VPS-ie mógłby sprawdzać stan obu backendów i kierować ruch do tego, który działa.

Dla serwisów bezstanowych (strona www) to działa bez problemów — HAProxy robi health-check i failover jest automatyczny.

Problem pojawia się przy serwisach ze stanem:

Nextcloud — pliki muszą być zsynchronizowane między węzłami. Można to rozwiązać przez replikację RAID-1 przez sieć (np. DRBD), ale to złożone i wrażliwe na opóźnienia między lokalizacjami. Prostsze podejście: jeden węzeł jest aktywny, drugi to hot standby — dane są replikowane jednostronnie, failover jest ręczny lub półautomatyczny.

Stalwart Mail — Stalwart wspiera tryb klastrowy, więc wielowęzłowe wdrożenie jest możliwe. Wymaga jednak współdzielonego backendu bazodanowego i storage dla wiadomości. W prostym scenariuszu failover wystarczy jedna aktywna instancja z replikowanymi danymi.

Wniosek: architektura nadaje się do rozbudowy o drugi węzeł jako pasywny failover — VPS kieruje ruch do aktywnego węzła, w razie awarii przełącza na drugi. Active-active z dwoma węzłami piszącymi jednocześnie wymagałoby istotnie innego podejścia do synchronizacji danych i wykracza poza zakres tej architektury.

Co dalej — selfsource

rodzinal.pl zaczęło się jako własny projekt, ale przy okazji udowodniło że taka architektura działa. Każdy element — Incus, WireGuard, HAProxy, Stalwart, Nextcloud — da się powtórzyć. Problem w tym, że wymaga to wiedzy z kilku dziedzin naraz: sieci, Linuksa, konfiguracji poczty, konteneryzacji.

Właśnie to jest punktem wyjścia dla selfsource — platformy, która pozwoli każdemu postawić taką infrastrukturę przez panel administracyjny, bez grzebania w konfiguracjach. Wybierasz serwisy, podajesz domenę — reszta dzieje się sama.

rodzinal.pl to prototyp. selfsource to produkt.