Termin reverse proxy na pewno kiedyś obił się o uszy. Traefik, Nginx, Apache, a może HAProxy? Niezależnie od wybranej aplikacji, zasada działania pozostaje ta sama. Postaram się omówić to wspaniałe narzędzie w sposób maksymalnie prosty. Oprzemy się o Nginx Proxy Manager uruchomionego w kontenerze.

Kilka słów o zasadzie działania

Wyobraź sobie sytuację, w której masz uruchomione kilka usług i są one wyeksponowane na świat. Może to strona internetowa, może do tego jakiś NAS, może podgląd do rejestratora? Może nawet posiadasz domenę i sobie zrobiłeś w panelu zarządzania domeną subdomeny, które kierują ruch na konkretne usługi na konkretnym adresie IP i konkretnym porcie?

Na routerze też pewnie masz przekierowane kilka portów na kilka usług. No i szyfrowanie ruchu, HTTPS rzecz jasna, SSL i cała certyfikacyjna świta. Może nawet użyłeś Certbota do wygenerowania certyfikatu i pilnujesz, aby darmowe certyfikaty z LetsEncrypt aktualizować na bieżąco. No i pamiętasz o tym, aby przechodzić przez całą ścieżkę zarządzania domenami, kopiowania certyfikatów, konfiguracji z palca routera, zabezpieczania każdego portu, szyfrowania…

Ludzie z natury są leniwi. Ale nie tak, że nie chce im się robić czegoś, ale tak, że nie chce im się czegoś robić dwa razy. Albo trzy razy. Czy tam siedemnaście. A przy okazji piekąc dwie (albo siedemnaście) pieczeni na jednym ogniu, można spokojnie odetchnąć i delektować się opierdalaniem przed telewizorem. Zachęciłem?

Wyobraź sobie, że eksponujesz jeden port, przekierowujesz jeden port, certyfikatami zarządzasz w jednym miejscu, subdomeny klikasz w jednym miejscu i nie musisz pilnować żadnych certyfikatów, tak długo, jak nic nie płonie. No i sobie robisz hatetepeesa, nie zgadniesz, jednym kliknięciem. Ej, ja w to wchodzę!

Teraz na serio: reverse proxy to coś w rodzaju mądrego parkingu z Tokio Drift podającego samochód właścicielowi. Eksponujesz jeden port, który kierujesz na host z uruchomionym reverse proxy i to tyle. Reverse proxy odzywa się do maszyn z aplikacjami, reverse proxy serwuje certyfikaty i reverse proxy obsługuje kierowanie ruchem. Reverse proxy to serwer pośredniczący, który przyjmuje ruch z Internetu i przekazuje go do odpowiednich usług wewnątrz sieci na podstawie domeny, ścieżki lub innych reguł. Widzisz już pewne zalety z tego płynące?

Co mi to daje?

Więcej czasu na browara, ale nie od razu, ale potem. Koniec zalet, do widzenia.

Przyjrzyj się ponownie zasadzie działania nakreślonej w poprzednim akapicie. Patrz:

  • Certyfikatami zarządzasz w ramach jednego eksponowanego hosta (spore uproszczenie, ale nam to teraz wystarczy)
  • Pilnujesz jednego wejścia do sieci, nie siedemnastu
  • Bardzo elastycznie zarządzasz subdomenami
  • Możesz łatwo zarządzać ruchem w obrębie domeny
  • Oszczędzasz czas, robiąc prawidłową konfigurację tylko raz
  • Łatwość sterowana i określania skąd dana subdomena może być osiągalna. NAS dostępny publicznie? A proszę bardzo. Monitoring tylko z adresów sieci LAN? Nic więcej nie mów, masz to
  • Automatyczna aktualizacja certyfikatów (odnawianie, aktualizacja, dodawanie, usuwanie, etc…)
  • Bezpieczeństwo. To potężny boost bezpieczeństwa, jeśli prawidłowo to uruchomisz
  • Load balancer? A proszę, czemu nie?
