Najpierw był jeden blog. Potem doszedł n8n. Potem jakiś Uptime Kuma, bo czemu nie. I nagle masz na jednym serwerze pięć aplikacji, każdą na innym porcie, a chciałbyś, żeby każda odpowiadała pod własną, ładną domeną.

Można to oczywiście wyrzeźbić ręcznie w konfiguracji nginx. Da się. Tylko że przy piątym pliku server {} i trzecim certyfikacie do odnowienia entuzjazm zwykle opada.

Nginx Proxy Manager załatwia to z poziomu przeglądarki. Wskazujesz, która domena ma prowadzić do której aplikacji, a on sam wyrabia certyfikaty SSL w Let’s Encrypt i sam pilnuje, żeby się nie przeterminowały.

Na Mikrusie#

Nginx Proxy Manager chodzi w Dockerze, a Dockera postawisz gotowym skryptem z NOOBS-a:

curl -s https://noobs.mikr.us | bash
sudo /opt/noobs/scripts/chce_dockera.sh

Możesz teraz skoczyć do sekcji Pierwsze uruchomienie. Dalej nie ma znaczenia, skąd masz Dockera.

Na dowolnym serwerze (Ubuntu/Debian)#

Tu Dockera instalujemy ręcznie, z oficjalnego repozytorium:

sudo apt update
sudo apt install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/$(. /etc/os-release && echo "$ID")/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/$(. /etc/os-release && echo "$ID") \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Pierwsze uruchomienie#

Katalog na konfigurację, od razu z wejściem do środka:

mkdir -p ~/nginxproxymanager && cd ~/nginxproxymanager
nano docker-compose.yml

Wklejasz:

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

I odpalasz:

docker compose up -d

Logowanie do panelu#

Tu robi się ciekawie. Panel siedzi na porcie 81, a tego portu wśród standardowo przydzielonych na Mikrusie (10000+ID, 20000+ID, 30000+ID) po prostu nie ma.

Dokupować portu nie trzeba. Wystarczy przypomnieć sobie, że cały adres IPv6 jest Twój, a my dajemy do tego darmową subdomenę pod dowolny port, w formacie serwer-port.mikrus.cloud. Bez klikania czegokolwiek w panelu. Swój adres wygenerujesz tak:

echo https://$(hostname)-81.mikrus.cloud

Wchodzisz pod wyświetlony adres i widzisz ekran pierwszego logowania. Imię, e-mail, nowe hasło administratora. Gotowe.

Czemu to w ogóle działa? Bo Docker domyślnie publikuje porty zarówno na IPv4, jak i na IPv6 hosta. W docker-compose.yml nie trzeba w tym celu niczego dopisywać.

Dodanie nowej strony#

W panelu: Hosts → Proxy Hosts → Add Proxy Host.

W polu domeny wpisujesz adres, pod którym ma być widoczna strona. Może być ich kilka. Tylko uwaga, bo to pole jest trochę podstępne: każdą domenę trzeba zatwierdzić Enterem albo Tabem. Samo wpisanie tekstu nie wystarczy i pole zostanie puste.

Schemat (HTTP/HTTPS) w formularzu bywa mylący. Dotyczy on tego, jak Nginx Proxy Manager rozmawia z Twoją aplikacją za kulisami, a nie tego, co widzi odwiedzający. Zazwyczaj wybierasz tu HTTP, nawet jeśli ludzie będą wchodzić po HTTPS. Szyfrowanie od strony świata NPM i tak weźmie na siebie.

Jako adres docelowy (Forward Hostname/IP) nie wpisuj localhost ani 127.0.0.1. Z wnętrza kontenera localhost to sam kontener, więc ani innych kontenerów, ani aplikacji na hoście w ten sposób nie zobaczysz. Wpisz wewnętrzny adres IPv4 swojego VPS-a (dla serwera o ID 123 to 192.168.1.123) albo nazwę innego kontenera, jeśli oba siedzą w tej samej sieci compose.

Na koniec zostaje podpięcie domeny, żeby wskazywała na Twój serwer. I tyle. Ruch pod tą domeną trafia do wybranej aplikacji.

Najczęstsze błędy#

Pole domeny puste, choć przecież coś wpisałeś. Brakło Entera albo Taba po wpisaniu adresu. Każdą wartość trzeba zatwierdzić.

localhost/127.0.0.1 jako adres docelowy. Z perspektywy kontenera to zawsze on sam, a nie Twoja aplikacja. Wewnętrzny adres IPv4 VPS-a albo nazwa kontenera - inaczej się nie da.

Strona działa, ale SSL już nie. Zanim zawalczysz o certyfikat w zakładce SSL, upewnij się, że DNS domeny faktycznie wskazuje na Twój serwer. Bez tego Let’s Encrypt nie uwierzy, że domena należy do Ciebie.

P.S. Na Mikrusie podobną robotę (reverse proxy z automatycznym SSL) odwala też wbudowany w panel Cytrus. Jeśli pełna elastyczność Nginx Proxy Managera nie jest Ci potrzebna, może się okazać, że to wszystko, czego szukałeś.