Как да инсталирате HAProxy с Docker Compose на Ubuntu VPS
One web service on a VPS is easy to expose directly — until you want one clean public front door, the freedom to swap the backend later, or a safer way to stop sending traffic to something broken. That is the point where a proxy stops feeling like “something for big infrastructure teams” and starts feeling practical.

HAProxy fits that role well. Think of it as the traffic manager sitting in front of your application: requests hit HAProxy first, and HAProxy decides where they should go next. You do not need a large cluster to benefit from that. Even on one Ubuntu 24.04 VPS, it gives you a cleaner edge between the internet and the service you are actually running.
This guide keeps the first deployment intentionally structured: one Ubuntu 24.04 VPS, Docker Compose, one HAProxy container, one demo backend, and proof that routing really works.
Защо HAProxy е важен преди да го имаш нужда
Представи си малък VPS, който управлява едно приложение перфектно днес. То отговаря на порт, сайтът се зарежда и всичко изглежда добре. Проблемите започват, когато искаш стабилна публична входна точка, възможност да замениш бекенда по-късно без да променяш публичния адрес, или преден слой, който може да спре да изпраща трафик към отказващ се сервис. Излагането на приложението директно начина да се чувства крехко изненадващо бързо.

Всички тези изисквания сочат към един и същ липсващ слой: контролирана входна точка между интернета и твоето приложение. HAProxy предоставя този слой. Клиентите се свързват първо с HAProxy, и HAProxy решава къде да отиде всяко искане по-нататък.
Това разделение е полезно дори преди да имаш множество сървъри. Дава ти по-чист публичен край сега и по-безопасен път към по-късни промени, като замяна на бекенда, маршрутизиране, осведомено за здравето, и HTTPS. Останалата част на ръководството показва този модел в най-простата му работеща форма и го проверява с реален път на искане.
Бързи HAProxy термини, които улесняват останалата част на това ръководство

Имате нужда само от малък набор от словар, за да следвате първото внедряване на HAProxy с увереност. Таблицата по-долу обхваща термините, които имат значение в това ръководство.
| Термин | Значение на обикновен английски |
|---|---|
| 🌐 reverse proxy | Услуга, обърната към клиентите, която получава заявки първа и ги предава на друга вътрешна услуга. |
| ⚖️ load balancer | Преден слой, който може да разпредели заявките между повече от един backend целеви ресурс. |
| 🚪 frontend | Местото, където клиентите се свързват към HAProxy. |
| 🧩 backend | Услугата или сървърът, към който HAProxy изпраща заявката по-нататък. |
| ❤️ health check | Начин за HAProxy да забележи дали един backend трябва да продължи да получава трафик. |
| 🐳 image | Пакетиран шаблон на приложение, използван за създаване на контейнери. |
| 📦 container | Работещ екземпляр на един image. |
За това ръководство, reverse proxy е първият мисловен модел, който трябва да имате предвид. HAProxy седи пред нещо друго и контролира предаването. Load balancing е разширената възможност, която става полезна, когато по-късно добавите няколко backend сървъра.
Двата термина, които имат най-голямо значение, когато отворите конфигурацията, са frontend и backend. Frontend е местото, където пристига клиентът. Backend е местото, където HAProxy изпраща заявката по-нататък. Health check е важен, защото позволява на HAProxy да забележи, когато един целеви ресурс трябва да спре да получава трафик.
За какво е добър HAProxy — и какво това ръководство намерено пропуска

Ако си представите вашия стек като офис сграда, HAProxy е приемната: трафикът пристига там първо, се насочва към правилното помещение и спира да се изпраща към помещение, което явно е недостъпно.
В това ръководство това се превежда в три работи, релевантни за начинаещи:
- приемане на входящи HTTP заявки
- препращане им към демо бекенда
- мониторинг дали този бекенд е достатъчно здрав, за да продължи да получава трафик
Това е вече полезно с един бекенд, защото ви дава един контролиран публичен край пред приложението.
По-късно същият модел се мащабира чисто. Можете да замените бекенда, да добавите повече бекенди, да въведете HTTPS, или да оставите HAProxy да разпредели трафика между множество цели вместо само един. За да запази първия проход преподаваем, това ръководство остава в HTTP режим и намерено пропуска TLS терминиране, ACLs, ограничаване на скоростта, stick таблици и HA двойки. Всички те са реални HAProxy теми. Те просто не са правилната начална точка за първо работещо развертаване.
Какво строите и какво ви трябва първо