Brak reverse proxy. Problem mocno. Oznaczamy to smutną minką 😞
Reverse proxy. Brak problemu, oznaczamy szczęśliwą minką 😃
Podobieństwo niezamierzone

Każdy z hostów, który znajduje się za reverse proxy, komunikuje się wyłączne z reverse proxy. Użytkownik komunikuje się z reverse proxy, a nie z hostami za nim. Użytkownik nie widzi reverse proxy, ale ono czuwa i pilnuje, żeby ten nie zamienił się w użyszkodnika. Reverse proxy to odpowiedz na wszystkie pytania ludzkości.

Niby nie zrobi ci kawy, ale robi porządek w sieci. A to niemal to samo.

Może także ogarniać balansowanie ruchu pomiędzy różnymi instancjami aplikacji. Jeśli zastanawiałeś się kiedyś, w jaki sposób można robić testy na produkcji, to to jest jedna z odpowiedzi na to pytanie. Właśnie tutaj czasami wprowadza się zmiany na np. 30% produkcji i obserwuje feedback. Jeśli jest ok, to wdrażasz zmiany w 100%, jeśli się coś obsrało, to tylko jedna trzecia śmierdzi. 70% lata i działa jak dotychczas. Możesz też po prostu rozkładać ruch na poszczególne segmenty infrastruktury. Jeden serwer się nudzi a drugi poci się od nadmiaru zapytań? Wyłącz ten drugi. Reverse proxy może to zbalansować. Nie traktuj tego jednak jak wyłącznej funkcjonalności, bo mówienie, że reverse proxy i load balancer to to samo, to jak pomylenie odwagi z odważnikiem. Różnice są spore, load balancer potrafi pracować zarówno w warstwie 7 OSI, jak i 4 OSI. Reverse proxy siedzi w warstwie aplikacji (siódemka OSI).

To oczywiście wycinek funkcjonalności. Na początku jednak najważniejsze jest jednak samo kierowanie ruchu i zabezpieczanie go. Na resztę przyjdzie czas, spokojnie, nie denerwuj się.

Stack technologiczny: co potrzebuję?

  • wygodnie mieć domenę, polecam jakiś tani śmietnik w Cloudflare
  • wjazd na router i umiejętność przekierowania portów (podpowiem ci co i jak…)
  • maszyna wirtualna albo jakiś stojący odłogiem pecet (serwerek?)
  • Docker na wyżej wymienionym sprzęcie
  • kawa
  • wskazane jest posiadanie mózgu, ale ten punkt potraktujmy nieco umownie
  • dozwolony ruch pomiędzy hostami, szczególnie pomiędzy serwerem z reverse proxy a aplikacjami
  • Najwygodniej w ramach reverse proxy używać portu 443. Nie jest to wymóg, ale nie komplikuj sobie na początku. Jeśli coś masz na adresie WAN routera i porcie 443 uruchomione (np. panel konfiguracji routera), przesuń go na inny port. Sprawdź w instrukcji routera jak to zrobić, albo zapytaj się dostawcy internetu

Warto dysponować większym zapasem czasu. Pozostawiając sarkazm, będziemy dłubać we wpisach związanymi z DNS, a te potrzebują trochę czasu na propagację. Czasami to trwa kilka minut, czasami niemal od ręki, ale niczym nie zwykłym jest witanie poranka z włączonym pingiem.

Warto przeczytać wpisy związane z rejestracją domeny oraz instalacją Dockera. W domyśle wszystko posadzimy na Linuksie, ale przy odrobinie samozaparcia cały proces nie jest mocno zależny od systemu operacyjnego.

Lubię generować grafiki w AI (wolę nie rysować). Podoba mi się, zostaje, bez powodu.

Gangi Novigradu Dockera

Przygotujmy sobie maszynę, na której przygotujemy sobie dwie przykładowe, działające usługi. Nie ma to teraz znaczenia, co to będzie. W przypadku mojego laba adres IP maszyny to 192.168.10.18. Posadzony na nim jest Debian, zainstalowany Docker. Tak, użyłem do instalacji mojego skryptu. Tylko głupiec by nie skorzystał.

