Что нового

Как диагностировать недоступность сайта через цепочку Reverse Proxy и найти TCP timeout до origin

d2f44462-ac0a-476f-90e5-960dae5a39f7.png


Как я диагностировал недоступность сайта через цепочку Reverse Proxy и нашёл сетевой timeout до origin​


В один момент перестали нормально открываться несколько моих сайтов. Накануне всё работало, конфигурация nginx не менялась, но сайты через цепочку reverse proxy перестали отвечать.

Последовательная проверка каждого участка позволила быстро локализовать проблему между промежуточным reverse proxy и origin-серверами.

Позже дополнительная проверка показала, что причиной сбоя на этом направлении была фильтрация с использованием технических средств противодействия угрозам (ТСПУ).

Важно разделять две вещи:

  • сетевые тесты и nginx-логи подтвердили TCP connect timeout при соединении middle proxy → origin;
  • конкретная причина в виде фильтрации с использованием ТСПУ была установлена отдельно.

Все реальные домены и публичные IP-адреса в статье заменены на адреса для документации.

Используемые адреса​


Код:
example.org          — основной сайт
tracker.example.org  — трекер

203.0.113.10         — публичный frontend
198.51.100.10        — промежуточный reverse proxy
192.0.2.10           — web origin
192.0.2.20           — tracker origin
198.51.100.1         — gateway middle proxy

Используемые IP относятся к TEST-NET диапазонам и не отражают реальную географию серверов.

Исходная схема​


Код:
Пользователь
|
v
Frontend
203.0.113.10
|
v
Middle proxy
198.51.100.10
|
+----------------------+
|                      |
v                      v
192.0.2.10             192.0.2.20
Web origin             Tracker origin

1. Проверяю DNS​


С рабочего компьютера проверяю разрешение имени через нужный DNS-сервер:

Код:
nslookup example.org DNS_SERVER_IP

Получаю ожидаемый адрес:

Код:
example.org
Address: 203.0.113.10

Проверяемый DNS-сервер возвращает ожидаемый IP.

Это не полная проверка всей DNS-инфраструктуры, но очевидную ошибку разрешения имени через этот DNS-сервер на данном этапе исключает.

Позже curl также показывает, что example.org разрешается в ожидаемый адрес:

Код:
Connected to example.org (203.0.113.10) port 443

2. Проверяю HTTPS​


На Windows:

Код:
curl.exe -vk --max-time 15 https://example.org/ -o NUL

TCP-соединение устанавливается:

Код:
Connected to example.org (203.0.113.10) port 443

TLS-handshake завершается успешно, через ALPN в моём случае согласовывается HTTP/1.1:

Код:
ALPN: server accepted http/1.1

curl отправляет запрос:

Код:
GET / HTTP/1.1
Host: example.org

Код:
Request completely sent off

Но HTTP-ответ не приходит в течение заданного времени ожидания.

На этом этапе уже понятно:

  • имя разрешяется в ожидаемый IP;
  • TCP-соединение с frontend устанавливается;
  • TLS работает;
  • HTTP-запрос полностью отправляется на frontend;
  • HTTP-ответ клиенту не возвращается в течение заданных 15 секунд.

Где именно возникает задержка, проверяю дальше.

Ключ -k отключает обычную проверку TLS-сертификата, включая доверие к центру сертификации и соответствие сертификата имени хоста.

Для обычной проверки повторяю запрос без него:

Код:
curl.exe -v --max-time 15 https://example.org/

3. Проверяю HTTP на 80 порту​


Код:
curl.exe -v --max-time 15 http://example.org/ -o NUL

Получаю:

Код:
HTTP/1.1 301 Moved Permanently
Location: https://example.org/

То есть frontend принимает соединение на TCP/80 и возвращает HTTP-редирект.

4. Проверяю конфигурацию frontend​


Смотрю активную конфигурацию nginx:

Код:
nginx -T 2>&1 | grep -n -A40 -B5 'server_name.*example.org'

Frontend принимает HTTPS-запрос клиента, завершает TLS и проксирует запрос дальше на middle proxy по HTTP:

Код:
198.51.100.10

Пример:

Код:
location / {
proxy_pass http://198.51.100.10;

```
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
```

}

5. Смотрю error.log на frontend​


В логах повторяется:

Код:
upstream timed out (110: Connection timed out)
while reading response header from upstream
upstream: "http://198.51.100.10:80/"

Ключевая часть:

Код:
while reading response header from upstream

Это не TCP connect timeout.

Frontend дошёл до стадии чтения заголовка ответа от upstream, но не получил данных от него в течение интервала proxy_read_timeout.

Сам proxy_read_timeout задаёт интервал между операциями чтения от upstream, а не максимальное время получения всего ответа.

Значит, следующий шаг — проверить middle proxy напрямую.

6. Проверяю middle proxy с frontend​


На Linux:

