Zaoszczędź 15% na wszystkich usługach hostingowych

Sprawdź swoje umiejętności i zdobądź Rabat na dowolny plan hostingowy

Użyj kodu: Skills Rozpocznij
Sekcja
Administracja Bezpieczeństwo

Jak zainstalować HAProxy z Docker Compose na Ubuntu VPS

Jedna usługa sieciowa na VPS jest łatwa do bezpośredniego udostępnienia — dopóki nie chcesz jednych czystych publicznych drzwi, swobody zamiany backendu później lub bezpieczniejszego sposobu na zatrzymanie wysyłania ruchu do czegoś, co jest zepsute. To jest punkt, w którym proxy przestaje być „czymś dla dużych zespołów infrastruktury” i zaczyna być praktyczne.

intro

HAProxy doskonale pasuje do tej roli. Pomyśl o tym jako o menedżerze ruchu siedzącym przed Twoją aplikacją: żądania trafiają najpierw do HAProxy, a HAProxy decyduje, dokąd powinny pójść dalej. Nie potrzebujesz dużego klastra, aby skorzystać z tego. Nawet na jednym VPS Ubuntu 24.04 daje ci czystszą granicę między internetem a usługą, którą faktycznie uruchamiasz.

Ten przewodnik utrzymuje pierwsze wdrożenie celowo ustrukturyzowane: jeden VPS Ubuntu 24.04, Docker Compose, jeden kontener HAProxy, jeden demo backend i dowód, że routing naprawdę działa.

Dlaczego HAProxy jest ważny, zanim go potrzebujesz

Wyobraź sobie mały VPS uruchamiający jedną aplikację, która działa dobrze dzisiaj. Odpowiada na porcie, strona się ładuje i wszystko wygląda dobrze. Problemy zaczynają się, gdy chcesz mieć stabilny publiczny punkt wejścia, możliwość zastąpienia backendu później bez zmiany publicznego adresu, lub warstwę frontową, która może przestać wysyłać ruch do usługi, która zawodzi. Bezpośrednie udostępnianie aplikacji zaczyna się wydawać niestabilne zaskakująco szybko.

whymatters

Te wymagania wszystkie wskazują na tę samą brakującą warstwę: kontrolowany punkt wejścia między internetem a twoją aplikacją. HAProxy zapewnia tę warstwę. Klienci łączą się z HAProxy jako pierwsi, a HAProxy decyduje, gdzie każde żądanie idzie dalej.

Ta separacja jest przydatna nawet zanim będziesz mieć wiele serwerów. Daje ci czystszą publiczną krawędź teraz i bezpieczniejszą ścieżkę do późniejszych zmian, takich jak zastąpienie backendu, routing świadomy zdrowia i HTTPS. Reszta przewodnika pokazuje ten wzorzec w jego najprostszej działającej formie i weryfikuje go rzeczywistą ścieżką żądania.

Szybkie terminy HAProxy, które ułatwiają zrozumienie reszty tego przewodnika

quick

Potrzebujesz tylko małego zestawu słownictwa, aby pewnie śledzić pierwsze wdrożenie HAProxy. Poniższa tabela obejmuje terminy, które mają znaczenie w tym przewodniku.

TerminZnaczenie w prostym języku
🌐 reverse proxyUsługa frontowa, która jako pierwsza odbiera żądania i przekazuje je innej usłudze wewnętrznej.
⚖️ load balancerWarstwa frontowa, która może rozprowadzać żądania na więcej niż jeden cel backend.
🚪 frontendMiejsce, w którym klienci łączą się z HAProxy.
🧩 backendUsługa lub serwer, do którego HAProxy wysyła żądanie dalej.
❤️ health checkSposób, w jaki HAProxy zauważa, czy backend powinien nadal otrzymywać ruch.
🐳 imageSpakowany szablon aplikacji używany do tworzenia kontenerów.
📦 containerUruchomiona instancja obrazu.

W tym przewodniku reverse proxy to pierwszy model mentalny, który warto mieć na uwadze. HAProxy siedzi przed czymś innym i kontroluje przekazanie. Load balancing to rozszerzona możliwość, która staje się przydatna, gdy później dodasz wiele serwerów backend.

