502 Bad Gateway — nginx orqasida nima buzildi
Deploy tugadi, sahifani yangilaysiz — oq fon, o'rtada 502 Bad Gateway, pastida kichkina nginx/1.27.5. Birinchi reflex — nginx'ni restart qilish. Odatda bu foyda bermaydi, chunki nginx sog'. 502 ni aynan u qaytardi: so'rovni qabul qildi, orqadagi servisga (upstream) uzatmoqchi bo'ldi va yaroqli javob ololmadi.
Demak tergov nginx'dan emas, nginx bilan upstream orasidagi yo'ldan boshlanadi.
502 nimani anglatadi#
502 — "mijoz tomoni joyida, upstream'dan javob yo'q yoki buzuq". Qo'shni belgilar esa boshqa joyga ishora:
| Mijoz ko'radi | Qayerdan qidirish kerak |
|---|---|
| Ulanish xatosi, HTTP kodi yo'q | nginx'ning o'zi ishlamayapti yoki port yopiq |
| 502 Bad Gateway | upstream ulanishni rad etdi, uzdi yoki nomi topilmadi |
| 504 Gateway Time-out | upstream vaqtida javob bermadi |
| Ilovaning o'z 404 sahifasi | so'rov yetib bordi, lekin yo'l noto'g'ri uzatildi |
1-qadam: error.log — birinchi dalil#
Rasmiy nginx image'ida /var/log/nginx/error.log — /dev/stderr ga, access.log esa /dev/stdout ga symlink. Ikkalasi ham docker compose logs da:
$ docker compose logs --tail=200 proxy | grep -E 'upstream|emerg'Xato qatoridagi eng qimmatli maydon — upstream:. U siz o'ylagan manzilni emas, nginx haqiqatan urgan IP va portni ko'rsatadi.
connect() failed (111: Connection refused)#
2026/09/21 08:18:37 [error] 23#23: *7 connect() failed (111: Connection refused) while connecting to upstream, client: 172.28.0.1, server: _, request: "GET / HTTP/1.1", upstream: "http://172.28.0.2:8000/", host: "localhost"Paket manzilga yetib bordi, lekin o'sha portda hech kim tinglamayapti — yadro darhol rad javobini qaytardi. Tarmoq ishlayapti, muammo port yoki jarayonda:
- ilova yiqilgan yoki qayta ishga tushyapti (
docker compose ps,docker compose logs api); - ilova boshqa portda tinglayapti:
proxy_pass8000 ga, ilova esa 3000 da; - ilova faqat
127.0.0.1da tinglayapti — uvicorn'ning--hoststandart qiymati aynan shu; proxy_passdalocalhostyozilgan;apiqayta yaratilgan va boshqa IP olgan, nginx esa eskisiga urilyapti.
upstream timed out (110: ...)#
2026/09/21 08:19:41 [error] 163#163: *33 upstream timed out (110: Operation timed out) while reading response header from upstream, client: 172.28.0.1, server: _, request: "GET /report HTTP/1.1", upstream: "http://172.28.0.4:8000/report", host: "localhost"while connecting to upstream — paket ketdi, javob kelmadi: faervol tashlab yuboryapti yoki manzilda hech kim yo'q. while reading response header from upstream — ulanish bo'ldi, lekin ilova javob yozmadi: sekin so'rov, band bo'lgan worker, bazani kutish. Ikkala holatda ham mijoz 504 oladi, 502 emas. proxy_connect_timeout va proxy_read_timeout standart qiymati — 60 soniya.
no live upstreams#
2026/09/21 08:21:39 [error] 307#307: *77 no live upstreams while connecting to upstream, client: 172.28.0.1, server: _, request: "GET /api/orders HTTP/1.1", upstream: "http://backend/api/orders", host: "localhost"Bu safar nginx ulanishga urinmagan ham. upstream backend blokidagi har bir server fail_timeout (standart 10 soniya) ichida max_fails (standart 1) marta yiqilib, vaqtincha chetlatilgan — shuning uchun nginx darhol 502 qaytargan. upstream: maydonida IP emas, guruh nomi: asl sabab bu qatorda yo'q. Yuqoriroqdan birinchi connect() failed yoki timed out qatorini qidiring.
host not found in upstream#
2026/09/21 08:21:54 [emerg] 1#1: host not found in upstream "apii" in /etc/nginx/conf.d/default.conf:6[emerg] — bu 502 emas: nginx umuman ishga tushmagan, mijoz yopiq portni ko'radi. proxy_pass dagi oddiy nomni nginx konfiguratsiyani yuklashda bir marta resolve qiladi; Docker DNS nomni bilmasa, jarayon chiqib ketadi. Sabablari: servis nomida xato, proxy va api umumiy tarmoqda emas (Docker DNS nomlarni faqat bitta tarmoq ichida beradi), yoki nginx ko'tarilganda api konteyneri hali yaratilmagan.
2-qadam: upstream'ni nginx ko'zi bilan tekshirish#
Log nginx qayerga urganini aytdi. Endi o'sha joyga o'zingiz boring — nginx konteyneri ichidan, chunki DNS, tarmoq va localhost u yerda nginx ko'rgandek:
$ docker compose exec proxy curl -sS -o /dev/null -w '%{http_code}\n' http://api:8000/
curl: (7) Failed to connect to api port 8000 after 7 ms: Could not connect to server
000000 — javob umuman kelmagan. curl'ning chiqish kodi (echo $?) yo'nalish beradi: 6 — nom topilmadi (DNS yoki tarmoq), 7 — ulanib bo'lmadi (hech kim tinglamayapti), 28 — vaqt tugadi. 200 chiqsa, upstream sog' va muammo nginx konfiguratsiyasida. nginx:1.27-alpine da curl bor; Python va Node alpine image'larida — busybox wget -qO-.
Ilova aslida qayerda tinglayapti?
$ docker compose exec api netstat -ltn
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 127.0.0.1:8000 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.11:45485 0.0.0.0:* LISTEN127.0.0.1:8000 — ilova faqat o'z konteynerining loopback'ida. nginx boshqa konteyner, u eth0 orqali keladi va yopiq eshikka uriladi. To'g'risi — 0.0.0.0:8000. 127.0.0.11 dagi qator — Docker'ning ichki DNS'i, compose tarmog'idagi har bir konteynerda bor.
Image'da netstat ham bo'lmasa (distroless, slim), uning tarmoq namespace'iga vaqtinchalik konteyner ulang:
$ docker run --rm --network container:$(docker compose ps -q api) busybox:1.37 netstat -ltnKonteynersiz, systemd ostidagi servis uchun xuddi shu savolga ss -ltn javob beradi.
3-qadam: tipik sabablar#
localhost — bu nginx'ning o'zi#
Compose'da har bir servis — alohida konteyner, alohida tarmoq namespace. nginx konteyneri ichida localhost nginx'ning o'zi; u yerda 8000-portda hech kim yo'q. Logdagi belgi — upstream: "http://127.0.0.1:8000/" yoki [::1]:8000. To'g'risi — servis nomi:
location / {
proxy_pass http://api:8000;
}Port ham konteyner porti: api da ports: ["8080:8000"] bo'lsa ham, konteynerlar orasida api:8000 ishlatiladi — 8080 host uchun eshik, compose tarmog'i ichida u yo'q. Proksi ortidagi servisga ports umuman kerak emas.
Deploy paytidagi 502#
Ishga tushish poygasi. nginx bir soniyada ko'tariladi, ilova o'n soniyada. Shu oraliqda har so'rov — 111: Connection refused. Oddiy depends_on konteyner ishga tushganini kutadi, ilova tayyorligini emas. Yechim — healthcheck va service_healthy:
services:
proxy:
image: nginx:1.27-alpine
depends_on:
api:
condition: service_healthy
api:
build: .
command: uvicorn app:app --host 0.0.0.0 --port 8000
healthcheck:
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/health', timeout=3)"]
interval: 5s
retries: 5Healthcheck Python'ning o'zida — image'da wget yoki curl bo'lishi shart emas.
Eskirgan IP. nginx proxy_pass dagi nomni faqat konfiguratsiyani yuklaganda resolve qiladi va IP'ni eslab qoladi. docker compose up -d api ni qayta yaratsa, yangi konteyner boshqa IP olishi mumkin, nginx esa eski manzilga urishda davom etadi. O'sha IP endi boshqa konteynerniki bo'lsa — Connection refused, hech kimniki bo'lmasa — timeout yoki 113 xatosi. Belgisi: docker compose exec proxy curl http://api:8000/ ishlaydi (curl nomni yangidan so'raydi), nginx esa 502 beradi.
Tez yechim — nginx -s reload: konfiguratsiya qayta o'qiladi va nomlar yangidan resolve qilinadi. Doimiy yechim — nomni har so'rovda Docker DNS'dan so'rash:
resolver 127.0.0.11 valid=10s;
location / {
set $upstream http://api:8000;
proxy_pass $upstream;
}proxy_pass da o'zgaruvchi bo'lsa, nom so'rov paytida resolve qilinadi. Shu sababli bu variantda xato nom nginx'ni yiqitmaydi — o'sha so'rov 502 oladi va logda apii could not be resolved (3: Host not found) chiqadi.
proxy_pass va oxirgi /#
Bu 502 bermaydi, lekin xuddi shu tergovda chiqadi: proksi sog', ilova sog', lekin ilova 404 qaytaradi. Qoida: proxy_pass da URI qismi bo'lsa (hatto birgina /), nginx location ga mos kelgan qismni o'sha URI bilan almashtiradi. Bo'lmasa, yo'l o'zgarmasdan uzatiladi.
location | proxy_pass | So'rov | Ilovaga yetib boradi |
|---|---|---|---|
/api/ | http://api:8000 | /api/users | /api/users |
/api/ | http://api:8000/ | /api/users | /users |
/api | http://api:8000/ | /api/users | //users |
Uchinchi qator eng ayyori: ba'zi serverlar //users ni o'zi tuzatadi, ba'zilari 404 beradi. location va proxy_pass dagi slash'lar juft bo'lsin.
502 va 504: log qatoridan status kodigacha#
| Log qatori | Mijoz oladi |
|---|---|
connect() failed (111: Connection refused) | 502 |
upstream prematurely closed connection | 502 |
no live upstreams | 502 |
could not be resolved (3: Host not found) | 502 |
upstream timed out (110: ...) | 504 |
[emerg] host not found in upstream | hech narsa — nginx ishga tushmagan |
upstream prematurely closed connection ga alohida qarang: ilova so'rovni qabul qilgan, lekin javob yozmasdan ulanishni yopgan. Odatda jarayon so'rov o'rtasida o'ldirilgan — OOM killer yoki gunicorn'ning worker timeout'i (standart 30 soniya) tomonidan. Tashqaridan bu sekin so'rovga o'xshaydi, lekin 504 emas, 502 keladi: nginx kutib charchamadi, ulanish uning qo'lida yopildi. Ulanish keskin uzilsa, xuddi shu holat recv() failed (104: Connection reset by peer) bo'lib ko'rinadi.
Tuzatgandan keyin: tekshirish#
Avval sintaksis, keyin qayta yuklash — restart emas, u ochiq ulanishlarni uzadi:
$ docker compose exec proxy nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
$ docker compose exec proxy nginx -s reload
$ curl -sI http://localhost/ | head -1
HTTP/1.1 200 OKKeyingi 502 ni tezroq topish uchun access log'ga upstream maydonlarini qo'shing. Rasmiy image'da conf.d/*.conf fayllari http {} ichiga ulanadi, shuning uchun log_format ni o'sha faylning boshiga yozsa bo'ladi:
log_format upstream '$remote_addr "$request" $status '
'up=$upstream_addr up_status=$upstream_status '
'rt=$request_time urt=$upstream_response_time';
server {
listen 80;
access_log /var/log/nginx/access.log upstream;
# ...
}Endi har bir 502 qatorida qaysi upstream qancha vaqtda nima qaytargani yoziladi:
172.28.0.1 "GET /api/orders HTTP/1.1" 502 up=172.28.0.4:8000 up_status=502 rt=0.005 urt=0.006up= maydonida vergul bilan bir nechta manzil bo'lsa, nginx ularning har birini sinab ko'rgan — localhost holatida aynan shunday: up=[::1]:8000, 127.0.0.1:8000. urt rt ga yaqin bo'lsa, vaqtning hammasi upstream'ni kutishga ketgan.
Amaliyot#
Har bir laboratoriya shu maqoladagi bitta sababni compose faylida beradi: ishga tushish poygasi, loopback'dagi ilova, tarmoqlar chegarasidagi proksi, bitta proksi ortida ikki servis. Buyruqlarni esa mashg'ulotda mustahkamlang.