Код:
curl -v --connect-timeout 5 --max-time 10
http://198.51.100.10/
-H 'Host: example.org'

Получаю:

Код:
Connected to 198.51.100.10 port 80

GET / HTTP/1.1
Host: example.org

а затем:

Код:
Operation timed out after 10000 milliseconds
with 0 bytes received

TCP-соединение с middle proxy устанавливается. curl отправляет HTTP-запрос, но ответ не приходит в течение заданных 10 секунд.

7. Проверяю nginx локально на middle proxy​


Подключаюсь к middle proxy и выполняю:

Код:
curl -v --connect-timeout 5 --max-time 10
http://127.0.0.1/
-H 'Host: example.org'

Результат тот же:

Код:
Connected to 127.0.0.1 port 80

GET / HTTP/1.1
Host: example.org

Operation timed out after 10000 milliseconds
with 0 bytes received

Проблема воспроизводится даже через localhost: соединение устанавливается, но HTTP-ответ не приходит в течение заданных 10 секунд.

Следовательно, внешний участок:

Код:
пользователь -> frontend -> middle proxy

не является причиной самого зависания на middle proxy.

Сам этот тест ещё не показывает, на каком внутреннем этапе зависает nginx. Это становится понятно из его логов.

8. Проверяю состояние middle proxy​


Код:
uptime
free -m
df -h
systemctl status nginx
nginx -t

Явных признаков перегрузки нет, nginx запущен, а nginx -t проходит успешно:

Код:
Active: active (running)

syntax is ok
test is successful

То, что конфигурация nginx не менялась, ещё ничего не гарантирует: могли измениться маршрутизация, firewall, ACL или фильтрация на стороне сети или провайдера.

9. Нахожу следующий upstream​


Для быстрого поиска:

Код:
nginx -T 2>&1 | grep -nE -A5 -B2
'upstream|proxy_pass|server_name.*example'

Если блок большой, просматриваю полный вывод:

Код:
nginx -T

Следующими узлами оказались:

Код:
192.0.2.10
192.0.2.20

10. Нахожу ключевую ошибку на middle proxy​


В error.log middle proxy появляется уже другая ошибка:

Код:
upstream timed out
while connecting to upstream

Например:

Код:
upstream:
"http://192.0.2.20:80/announce.php"

Именно:

Код:
while connecting to upstream

означает, что nginx не смог установить соединение с upstream в пределах proxy_connect_timeout.

В отличие от:

Код:
while reading response header from upstream

здесь проблема уже находится на стадии установления TCP-соединения.

11. Проверяю origin напрямую​


С middle proxy:

Код:
curl -v --connect-timeout 5 --max-time 10
http://192.0.2.10/
-H 'Host: example.org'

Получаю:

Код:
Trying 192.0.2.10:80...

connect to 192.0.2.10 port 80 failed:
Connection timed out

Проверяю второй origin:

Код:
curl -v --connect-timeout 5 --max-time 10
http://192.0.2.20/announce.php
-H 'Host: tracker.example.org'

Результат такой же:

Код:
connect to 192.0.2.20 port 80 failed:
Connection timed out

Здесь curl уже не доходит до:

Код:
Connected to ...

TCP-соединение с origin не устанавливается в течение заданных 5 секунд.

Это основной результат всей диагностики.

PHP и веб-приложение не могут быть непосредственной причиной именно этого TCP connect timeout, потому что соединение ещё не дошло до HTTP-обработки.

12. Проверяю маршрут​


На middle proxy:

Код:
ip route get 192.0.2.10
ip route get 192.0.2.20

Например:

Код:
192.0.2.10 via 198.51.100.1 dev eth0 src 198.51.100.10

ip route get показывает результат route lookup ядра: выбранный next-hop и интерфейс.

Это не доказывает, что пакеты действительно проходят весь путь до origin.

13. Проверяю firewall​


На middle proxy проверяю, не блокируется ли локально исходящий или возвращающийся трафик.

iptables:

Код:
iptables -L OUTPUT -n -v --line-numbers
iptables -L INPUT -n -v --line-numbers
iptables -S

nftables:

Код:
nft list ruleset

UFW:

Код:
ufw status verbose

На origin проверяю входящие правила и наличие слушающего порта:

Код:
ss -lnt '( sport = :80 )'

При необходимости:

Код:
ss -lntp '( sport = :80 )'

и соответствующий firewall:

Код:
iptables -L INPUT -n -v --line-numbers
iptables -S

или:

Код:
nft list ruleset

Также учитываю внешние ACL, security groups и firewall провайдера, если они используются.

14. Дополнительно проверяю ICMP и другие TCP-порты​


Код:
ping -c 4 192.0.2.10
ping -c 4 192.0.2.20

В моём случае:

Код:
100% packet loss

Сам по себе ping ничего не доказывает, потому что ICMP может фильтроваться.