Dwa terminy, które mają największe znaczenie po otwarciu konfiguracji, to frontend i backend. Frontend to miejsce, w którym pojawia się klient. Backend to miejsce, do którego HAProxy wysyła żądanie dalej. Health check ma znaczenie, ponieważ pozwala HAProxy zauważyć, kiedy cel powinien przestać otrzymywać ruch.

Do czego HAProxy się nadaje — i co ten przewodnik celowo pomija

whatgood

Jeśli wyobrażasz sobie swój stack jako budynek biurowy, HAProxy to recepcja: ruch przychodzi tam najpierw, zostaje skierowany do właściwego pokoju i przestaje być wysyłany do pokoju, który jest wyraźnie niedostępny.

W tym przewodniku przekłada się to na trzy zadania istotne dla początkujących:

  1. akceptowanie przychodzących żądań HTTP
  2. przekazywanie ich do backendu demo
  3. monitorowanie, czy backend jest wystarczająco zdrowy, aby nadal otrzymywać ruch

To jest już przydatne z jednym backendem, ponieważ daje ci jedną kontrolowaną publiczną krawędź przed aplikacją.

Później ten sam wzorzec skaluje się czysto. Możesz zastąpić backend, dodać więcej backendów, wprowadzić HTTPS, lub pozwolić HAProxy rozprowadzać ruch na wiele celów zamiast tylko jednego. Aby utrzymać pierwszy przebieg jako nauczalny, ten przewodnik pozostaje w trybie HTTP i celowo pomija terminację TLS, ACL, ograniczanie szybkości, tabele stick i pary HA. To wszystko to rzeczywiste tematy HAProxy. Po prostu nie są właściwym punktem wyjścia dla pierwszego działającego wdrożenia.

Co budujesz i co musisz najpierw przygotować

buildingsetup

Przed utworzeniem plików warto zobaczyć ostateczny kształt stosu. Wdrożenie w tym przewodniku wygląda następująco:

Client browser or curl
        |
        v
HAProxy frontend (:80)
        |
        v
demo backend service (demo:5678)

Optional local-only validation:
HAProxy stats frontend (127.0.0.1:8404/stats)

Docker Compose jest tutaj główną ścieżką, ponieważ utrzymuje pierwszą instalację powtarzalną, przejrzystą i łatwą do edycji. Zamiast budować niestandardowy obraz w pierwszym dniu, przechowujesz konfigurację HAProxy na hoście, montując ją w kontenerze i uruchamiając cały stos z jednego pliku. Na samodzielnie zarządzanym Ubuntu VPS — na przykład VPS AlexHost — to czysty dopasowanie, ponieważ układ pozostaje łatwy do sprawdzenia.

💡 Wskazówka: Ten przewodnik celowo używa Docker Compose plus bind-mounted haproxy.cfg. Jest to najbardziej przejrzysta ścieżka pierwszej instalacji, ponieważ możesz edytować konfigurację proxy bezpośrednio bez dodawania kroku budowania obrazu.

Przed rozpoczęciem upewnij się, że masz przygotowane te podstawy:

  • Ubuntu 24.04 VPS
  • Zainstalowany Docker Engine
  • Docker Compose v2 dostępny przez docker compose
  • Dostęp do terminala i uprawnienia do uruchamiania Docker
  • Port 80 dostępny na hoście
  • Ruch HTTP przychodzący dozwolony, jeśli używasz UFW lub reguł zapory po stronie dostawcy

Najpierw sprawdź wersję Ubuntu

lsb_release -a

ubuntu-version

Następnie potwierdź, że Docker i nowoczesny Compose są dostępne:

docker --version
docker compose version

docker-version

Jeśli oba polecenia zwracają informacje o wersji, strona środowiska uruchomieniowego kontenera jest gotowa i możesz skupić się na HAProxy zamiast robić objazd do instalacji Docker.

Następnie upewnij się, że port 80 nie jest już w użyciu, a następnie sprawdź, czy UFW jest aktywny i czy HTTP jest już dozwolony:

sudo ss -tlnp | grep -E ':(80)s' || true
sudo ufw status
sudo ufw allow 80/tcp

ufw-status