Aplikacje? A proszę bardzo. Dwie instancje Nginx podstawiające prostego hateemela. Nic ambitnego, ale teraz o to chodzi. Nazwijmy to App1 i App2.

To moja strona i mój poradnik, uspokój się, nie kwestionuj moich metod.

Utworzyłem dwa katalogi z określoną strukturą i plikami. App1:

app1/
│
├─ docker-compose.yml
├─ nginx/
│ ├─ default.conf
│ └─ index.html

App2:

app2/
│
├─ docker-compose.yml
├─ nginx/
│ ├─ default.conf
│ └─ index.html

App1 docker-compose.yml:

services:
  nginx:
    image: nginx:latest
    container_name: app1
    ports:
      - 8080:80
    volumes:
      - ./nginx/index.html:/usr/share/nginx/html/index.html:ro
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
    restart: unless-stopped

App2 docker-compose.yml:

services:
  nginx:
    image: nginx:latest
    container_name: app2
    ports:
      - 8081:80
    volumes:
      - ./nginx/index.html:/usr/share/nginx/html/index.html:ro
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
    restart: unless-stopped

App1 i App2 nginx/default.conf:

server {
    listen 80;
    server_name localhost;

    location / {
        root /usr/share/nginx/html;
        index index.html;
    }
}

App1 nginx/index.html:

<!DOCTYPE html>
<html>
<head>
    <title> APP1 Hello World</title>
</head>
<body>
    <h1>Hello World, jestem APP1</h1>
</body>
</html>

App2 nginx/index.html

<!DOCTYPE html>
<html>
<head>
    <title> APP2 Hello World</title>
</head>
<body>
    <h1>Hello World, jestem APP2</h1>
</body>
</html>

Podnosimy kontenery

cd app1
docker compose up -d
cd ../app2
docker compose up -d

Sprawdzamy kontenery:

docker ps -a

Działa. Jak natura chciała.

Czym teraz dysponujemy? Działającymi lokalnie dwoma serwerami Nginx, serwującymi prostą stronę internetową. Możemy sprawdzić za pomocą curl, czy na pewno to działa:

user@TMPHost:~$ curl 192.168.10.18:8080
<!DOCTYPE html>
<html>
<head>
    <title> APP1 Hello World</title>
</head>
<body>
    <h1>Hello World, jestem APP1</h1>
</body>
</html>
user@TMPHost:~$ curl 192.168.10.18:8081
<!DOCTYPE html>
<html>
<head>
    <title> APP2 Hello World</title>
</head>
<body>
    <h1>Hello World, jestem APP2</h1>
</body>
</html>

Widzimy w odpowiedzi, że tak, że to działa, bo widzimy kod html przygotowanych przez nas stron internetowych.

Uściślając:

  • App1 działa pod adresem http://192.168.10.18:8080
  • App2 działa pod adresem http://192.168.10.18:8081
  • Ruch jest nieszyfrowany, brak certyfikatów
  • Łatwo podsłuchać taką transmisję
  • Brak zielonej kłódki w adresie ssie

To jest ten moment, gdzie warto się zainteresować pierwszą kawką. Albo piwkiem. Zależy, co wolisz. W cyfrowym świecie dysponujesz właśnie uruchomionymi dwoma serwerami HTTP, dość niezależnymi od siebie, niezbyt zabezpieczonymi, ale nie marudź, smacznej kawusi i czytaj dalej.

A gdzie ten reverse proxy?

Spokojnie. Właśnie to uruchamiamy. Najpierw potrzebna nam będzie aplikacja. Moim pierwszym wyborem jest Nginx Proxy Manager (znany jako NPM) i to na nim się oprę w dalszej części artykułu. Zasady są jednak dość uniwersalne, niezależnie od wybranej aplikacji, ale NPM pozwala na dość bezbolesne wejście do tego świata. Jeśli czujesz się wystarczająco mocny, uruchom coś innego, spoko, ale na samym początku nie zauważysz różnic aplikacjach, poza sposobem konfiguracji. A zapewniam cię, że NPM jest pod tym względem wybitnie dobry.

