~/blog / 502-bad-gateway-tergovback

502 Bad Gateway — nginx orqasida nima buzildi

8 daqiqa o'qish

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'radiQayerdan qidirish kerak
Ulanish xatosi, HTTP kodi yo'qnginx'ning o'zi ishlamayapti yoki port yopiq
502 Bad Gatewayupstream ulanishni rad etdi, uzdi yoki nomi topilmadi
504 Gateway Time-outupstream vaqtida javob bermadi
Ilovaning o'z 404 sahifasiso'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:

console
$ 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)#

text
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_pass 8000 ga, ilova esa 3000 da;
  • ilova faqat 127.0.0.1 da tinglayapti — uvicorn'ning --host standart qiymati aynan shu;
  • proxy_pass da localhost yozilgan;
  • api qayta yaratilgan va boshqa IP olgan, nginx esa eskisiga urilyapti.

upstream timed out (110: ...)#

text
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#

text
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#

text
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:

console
$ 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
000

000 — 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?

console
$ 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:*               LISTEN

127.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:

console
$ docker run --rm --network container:$(docker compose ps -q api) busybox:1.37 netstat -ltn

Konteynersiz, 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:

nginx
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:

yaml
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: 5

Healthcheck 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:

nginx
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.

locationproxy_passSo'rovIlovaga yetib boradi
/api/http://api:8000/api/users/api/users
/api/http://api:8000//api/users/users
/apihttp://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 qatoriMijoz oladi
connect() failed (111: Connection refused)502
upstream prematurely closed connection502
no live upstreams502
could not be resolved (3: Host not found)502
upstream timed out (110: ...)504
[emerg] host not found in upstreamhech 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:

console
$ 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 OK

Keyingi 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:

nginx
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:

text
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.006

up= 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.

labo'rtaHar deploy'da 30 soniya 502Proksi API tayyor bo'lmasdan ishga tushib, *502 Bad Gateway* qaytaryapti.mashqni ochish labosonIlova `127.0.0.1` da tinglayapti — konteynerdan tashqarida ko'rinmaydiPort ochiq, lekin *connection refused*. Ilova faqat konteyner ichidagi loopback'da.mashqni ochish labqiyinProksi — ikki dunyo chegarasidaProksi tashqi va ichki tarmoq o'rtasida turadi. Ilova faqat ichkarida.mashqni ochish labo'rtaIkki ilova, bitta kirish nuqtasi`shop` va `blog` alohida portlarda. Bitta proksi ikkalasini domen bo'yicha ajratsin.mashqni ochish buyruq mashqi5-bosqich · 16 vazifaNosozlik qidirishSayt ishlamayapti. Qayerdan boshlaysiz? Tarmoq, DNS, sertifikat, servis.bosqichni boshlash