✏️ UWAGA: Brak danych wyjściowych ze sprawdzenia ss zwykle oznacza, że port 80 jest wolny. Jeśli widzisz nginx, apache2, caddy lub inną usługę już słuchającą tam, napraw to najpierw. To dziesięciosekundowy krok preflight, który oszczędza wiele zamieszania później.

W powyższym przykładzie sudo ufw status pokazuje Status: active, a 80/tcp jest już obecny na liście dozwolonych. Dlatego sudo ufw allow 80/tcp zwraca Skipping adding existing rule zamiast dodawania nowej reguły. To wyjście jest normalne i po prostu oznacza, że reguła zapory była już na miejscu.

Utwórz Folder Projektu i Plik Compose

Zacznij od utworzenia małego folderu projektu dla dwóch plików, które potrzebuje to pierwsze wdrożenie:

mkdir -p ~/haproxy-docker
cd ~/haproxy-docker

mkdir

Po tym układ powinien być jak najmniejszy:

~/haproxy-docker/
├── compose.yaml
└── haproxy.cfg

Teraz utwórz compose.yaml i użyj tej dokładnej zawartości:

services:
  demo:
    image: hashicorp/http-echo:1.0
    command: ["-listen=:5678", "-text=Hello from the HAProxy demo backend"]
    restart: unless-stopped

  haproxy:
    image: haproxy:3.4.1
    depends_on:
      - demo
    ports:
      - "80:80"
      - "127.0.0.1:8404:8404"
    volumes:
      - ./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro
    sysctls:
      net.ipv4.ip_unprivileged_port_start: "0"
    restart: unless-stopped

Ten plik łączy kontenery razem, ale nie definiuje jeszcze logiki żądań HAProxy. Mówi Dockerowi, które obrazy uruchomić, które porty opublikować i skąd będzie zainstalowana konfiguracja HAProxy na hoście.

Poniższe ustawienia to te, które mają największe znaczenie dla czystego pierwszego wdrożenia:

Ustawienie ComposeDlaczego jest tutaj
hashicorp/http-echo:1.0Daje ci mały, przewidywalny backend demo bez jednoczesnego nauczania drugiego serwera WWW.
haproxy:3.4.1Używa przypiętego stabilnego tagu zamiast latest, co sprawia, że przewodnik jest mniej kruchy w czasie.
depends_onUruchamia usługę demo przed HAProxy, co jest pomocne dla kolejności pierwszego uruchomienia.
80:80Publikuje główny listener HTTP na standardowym porcie WWW, którego oczekują czytelnicy.
127.0.0.1:8404:8404Utrzymuje stronę statystyk dostępną do lokalnej walidacji bez domyślnego publicznego udostępniania.
./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:roMontuje widoczny plik konfiguracji po stronie hosta do oficjalnego obrazu HAProxy jako tylko do odczytu.
sysctls z net.ipv4.ip_unprivileged_port_start: “0”Pozwala kontenerowi HAProxy bez uprawnień root wiązać się z portami niskiego poziomu, takimi jak 80.
restart: unless-stoppedDaje ci praktyczne domyślne ustawienie VPS: uruchom ponownie po awarii lub restarcie, ale respektuj celowe ręczne zatrzymanie.

Jeszcze jeden szczegół ma tutaj znaczenie: w tym pliku nie ma niestandardowej sieci Docker, ponieważ Docker Compose automatycznie tworzy sieć domyślną. To daje ci DNS nazwy usług wewnątrz projektu, dlatego HAProxy będzie w stanie osiągnąć backend jako demo:5678 bez dodatkowego okablowania.

⚠️ Ostrzeżenie: Port 80 to port uprzywilejowany, więc linia sysctls nie jest dekoracyjna. Zmiana mapowania hosta na 8080:80 nie usuwa wymagania portu uprzywilejowanego wewnątrz kontenera, jeśli HAProxy nadal wiąże się z :80 wewnętrznie.

Napisz i zweryfikuj minimalny plik haproxy.cfg

Mając już wdrożoną infrastrukturę kontenerów, HAProxy nadal potrzebuje instrukcji dotyczących tego, gdzie przychodzi ruch, gdzie powinien iść i jak sprawdzana jest kondycja backendu. Utwórz haproxy.cfg:

global
    log stdout format raw local0

defaults
    mode http
    timeout connect 5s
    timeout client 30s
    timeout server 30s

frontend http
    bind :80
    default_backend demo_backend

backend demo_backend
    balance roundrobin
    server demo1 demo:5678 check

frontend stats
    bind :8404
    stats enable
    stats refresh 10s
    stats uri /stats

To jest konfiguracja minimalna, ale nie jednorazowa. log stdout format raw local0 to przyjazny dla kontenerów wybór rejestrowania, ponieważ Docker może łatwo wyświetlić stdout, a mode http w defaults utrzymuje cały przykład w trybie HTTP, dzięki czemu zachowanie listenera i backendu pozostaje spójne i czytelne.

✏️ UWAGA: Jeden szczegół warto wyjaśnić przed omówieniem sekcji: balance roundrobin jest ustawiony jawnie, ponieważ nowsze wersje HAProxy zmieniły domyślny algorytm backendu na random, a roundrobin jest łatwiejszy do nauczenia w przewidywalny sposób na pierwszym etapie.

Oto przejrzysty opis każdej sekcji:

SekcjaKluczowe linieCo robi
globallog stdout format raw local0Wysyła logi do stdout, aby rejestrowanie Docker pozostało proste.
defaultsmode http, timeoutyUstanawia bazowe zachowanie HTTP i rozsądne wartości timeoutów.
frontend httpbind :80, default_backend demo_backendTworzy publiczny listener i łączy go z definicją backendu.
backend demo_backendbalance roundrobin, server demo1 demo:5678 checkMówi HAProxy, którą usługę użyć i monitorować jej kondycję.
frontend statsbind :8404, stats enable, stats uri /statsDodaje opcjonalną lokalną stronę walidacji, aby później zobaczyć status runtime.

Możesz zauważyć jedną brakującą rzecz: option forwardfor. To pominięcie jest celowe na tym etapie. Zachowanie oryginalnego adresu IP klienta jest przydatne później, ale to pierwsze wdrożenie dotyczy udowodnienia routingu i kondycji backendu, a nie nauczania zachowania nagłówków za pomocą kontenera demo, który nie czyni tego sygnału szczególnie wartościowym.

💡 Wskazówka: Zawsze zweryfikuj konfigurację HAProxy przed uruchomieniem pełnego stosu. Ponieważ ta konfiguracja odnosi się do backendu po nazwie usługi Compose (demo), uruchom najpierw ten backend, aby HAProxy mógł go rozwiązać podczas walidacji.

Uruchom walidację z tego samego katalogu projektu:

docker compose up -d demo
docker compose run --rm --no-deps haproxy haproxy -V -c -f /usr/local/etc/haproxy/haproxy.cfg

success

Jeśli drugie polecenie kończy się komunikatem Configuration file is valid, już udowodniłeś, że HAProxy może poprawnie przeanalizować plik i rozwiązać cel backendu, zanim uruchomi się jakikolwiek aktywny listener.

Uruchom Stack i Udowodnij, że Proxy Działa

Po walidacji konfiguracji uruchom stack w trybie detached:

Ponieważ krok walidacji już uruchomił demo, ta komenda głównie uruchamia HAProxy i uzgadnia pełny stack dwóch usług:

docker compose up -d

start-cmpose

Następnie sprawdź, czy oba kontenery są uruchomione:

docker compose ps

compose-status

Ten widok procesów to tylko pierwszy punkt kontrolny. Potwierdza, że Docker uruchomił kontenery, ale nie potwierdza jeszcze, że HAProxy pomyślnie kieruje ruch do backendu. Następne żądanie weryfikuje rzeczywistą ścieżkę danych.

Teraz uruchom rzeczywisty test routingu z samego VPS:

curl -i http://127.0.0.1

valid

Sygnałem sukcesu jest HTTP/1.1 200 OK plus treść odpowiedzi zawierająca Hello from the HAProxy demo backend. Niektóre buildy http-echo zawijają ten tekst w małą odpowiedź HTML, więc skoncentruj się na frazie w treści bardziej niż na dokładnym formatowaniu.

Jeśli chcesz dowodu na poziomie przeglądarki, otwórz http://YOUR_SERVER_IP z innej maszyny.

browser-valid

Aby uzyskać drugą powierzchnię walidacji, sprawdź stronę statystyk tylko dla lokalnego dostępu z VPS:

curl http://127.0.0.1:8404/stats

Na stronie statystyk najprzydatniejszymi sygnałami są frontend o nazwie http, backend o nazwie demo_backend, wiersz serwera o nazwie demo1, status pokazany jako UP i zwykle wartość ostatniej kontroli taka jak L4OK in 0ms. Pamiętaj też o jednej małej osobliwości Dockera: krótka składnia depends_on kontroluje kolejność uruchamiania, ale nie czeka na to, aż usługa stanie się zdrowa. Jeśli bardzo pierwsze curl raz się nie powiedzie zaraz po uruchomieniu, czekaj kilka sekund i spróbuj ponownie, zanim założysz, że konfiguracja jest błędna.

Różnicę między stanem procesu a rzeczywistym sukcesem łatwiej jest przedstawić w formie tabeli:

StanCo ci to mówi
Kontenery są uruchomioneDocker uruchomił procesy.
curl -i http://127.0.0.1 zwraca 200 OK i frazę demoHAProxy rzeczywiście kieruje ruch do backendu.
Strona statystyk pokazuje demo1 jako UPHAProxy widzi backend jako zdrowy.

Typowe błędy przy pierwszym uruchomieniu i szybkie rozwiązania

mistakes

Jeśli konfiguracja nie działa od razu, oprzij się pokusie przepisania obu plików naraz. Większość błędów przy pierwszym uruchomieniu na tym stosie jest przewidywalna i znacznie łatwiej się je naprawia, gdy zmienia się jedną zmienną na raz.

Użyj tej matrycy jako szybkiej warstwy diagnostycznej:

  • HAProxy zamyka się natychmiast

    Prawdopodobna przyczyna: haproxy.cfg nie istnieje.

    Szybkie rozwiązanie: Upewnij się, że haproxy.cfg znajduje się obok compose.yaml.

    Dlaczego się to dzieje: Oficjalny obraz nie zawiera gotowego do użytku pliku konfiguracyjnego.


  • Błąd mówi, że nie można otworzyć /usr/local/etc/haproxy/haproxy.cfg

    Prawdopodobna przyczyna: Zła ścieżka bind-mount.

    Szybkie rozwiązanie: Zweryfikuj ./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro dokładnie.

    Dlaczego się to dzieje: HAProxy nie może się uruchomić bez ważnego pliku konfiguracyjnego.


  • Błąd mówi Permission denied na porcie 80

    Prawdopodobna przyczyna: Problem z wiązaniem portu uprzywilejowanego.

    Szybkie rozwiązanie: Zachowaj net.ipv4.ip_unprivileged_port_start: “0” w Compose, lub przenieś zarówno HAProxy jak i opublikowany port na 8080.

    Dlaczego się to dzieje: Kontener działa jako użytkownik niebędący rootem haproxy.


  • Zmieniłeś mapowanie na 8080:80 i nadal otrzymujesz błąd wiązania

    Prawdopodobna przyczyna: HAProxy nadal wiąże się z :80 wewnątrz kontenera.

    Szybkie rozwiązanie: Zmień zarówno mapowanie hosta jak i wewnętrzną linię bind, jeśli odchodzisz od portu 80.

    Dlaczego się to dzieje: Reguła portu uprzywilejowanego dotyczy również wnętrza kontenera.


  • Port 80 jest już w użyciu

    Prawdopodobna przyczyna: Inny serwis zajmuje port hosta.

    Szybkie rozwiązanie: Ponownie uruchom sprawdzenie ss i zatrzymaj lub przenieś konfliktujący serwis.

    Dlaczego się to dzieje: Tylko jeden proces może nasłuchiwać na tym samym porcie hosta.


  • Sprawdzenie składni zgłasza unknown keyword lub błędy specyficzne dla linii

    Prawdopodobna przyczyna: Błąd w konfiguracji HAProxy.

    Szybkie rozwiązanie: Ponownie uruchom sprawdzenie składni i napraw dokładną linię, którą zgłasza.

    Dlaczego się to dzieje: Parser HAProxy jest surowy, co jest pomocne, gdy używasz go celowo.


  • Kontenery działają, ale curl nie zwraca odpowiedzi demo

    Prawdopodobna przyczyna: Zła ścieżka routingu.

    Szybkie rozwiązanie: Ponownie sprawdź default_backend demo_backend, server demo1 demo:5678 check i nazwę serwisu demo.

    Dlaczego się to dzieje: Działający kontener nie jest dowodem prawidłowej ścieżki od frontendu do backendu.


  • Lokalny curl działa, ale witryna jest niedostępna z zewnątrz

    Prawdopodobna przyczyna: Zapora sieciowa lub reguła bezpieczeństwa dostawcy.

    Szybkie rozwiązanie: Otwórz port 80 w UFW i w dowolnej zaporze po stronie dostawcy.

    Dlaczego się to dzieje: Publikowanie lokalne może działać nawet wtedy, gdy dostęp publiczny jest nadal zablokowany.

⚠️ Ostrzeżenie: Zmień jedną rzecz na raz. Jeśli edytujesz zarówno compose.yaml jak i haproxy.cfg na ślepo, znacznie trudniej jest stwierdzić, czy błąd to problem ścieżki pliku, problem portu czy problem routingu.

Gdy potrzebujesz szybkich dowodów, trzymaj te polecenia w pobliżu:

docker compose logs haproxy
docker compose ps
docker compose up -d demo
docker compose run --rm --no-deps haproxy haproxy -V -c -f /usr/local/etc/haproxy/haproxy.cfg
sudo ss -tlnp | grep -E ':(80|8404)s' || true

To są trzy wzorce alertów, które warto rozpoznać na pierwszy rzut oka:

[ALERT] ... Cannot open configuration file /usr/local/etc/haproxy/haproxy.cfg : No such file or directory
[ALERT] ... Starting frontend http: cannot bind socket (Permission denied) [0.0.0.0:80]
[ALERT] ... parsing [/usr/local/etc/haproxy/haproxy.cfg:12] : unknown keyword 'chekc'; did you mean 'check' maybe?

To jest uspokajająca część małego pierwszego wdrożenia: kształty błędów są zwykle również małe. Nie musisz zaczynać od nowa. Musisz zidentyfikować, która warstwa narzeka i najpierw poprawić tę jedną rzecz.

Dokąd Iść Po Instalacji

Gdy demo z jednym backendem działa, architektura jest już użyteczna. Następnym rzeczywistym krokiem jest zastąpienie kontenera demo Twoją rzeczywistą aplikacją, zachowując tę samą strukturę HAProxy. Następnie dodaj HTTPS/TLS jako dedykowany kolejny krok i traktuj routing oparty na domenach oraz ACL jako oddzielne tematy zamiast pośpiesznie wrzucać je do tej pierwszej instalacji.

end

Gdy będziesz gotów na więcej niż jeden backend, ten sam wzorzec staje się wyraźnie znaczący:

backend app_backend
    balance roundrobin
    server app1 app1:8080 check
    server app2 app2:8080 check

Aby bezpiecznie edytować konfigurację z bind-mountem, najpierw zwaliduj, a następnie gracefully przeładuj HAProxy:

docker compose up -d demo
docker compose run --rm --no-deps haproxy haproxy -V -c -f /usr/local/etc/haproxy/haproxy.cfg
docker compose kill -s HUP haproxy

📝 Uwaga: Strona statystyk jest celowo dostępna tylko lokalnie w tym przewodniku. Jeśli kiedykolwiek ją udostępnisz publicznie, najpierw dodaj uwierzytelnianie i kontrolę dostępu.

To sprowadza Cię z powrotem do pierwotnego problemu: chciałeś jedne czyste drzwi wejściowe przed usługą, bez zamieniania pierwszej konfiguracji w pełny projekt operacyjny. Masz teraz tę działającą ścieżkę. Co ważniejsze, masz też właściwy model myślowy: HAProxy odbiera ruch jako pierwszy, przekazuje go tam, gdzie powinien, i daje Ci czystszy sposób na rozwijanie stosu na samodzielnie zarządzanym VPS bez utraty kontroli nad konfiguracją.