Преди да създавате файлове, помага да видите крайната форма на стека. Разгръщането в това ръководство изглежда така:
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 е основният път тук, защото поддържа първоначалната инсталация възпроизводима, видима и лесна за редактиране. Вместо да строите персонализиран образ в първия ден, запазвате конфигурацията на HAProxy на хоста, я монтирате в контейнера и стартирате целия стек от един файл. На самоуправляван Ubuntu VPS — например AlexHost VPS — това е чист подход, защото оформлението остава лесно за проверка.
💡 Съвет: Това ръководство използва Docker Compose плюс bind-mounted haproxy.cfg с цел. Това е най-прозрачният път за първоначална инсталация, защото можете да редактирате конфигурацията на прокси директно без да добавяте стъпка за изграждане на образ.
Преди да начнете, убедете се, че имате следните основи:
- Ubuntu 24.04 VPS
- Docker Engine инсталиран
- Docker Compose v2 достъпен чрез docker compose
- Достъп до терминал и разрешение за стартиране на Docker
- Порт 80 достъпен на хоста
- Входящ HTTP разрешен, ако използвате UFW или правила на фаерволът от страната на доставчика
Първо, проверете вашата версия на Ubuntu
lsb_release -a
След това, потвърдете, че Docker и модерният Compose са достъпни:
docker --version
docker compose version
Ако и двете команди върнат информация за версията, страната на контейнерния runtime е готова и можете да останете сфокусирани на HAProxy вместо да се отклоните в инсталация на Docker.
След това, убедете се, че порт 80 не е вече в употреба, след това проверете дали UFW е активен и дали HTTP вече е разрешен:
sudo ss -tlnp | grep -E ':(80)s' || true
sudo ufw status
sudo ufw allow 80/tcp
✏️ ЗАБЕЛЕЖКА: Без изход от проверката ss обикновено означава, че порт 80 е свободен. Ако видите nginx, apache2, caddy или друга услуга вече слушаща там, първо поправете това. Това е десетсекундна предварителна проверка, която спестява много объркване по-късно.
В примера по-горе, sudo ufw status показва Status: active, и 80/tcp вече присъства в списъка на разрешенията. Затова sudo ufw allow 80/tcp връща Skipping adding existing rule вместо да добави ново. Този изход е нормален и просто означава, че правилото на фаерволът вече беше на място.
Създайте папката на проекта и Compose файла
Начнете с създаването на малка папка на проекта за двата файла, които е необходимо първото разгръщане:
mkdir -p ~/haproxy-docker
cd ~/haproxy-docker
След това оформлението трябва да бъде възможно най-малко:
~/haproxy-docker/
├── compose.yaml
└── haproxy.cfgСега създайте compose.yaml и използвайте точно това съдържание:
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Този файл свързва контейнерите заедно, но все още не определя логиката на HAProxy заявките. Той казва на Docker кои образи да стартира, кои портове да публикува и откъде ще бъде монтирана конфигурацията на HAProxy на хоста.
Следните настройки са най-важни за чисто първо разгръщане:
| Настройка на Compose | Защо е тук |
|---|---|
| hashicorp/http-echo:1.0 | Дава ви малък, предсказуем демо бекенд без да преподавате втори уеб сървър в същото време. |
| haproxy:3.4.1 | Използва фиксиран стабилен таг вместо latest, което поддържа ръководството по-стабилно във времето. |
| depends_on | Стартира услугата demo преди HAProxy, което е полезно за реда при първо стартиране. |
| 80:80 | Публикува основния HTTP слушател на стандартния уеб порт, който читателите очакват. |
| 127.0.0.1:8404:8404 | Поддържа страницата със статистика достъпна за локална валидация без да я излагате публично по подразбиране. |
| ./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro | Монтира видимия конфигурационен файл на хоста в официалния образ на HAProxy като само за четене. |
| sysctls с net.ipv4.ip_unprivileged_port_start: “0” | Позволява на контейнера на HAProxy без root права да се свързва към нископоставени портове като 80. |
| restart: unless-stopped | Дава ви практичен VPS подразбиране: рестартирайте след отказ или рестартиране, но уважавайте намерено ръчно спиране. |
Още един детайл е важен тук: няма персонализирана Docker мрежа в този файл, защото Docker Compose създава мрежа по подразбиране автоматично. Това ви дава DNS с име на услугата вътре в проекта, което е причината HAProxy да може да достигне бекенда като demo:5678 без допълнително свързване.
⚠️ Внимание: Портът 80 е привилегирован порт, така че редът sysctls не е декоративен. Промяната на картографирането на хоста на 8080:80 не премахва изискването за привилегирован порт вътре в контейнера, ако HAProxy все още се свързва към :80 вътрешно.
Напишете и валидирайте минимален haproxy.cfg
С контейнерното свързване на място, HAProxy все още се нуждае от инструкции за това, където пристига трафикът, където трябва да отиде и как се проверява здравето на backend. Създайте 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Това е минимална конфигурация, но не е еднократна. log stdout format raw local0 е избора, приятелски настроен към контейнери, тъй като Docker може лесно да повърши stdout, и mode http в defaults поддържа целия пример в HTTP режим, така че поведението на слушателя и backend остават последователни и четливи.
✏️ ЗАБЕЛЕЖКА: Един детайл е достоен да бъде отбелязан преди разбора на раздела: balance roundrobin е зададен изрично, тъй като по-новите версии на HAProxy промениха алгоритъма на backend по подразбиране на random, и roundrobin е по-лесно да се преподава предсказуемо при първи проход.
Ето разбора на всеки раздел на обикновен английски:
| Раздел | Ключови редове | Какво прави |
|---|---|---|
| global | log stdout format raw local0 | Изпраща логове към stdout, така че логването на Docker остава просто. |
| defaults | mode http, timeouts | Установява базово HTTP поведение и разумни стойности на timeout. |
| frontend http | bind :80, default_backend demo_backend | Създава публичния слушател и го свързва с дефиницията на backend. |
| backend demo_backend | balance roundrobin, server demo1 demo:5678 check | Казва на HAProxy кой сервис да използва и да следи здравето му. |
| frontend stats | bind :8404, stats enable, stats uri /stats | Добавя опционална локална страница за валидация, така че можете да видите статуса по време на изпълнение по-късно. |
Може да забележите едно нещо, което липсва: option forwardfor. Това пропускане е намерено в базовия път. Запазването на оригиналния IP адрес на клиента е полезно по-късно, но това първо развертане е за доказване на маршрутизиране и здравето на backend, не за преподаване на поведението на заглавката с демо контейнер, който не прави този сигнал особено ценен.
💡 Съвет: Винаги валидирайте конфигурацията на HAProxy преди да стартирате пълния стек. Тъй като тази конфигурация се отнася към backend по неговото име на услугата на Compose (demo), стартирайте този backend първо, така че HAProxy да може да го разреши по време на валидация.
Изпълнете валидацията от същата директория на проекта:
docker compose up -d demo
docker compose run --rm --no-deps haproxy haproxy -V -c -f /usr/local/etc/haproxy/haproxy.cfg
Ако втората команда завършва с Configuration file is valid, вече сте доказали, че HAProxy може да парсира файла правилно и да разреши целта на backend преди всеки живо слушател да стартира.
Стартирайте Stack-а и докажете, че Proxy работи
След като конфигурацията е валидна, стартирайте stack-а в detached режим:
Тъй като стъпката за валидация вече стартира demo, тази команда главно пуска HAProxy и синхронизира пълния two-service stack:
docker compose up -d
След това проверете дали и двата контейнера са активни:
docker compose ps
Този преглед на процесите е само първата контролна точка. Той потвърждава, че Docker стартира контейнерите, но не и че HAProxy успешно маршрутизира трафика към backend-а. Следващото заявление проверява действителния път на данните.
Сега изпълнете действителния тест за маршрутизиране от самия VPS:
curl -i http://127.0.0.1
Сигналът за успех е HTTP/1.1 200 OK плюс тялото на отговора, съдържащо Hello from the HAProxy demo backend. Някои http-echo версии обвиват този текст в малък HTML отговор, така че се фокусирайте на фразата в тялото повече, отколкото на точното форматиране.
Ако искате доказателство на ниво браузър, отворете http://YOUR_SERVER_IP от друга машина.