Instalację zaczniemy od utworzenia na 192.168.10.18 kolejnego kontenera. Oczywiście możesz utworzyć kolejną maszynę wirtualną albo przytachać kolejny komputer z piwnicy, nie ma problemu. Warunkiem jest to, o czym wspomniałem wyżej, czyli to, aby hosty pozwalały na komunikację HTTP pomiędzy sobą, bo inaczej reverse proxy nie zadziała prawidłowo. Na stan obecny można spokojnie majstrować to w ramach jednej maszyny wirtualnej i operować kontenerami.

W pierwszym odruchu polecam zajrzeć na stronę projektu. Jest tam świetnie opisany poradnik i szybki start. Warto jednak domyślnie podany plik docker-compose.yml nieco zmodyfikować:

services:
  app:
    image: 'jc21/nginx-proxy-manager:latest'
    restart: unless-stopped
    environment:
      TZ: "Europe/Warsaw"
    ports:
      - '80:80'
      - '81:81'
      - '443:443'
    volumes:
      - ./data:/data
      - ./letsencrypt:/etc/letsencrypt

Plik umieść w katalogu NPM. Należy się też szybkie wyjaśnienie. Spójrz na porty, które są eksponowane, bo mogą trochę zamieszać w zrozumieniu:

  • 80 oraz 443 to klasyczne porty HTTP/HTTPS. One służą do obsługi ruchu stron internetowych. Obecnie od 80/HTTP się odchodzi, spokojnie można pozostać na 443/HTTPS i nie przejmować się niczym
  • 81 to port, którego pod żadnym, ale kurwa żadnym pozorem nie należy eksponować, bo urwie ci to dupę przy samej ręce. Ten port ma być osiągalny wyłącznie lokalnie. Dlaczego? Śpieszę z odpowiedzią: to panel zarządzania NPM. Jak go wystawisz, to tak, jakbyś podsunął tyłek do glory hole w trakcie trwania tęczowego festiwalu kiełbasek i wyrobów wędliniarskich. Może się nic nie stanie, a może właśnie cała produkcja stanie. Nie i koniec. Pilnuj tego wjazdu jak Trump immunitetu, jak Kim granic, jak Stary passata.

Aplikację uruchamiamy standardowo:

docker compose up -d

I wchodzimy pod adres http://<IP>:81 (w tym przypadku http://192.168.10.18:81). Przechodzimy przez szybką konfigurację, konto, hasło, akceptuję, nie dam pieniążków bo jestem cebulą, dalej, tak, koniec.

Już prawie, prawie…

Router

Ustaw przekierowanie do tego hosta. Na zewnątrz wyeksponuj port 443/TCP, wewnątrz podepnij <IP>:443/TCP (w moim przypadku 192.168.10.18:443). To jedyne miejsce, gdzie odeślę cię do instrukcji urządzenia albo podpytania u operatora, bo routerów jest milion, panelów zarządzania jest milion, ale miłość jest jedna i jest nią Passat ❤️

Przy okazji podejrzyj swój adres IP na WAN i jeśli nie jest publiczny, kup sobie taki u operatora.

Ehh, może kiedyś…

Certyfikaty

Skup się teraz. Oprę się o Cloudflare, ale będzie to wyglądać wszędzie podobnie. W NPM wejdź Certificates a tam Add Certificate i via DNS.

Domain names: skup się bardziej. Wpisz najpierw swoją domenę bez żadnych przedrostków (tutaj: beremetal.pl) oraz po spacji użyj wildcarda, czyli gwiazdka kropka domena (tutaj: *.beremetal.pl). Pozwoli to na zarządzanie certyfikatem zarówno w obrębie podanej domeny, jak i jej subdomen.

DNS Provider: Cloudflare. Mówiłem, że się na nim opieram.

Credentials File Content: Skupienie razy sześć. Musisz w panelu zarządzania Cloudflare wygenerować Token, następnie go wkleić. Nikomu nigdy go nie podawaj, bo urwie ci rękę przy samym kolanie.