При необходимости проверяю несколько TCP-портов:

Код:
nc -vz -w 5 192.0.2.10 22
nc -vz -w 5 192.0.2.10 80
nc -vz -w 5 192.0.2.10 443

Это помогает понять, ограничена ли проблема одним сервисом или затрагивает направление шире.

15. При необходимости смотрю tcpdump​


Если нужно понять, приходит ли TCP SYN на origin:

Код:
tcpdump -ni any tcp port 80

После определения фактического source IP фильтр можно сузить:

Код:
tcpdump -ni any host 198.51.100.10 and tcp port 80

Если SYN при корректной точке захвата и с учётом возможного NAT/SNAT на origin не виден, он не доходит до наблюдаемого сетевого стека origin.

Для данного инцидента этого уровня проверки было достаточно.

16. Проверяю с другой точки сети​


С другого сервера:

Код:
curl -v --connect-timeout 5 --max-time 10
http://192.0.2.10/
-H 'Host: example.org'

Если:

Код:
другой сервер -> origin = OK

а:

Код:
middle proxy -> origin = connect timeout

значит, проблема связана с middle proxy или сетевым путём от него до origin.

Именно такой подход — проверять доступность с каждого сервера по очереди — в моём случае быстро показал проблемный участок.

Установленная причина​


Непосредственно сетевой диагностикой было установлено следующее.

Frontend фиксировал:

Код:
while reading response header from upstream

Middle proxy фиксировал:

Код:
while connecting to upstream

Прямой запрос с middle proxy до origin показывал:

Код:
Connection timed out

Следовательно, подтверждённый симптом при соединении:

Код:
middle proxy -> origin

был:

Код:
TCP connect timeout

Эти тесты сами по себе не позволяют определить ТСПУ как конкретный механизм фильтрации.

После того как проблемное направление было локализовано, я провёл дополнительную проверку. По её результатам причиной сбоя на этом сетевом направлении была определена фильтрация с использованием ТСПУ.

Речь идёт именно о конкретном инциденте и конкретном сетевом направлении.

Почему увеличение timeout не решило бы проблему​


Можно увеличить:

Код:
proxy_connect_timeout
proxy_read_timeout

Но если TCP-соединение с origin не устанавливается из-за сетевой проблемы или фильтрации, увеличение timeout только заставит nginx и пользователя дольше ждать тот же результат.

Перезапуск nginx тоже ничего не исправит, если nginx нормально работает и проблема находится дальше по сетевой цепочке.

Мой короткий алгоритм диагностики​


  1. Проверяю DNS.
  2. Проверяю HTTP и HTTPS через curl.
  3. Смотрю, на каком этапе останавливается запрос.
  4. Проверяю error.log nginx.
  5. Смотрю, какой upstream используется.
  6. Проверяю этот upstream напрямую.
  7. Повторяю проверку на следующем сервере.
  8. При while connecting to upstream проверяю прямое TCP-соединение до origin.
  9. Проверяю ip route get и firewall.
  10. При необходимости использую ping, nc и tcpdump.
  11. Сравниваю доступность origin с другой точки сети.

Главное — проверять цепочку последовательно, переход за переходом, а не начинать с изменения timeout и перезапуска сервисов.

Вывод​


Финальная картина выглядела так:

Код:
Пользователь
|
v
Frontend
203.0.113.10
|
| соединение с middle работает
v
Middle proxy
198.51.100.10
|
| TCP connect timeout
X
|
v
Origin
192.0.2.10 / 192.0.2.20

На frontend я видел:

Код:
while reading response header from upstream

а на middle proxy:

Код:
while connecting to upstream

Прямой curl с middle proxy до обоих origin подтверждал:

Код:
Connection timed out

Именно последовательная проверка:

Код:
клиент
->
frontend
->
middle proxy
->
origin

позволила без лишних изменений конфигурации быстро найти проблемный участок.

После дополнительной проверки была установлена и конкретная причина сбоя на этом направлении — фильтрация с использованием ТСПУ.

Главный вывод для меня простой: если nginx сообщает upstream timed out, сначала нужно понять, на каком именно переходе перестаёт ходить трафик, а уже потом менять конфигурацию или искать проблему в приложении.
Об авторе
Guru
Василий, cистемный админ /gnu/linux/windows/macos/mikrotik/troubleshooter, создатель сайта
Интересуюсь всем что делает инфраструктуру быстрой и надёжной
Открыт к общению и проектам, написать мне можно через форму или в личном сообщении

❗ Если есть пожелания по обзору какого-либо вопроса не представленного на сайте - пиши в комментариях

Комментарии

Нет комментариев для отображения.

Информация о статье

Автор
Guru
Время чтения статьи
7 мин чтения
Просмотры
14
Посл. обновление

Ещё в Работа над ошибками

Ещё от Guru

Поделиться этой статьёй

Назад
Верх