За втора повърхност за валидация, проверете страницата със статистика, която е само локална, от VPS:
curl http://127.0.0.1:8404/statsНа страницата със статистика, най-полезните сигнали са frontend с име http, backend с име demo_backend, ред на сървър с име demo1, статус показан като UP, и обикновено последна проверка със стойност като L4OK in 0ms. Също така имайте предвид една малка Docker особеност: синтаксис depends_on контролира реда на стартиране, но не чака сервис да стане здравословен. Ако първото curl веднъж се провали веднага след стартиране, изчакайте няколко секунди и опитайте отново, преди да предположите, че конфигурацията е грешна.
Разликата между състояние на процес и реален успех е по-лесна за разбиране в таблична форма:
| Състояние | Какво ви казва |
|---|---|
| Контейнерите са running | Docker стартира процесите. |
| curl -i http://127.0.0.1 връща 200 OK и фразата за демо | HAProxy действително маршрутизира трафика към backend-а. |
| Страницата със статистика показва demo1 като UP | HAProxy вижда backend-а като здравословен. |
Често срещани грешки при първо стартиране и бързи решения

Ако настройката не работи веднага, устойте на желанието да пренапишете двата файла наведнъж. Повечето първоначални откази на този стек са предвидими и те стават много по-лесни за поправка, когато промените една променлива наведнъж.
Използвайте тази матрица като бърз диагностичен слой:
HAProxy се затваря веднага
Вероятна причина: haproxy.cfg липсва.
Бързо решение: Убедете се, че haproxy.cfg съществува до compose.yaml.
Защо се случва: Официалният образ не идва с готов за употреба конфиг.
Грешката казва, че не може да отвори /usr/local/etc/haproxy/haproxy.cfg
Вероятна причина: Неправилен път на bind-mount.
Бързо решение: Проверете ./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro точно.
Защо се случва: HAProxy не може да стартира без валиден конфиг файл.
Грешката казва Permission denied на порт 80
Вероятна причина: Проблем с привилегирана портова връзка.
Бързо решение: Запазете net.ipv4.ip_unprivileged_port_start: “0” в Compose, или преместете както HAProxy, така и публикувания порт на 8080.
Защо се случва: Контейнерът работи като непривилегирован haproxy потребител.
Вие промените картографирането на 8080:80 и все още получавате грешка при свързване
Вероятна причина: HAProxy все още се свързва към :80 вътре в контейнера.
Бързо решение: Променете както картографирането на хоста, така и вътрешния ред bind, ако се отдалечите от порт 80.
Защо се случва: Правилото за привилегирани портове се прилага и вътре в контейнера.
Порт 80 вече е в употреба
Вероятна причина: Друга услуга притежава хост портът.
Бързо решение: Преустановете проверката ss и спрете или преместете конфликтната услуга.
Защо се случва: Само един процес може да слуша на един и същи хост порт.
Проверката на синтаксиса докладва unknown keyword или грешки, специфични за редове
Вероятна причина: Печатна грешка в HAProxy конфига.
Бързо решение: Преустановете проверката на синтаксиса и поправете точния ред, който докладва.
Защо се случва: Парсерът на HAProxy е строг, което е полезно, когато го използвате намерено.
Контейнерите са активни, но curl не връща демо отговора
Вероятна причина: Маршрутният път е неправилен.
Бързо решение: Преконтролирайте default_backend demo_backend, server demo1 demo:5678 check и името на услугата demo.
Защо се случва: Работещ контейнер не е доказателство за правилен път от frontend към backend.
Локалният curl работи, но сайтът е недостъпен отвън
Вероятна причина: Firewall или правило за сигурност от страна на доставчика.
Бързо решение: Отворете порт 80 в UFW и всеки firewall от страна на доставчика.
Защо се случва: Локалното публикуване може да работи дори когато публичният достъп все още е блокиран.
⚠️ Внимание: Променяйте по един елемент наведнъж. Ако редактирате както compose.yaml, така и haproxy.cfg сляпо, много по-трудно е да определите дали отказът е проблем с пътя на файла, проблем с портовете или проблем с маршрутизирането.
Когато имате нужда от бързо доказателство, держите тези команди наблизо:
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Това са трите модела на алерти, които най-много си струва да разпознаете на пръв поглед:
[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?Това е успокояващата част на малко първо развертване: формите на отказ обикновено са малки и. Не е необходимо да започвате отново. Трябва да определите кой слой се оплаква и да коригирате първо този един елемент.
Къде да отидете след инсталацията
Когато демото с един бекенд работи, архитектурата вече е полезна. Следващата реална стъпка е да замените демо контейнера с вашето действително приложение, като запазите същата HAProxy структура. След това добавете HTTPS/TLS като отделна последваща стъпка и третирайте маршрутизирането на базата на домейн плюс ACL като отделни теми, вместо да ги бързате в този първи инсталация.

Когато сте готови за повече от един бекенд, същият модел става видимо значим:
backend app_backend
balance roundrobin
server app1 app1:8080 check
server app2 app2:8080 checkЗа безопасни редакции на конфигурация, монтирана чрез bind, първо валидирайте и след това презаредете 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📝 Забележка: Страницата със статистика е умишлено само локална в това ръководство. Ако някога я разкриете публично, първо добавете удостоверяване и контроли на достъпа.
Това ви връща към първоначалния проблем: искахте един чист входен портал пред услуга, без да превръщате първата настройка в пълен операционен проект. Вече имате този работещ път. Още по-важното е, че имате и правилния мисловен модел: HAProxy получава трафика първи, го препраща където трябва, и ви дава по-чист начин да растете стека на самоуправляван VPS без да губите контрол над конфигурацията.
от всички хостинг услуги