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 internetowa 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 uszkodzone. To jest moment, 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 z tego korzystać. 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 ma znaczenie, zanim go potrzebujesz

Wyobraź sobie mały VPS uruchamiający jedną aplikację, która działa doskonale 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 się nie powiedzie. Bezpośrednie udostępnianie aplikacji zaczyna się wydawać zaskakująco szybko kruche.

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 w pierwszej kolejności, a HAProxy decyduje, gdzie każde żądanie trafia 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 front-endowa, która najpierw odbiera żądania i przekazuje je do innej usługi wewnętrznej.
⚖️ load balancerWarstwa frontowa, która może rozprowadzać żądania na więcej niż jeden cel backend.
🚪 frontendMiejsce, gdzie 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 jest pierwszym modelem mentalnym, który należy 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, gdzie pojawia się klient. Backend to miejsce, gdzie HAProxy wysyła żądanie dalej. Health check ma znaczenie, ponieważ pozwala HAProxy zauważyć, kiedy cel powinien przestać otrzymywać ruch.

W czym HAProxy się wyróżnia — i co ten przewodnik celowo pomija

whatgood

Jeśli wyobrażasz sobie swój stos 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ę czyszczenie. 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 w nauczalnym stanie, ten przewodnik pozostaje w trybie HTTP i celowo pomija terminację TLS, ACL, ograniczanie szybkości, tabele stick i pary HA. To wszystko są 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, montujesz ją w kontenerze i uruchamiasz cały stos z jednego pliku. Na samodzielnie zarządzanym Ubuntu VPS — na przykład AlexHost VPS — to czysty pasuje, 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
  • 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 odbiegać 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ż nasłuchują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 dodawać nową regułę. Te dane wyjściowe są normalne i po prostu oznaczają, ż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

Następnie 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 Docker’owi, które obrazy uruchomić, które porty opublikować i skąd zainstalować konfigurację HAProxy z hosta.

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 ujawniania.
./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 działającemu 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 szanuj 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 jest portem uprzywilejowanym, 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

Po skonfigurowaniu kontenera HAProxy nadal potrzebuje instrukcji dotyczących miejsca przybycia ruchu, dokąd powinien trafić 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 minimalna konfiguracja, ale nie jednorazowa. log stdout format raw local0 to przyjazny dla kontenerów wybór logowania, 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 podziałem 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 przy pierwszym przejściu.

Oto przejrzysty opis każdej sekcji:

SekcjaKluczowe linieCo robi
globallog stdout format raw local0Wysyła logi do stdout, aby logowanie Docker pozostało proste.
defaultsmode http, timeoutyUstanawia bazowe zachowanie HTTP i rozsądne wartości timeout.
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órej usługi 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 w ścieżce bazowej. Zachowanie oryginalnego IP klienta jest przydatne później, ale to pierwsze wdrożenie dotyczy udowodnienia routingu i kondycji backendu, a nie nauczania zachowania nagłówka 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 druga komenda kończy się komunikatem Configuration file is valid, już udowodniłeś, że HAProxy może poprawnie przeanalizować plik i rozwiązać cel backendu przed uruchomieniem jakiegokolwiek aktywnego listenera.

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ą aktywne:

docker compose ps

compose-status

Ten widok procesów to tylko pierwszy punkt kontrolny. Potwierdza, że Docker uruchomił kontenery, ale nie to, ż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 kompilacje http-echo owijają ten tekst w małą odpowiedź HTML, więc skup 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

Dla drugiej powierzchni walidacji sprawdź stronę statystyk tylko lokalnie z VPS:

curl http://127.0.0.1:8404/stats

Na stronie statystyk najbardziej przydatne sygnały to frontend nazwany http, backend nazwany demo_backend, wiersz serwera nazwany 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 śledzić 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 naprawy

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 zmieniasz jedną zmienną naraz.

Użyj tej matrycy jako szybkiej warstwy diagnostycznej:

  • HAProxy kończy pracę natychmiast

    Prawdopodobna przyczyna: Brakuje pliku haproxy.cfg.

    Szybka naprawa: Upewnij się, że plik haproxy.cfg znajduje się obok compose.yaml.

    Dlaczego się to dzieje: Oficjalny obraz nie zawiera gotowego do użycia 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.

    Szybka naprawa: Sprawdź dokładnie ./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro.

    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.

    Szybka naprawa: 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 inny niż root haproxy.


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

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

    Szybka naprawa: 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.

    Szybka naprawa: 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: Literówka w konfiguracji HAProxy.

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

    Dlaczego się to dzieje: Parser HAProxy jest rygorystyczny, co jest pomocne, gdy używasz go świadomie.


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

    Prawdopodobna przyczyna: Ścieżka routingu jest zła.

    Szybka naprawa: 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 na prawidłową ścieżkę od frontendu do backendu.


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

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

    Szybka naprawa: Otwórz port 80 w UFW i w dowolnej zaporze sieciowej po stronie dostawcy.

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

⚠️ Ostrzeżenie: Zmieniaj jedną rzecz naraz. Jeśli na ślepo edytujesz zarówno compose.yaml, jak i haproxy.cfg, znacznie trudniej będzie ustalić, czy błąd to problem ze ścieżką pliku, problem z portem czy problem z routingiem.

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.

Gdzie 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 osobne tematy zamiast pospiesznie wrzucać je do tej pierwszej instalacji.

end

Gdy będziesz gotowy 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ę zamontowaną bind-mount, 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ą publicznie udostępnisz, najpierw dodaj uwierzytelnianie i kontrolę dostępu.

To sprowadza Cię z powrotem do oryginalnego problemu: chciałeś jedne czyste drzwi wejściowe przed usługą, bez zamieniania pierwszej konfiguracji w pełny projekt operacyjny. Teraz masz 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ą.