Skąd ten token zdobyć? Ukraść. Wygenerować w panelu Cloudflare. Prawy górny róg -> Profile -> po lewej API Tokens -> Create Token.

Łap ustawienia tokena:

Czy są to najlepsze ustawienia? Pewnie nie. Czy wystarczą? Pewnie tak. To lab, nie produkcja, uspokój się. Klikaj na dole Token Summary i zapisz token. Skopiuj go.

Wygenerowany token wklej w Credentials File Content w panelu konfiguracji certyfikatu, jak poniżej:

Kliknij Save i zrób sobie nową kawę. Serio, to chwilę czasami trwa. Wracaj z tą kawą!

Kto sieje wiatr…

Mamy certyfikat, ale nie mamy skonfigurowanego DNS u dostawcy (Cloudflare). W Cloudflare na stronie głównej Domains -> NazwaDomeny -> (po lewej) DNS -> Records

Przyjrzy się powyższemu screenshotowi. Potrzebujesz 2 rekordów:

  • A kierujący na Twój Publiczny Adres IP (mówiłem, zapisz sobie jak jesteś już na routerze…)
  • CNAME wskazujący na wszystkie subdomeny na domenę (będą się prawidłowo rozwiązywać), co powoduje właśnie gwiazdka *. Alternatywnie możesz dodawać kolejne subdomeny (jak na przykład app1, app2, nas, www, dupadupa…), osiągając konkretne adresy (jak na przykład app1.beremetal.pl, app2.beremetal.pl, nas.beremetal.pl, www.beremetal.pl, dupadupa.beremetal.pl)

Powyższe wpisy dadzą nam dwie rzeczy:

  • Ruch na naszą domenę będzie kierowany (rozwiązywany) z naszym adresem IP
  • Ruch dotyczący subdomen też trafi do nas

W obu przypadkach obsłuży go nasz reverse proxy, czyli Nginx Proxy Manager.

Zaklinanie, czyli wracamy do NPM

W NPM pakujemy się w Proxy Hosts i Add Proxy Host.

Spójrz na formularz, który właśnie przywołałeś:

Domain Names: wpisz tutaj poddomenę. Tutaj app1.beremetal.pl. To jest to, co podasz w przeglądarce.

Scheme: http. Dlaczego? Bo lokalnie wystawiasz to jako http. Gdybyś już lokalnie to wystawiał w https, wybrałbyś https. Teraz nie masz szyfrowania w sieci lokalnej, więc wybieraj http.

Forward Hostname/IP: 192.168.10.18. Ty jednak podaj adres IP serwera, na którym posadziłeś te dwa kontenery z Nginx i prostym hateemelem.

Port: w przypadku app1, to 8080.

Przejdź do zakładki SSL. W tym miejscu zaznacz wszystkie suwaczki i wybierz z listy swój wygenerowany certyfikat:

Save. Poczekaj chwilę, niech się w tle jeszcze DNS propagują.

Brawo, działa. Teraz zajmijmy się app2.beremetal.pl:

SSL jak wcześniej…

…i sprawdzamy:

No kurwa działa. Bo działać musi!

Podsumowanie

Co osiągnęliśmy? Mamy pełnego HTTPS wyeksponowanego na świat. Ruch na HTTP też przerabiamy na HTTPS. Mamy elastyczne zarządzanie certyfikatami, mamy także bardzo wygodne zarządzanie subdomenami. Mamy spełnione wszystkie interesujące nas założenia. Nie podstawiliśmy nigdzie tyłka do klapsa, zrobiliśmy wszystko zgodnie ze sztuką. Serwer NPM bierze na siebie ruch przychodzący i rozdziela go do odpowiednich hostów, co chwilę temu wykazaliśmy.

Możemy w ten sposób uruchamiać produkcyjnie reverse proxy i mieć jednocześnie świadomość, że jest to zrobione lepiej, niż 90% gównoserwisów na tej planecie. Serio, jeśli przez to przebrnąłeś, gratuluję, bo to kawał dobrej i solidnej roboty.

Źródła


0 komentarzy

Dodaj komentarz

Symbol zastępczy awatara

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *