TCP-соединение редко “просто не работает”. Обычно ломается что-то конкретное: сервис не слушает порт, пакет не доходит до сервера, ответ теряется на обратном пути, соединение сбрасывается через RST или приложение принимает подключение, но дальше молчит.
Хорошая диагностика начинается не с любимой команды, а с вопроса: на каком участке рвётся цепочка? Ниже — базовый порядок проверки для Linux-сервера или рабочей станции. Без глубокого Wireshark, но уже достаточно практично, чтобы отделить проблему приложения от проблемы сети.
Сначала определите симптом
Перед командами полезно назвать проблему своими словами. Это экономит время.
Типовые варианты:
- порт не слушается на сервере;
- TCP handshake не проходит;
- соединение устанавливается, но приложение не отвечает;
- соединение сразу сбрасывается через
RST; - подключение висит и заканчивается timeout;
- проблема есть только у одного клиента или из одной сети.
Если симптом понятен, инструменты выбираются сами: ss покажет сокеты, ping и traceroute проверят путь, tcpdump покажет реальные пакеты, а journalctl подскажет, что думает сервис или ядро.

Быстрый порядок проверки
Если нужно быстро понять направление, идите так:
- На сервере проверьте, слушает ли сервис нужный порт через
ss. - С клиента проверьте доступность хоста через
ping. - Посмотрите маршрут через
tracerouteилиtracepath. - Создайте TCP-попытку через
curlилиnc. - Снимите
tcpdumpна клиенте и сервере. - Проверьте логи сервиса и ядра через
journalctl.
Этот порядок не идеален для всех случаев, но он хорошо защищает от хаоса. Не придётся гадать, где проблема: в приложении, маршруте, firewall или обратном пути.
1. Проверяем сокеты через ss
ss — первая команда на сервере. Она отвечает на простой вопрос: есть ли вообще процесс, который слушает нужный TCP-порт?
Показать слушающие TCP-порты и процессы:
ss -ltnp
Показать все TCP-соединения:
ss -tan
Показать только установленные соединения:
ss -tan state established
Показать соединения, где клиент отправил SYN и ждёт ответа:
ss -tan state syn-sent
Показать TIME-WAIT:
ss -tan state time-wait
Точечная проверка по порту:
ss -tinp '( sport = :443 or dport = :443 )'
На что смотреть:
LISTEN— сервис поднят и слушает порт;ESTAB— соединение установлено;SYN-SENT— клиент ждёт ответ на SYN;CLOSE-WAIT— удалённая сторона закрыла соединение, а локальное приложение ещё не завершило его;- много
TIME-WAIT— не всегда ошибка, но повод посмотреть на частоту коротких соединений.
Если на сервере нет LISTEN на нужном порту, внешняя сеть пока ни при чём. Сначала разбирайтесь с сервисом: он не запущен, слушает другой адрес, упал при старте или привязан только к 127.0.0.1.
2. Проверяем доступность через ping
ping не проверяет TCP-порт. Он проверяет, отвечает ли хост по ICMP и нет ли явной потери пакетов.
ping -c 4 example.com
Смотрите на три вещи:
- есть ли ответы;
- есть ли packet loss;
- насколько стабильная задержка.
Если ping не проходит, это ещё не доказывает, что TCP тоже не пройдёт. ICMP часто режут на firewall или у провайдера. Но если ping показывает потери и скачущую задержку, это хороший сигнал, что проблема может быть ниже приложения.
3. Проверяем маршрут через traceroute
Обычный traceroute помогает понять, где примерно ломается путь до хоста.
traceroute example.com
Если traceroute не установлен, часто есть tracepath:
tracepath example.com
Для статьи про TCP важный момент: обычный traceroute может использовать UDP или ICMP, а проблема иногда проявляется только на конкретном TCP-порту. Для проверки TCP-маршрута используйте режим -T:
sudo traceroute -T -p 443 example.com
Это не заменяет tcpdump, но даёт более честную картину, если проблема завязана на фильтрацию TCP/443.
Что полезно заметить:
- на каком хопе начинается резкая задержка;
- где маршрут обрывается;
- отличается ли поведение для обычного traceroute и TCP traceroute;
- нет ли странного ухода трафика через VPN, провайдера или промежуточный firewall.
Звёздочки в выводе traceroute не всегда означают поломку. Некоторые узлы просто не отвечают на диагностические пакеты, но нормально пересылают рабочий трафик дальше.
4. Создаём TCP-попытку через curl или nc
Иногда нужно не просто “проверить сеть”, а создать конкретную TCP-попытку, которую потом можно увидеть в ss и tcpdump.
Для HTTP/HTTPS удобно использовать curl:
curl -v https://example.com/
Для произвольного TCP-порта подойдёт nc:
nc -vz 203.0.113.10 443
Если nc пишет succeeded, TCP-соединение установилось. Это ещё не значит, что приложение полностью работает, но handshake прошёл.
Если видите timed out, чаще всего ответ не вернулся. Если connection refused, удалённая сторона активно отказала, обычно через RST: порт закрыт или сервис не слушает.
5. Смотрим пакеты через tcpdump
Когда нужно перестать гадать, берём tcpdump. Он показывает, что реально ушло в сеть и что вернулось обратно.
Базовый захват по адресу и порту:
sudo tcpdump -i any -nn -vv 'tcp and host 203.0.113.10 and port 443'
Если знаете интерфейс, лучше указать его явно:
sudo tcpdump -i eth0 -nn -vv 'tcp and port 443'
Полезные фильтры:
host <ip>— трафик к конкретному адресу;port <port>— конкретный порт;tcp and (port 80 or port 443)— быстрый фильтр для веб-трафика;-S— абсолютные TCP sequence number;-A— вывод полезной нагрузки текстом, если протокол не шифрован.
Как читать TCP handshake:
- клиент отправляет
SYN; - сервер отвечает
SYN, ACK; - клиент отвечает
ACK; - после этого соединение считается установленным.
Типовые картины:
SYNуходит,SYN, ACKне возвращается — firewall, NAT, маршрут или порт не дошёл до сервера;SYNприходит на сервер, но сервер не отвечает — локальный firewall, неправильный адрес, не тот интерфейс или сервис не слушает;- приходит
RST— порт закрыт или соединение сбрасывается; - видно много retransmission — пакеты теряются или есть проблема с MTU/маршрутом;
- handshake прошёл, но дальше нет данных — смотрите приложение, прокси и логи.
Лучший вариант — снять tcpdump с двух сторон: на клиенте и на сервере. Если на клиенте SYN уходит, а на сервере его нет, пакет потерялся по дороге. Если сервер отвечает, а клиент ответа не видит, ищите проблему на обратном маршруте.
6. Проверяем логи через journalctl
Логи часто объясняют то, чего не видно в пакетах. Например, сервис не смог привязаться к адресу, упал после старта или отбрасывает подключение на уровне приложения.
Логи конкретного сервиса за текущую загрузку:
journalctl -u nginx -b
Для SSH:
journalctl -u ssh -b
Если нужен kernel log:
journalctl -k -b
Фильтр по сетевым словам:
journalctl -k -b -g 'tcp|mtu|link|timeout|reset|conn'
Если journalctl -g недоступен в вашей версии systemd, используйте обычный grep:
journalctl -k -b | grep -Ei 'tcp|mtu|link|timeout|reset|conn'
Что искать:
- сервис не стартует;
bind failedилиaddress already in use;- ошибка привязки к IP-адресу;
- сообщения о link up/link down;
- признаки проблем с MTU;
- частые рестарты службы;
- ошибки reverse proxy или backend-сервиса.
Если в tcpdump handshake проходит, а приложение молчит, journalctl часто становится главным источником правды.
Минимум про firewall, NAT и обратный маршрут
Многие TCP-проблемы выглядят как “сервер не отвечает”, хотя сервер вообще не виноват.
Быстрая логика такая:
ssпоказываетLISTEN, но снаружи порт не открывается — проверьте firewall, NAT, security group, проброс портов;- серверный
tcpdumpне видит входящийSYN— пакет не дошёл до сервера; - сервер видит
SYNи отправляетSYN, ACK, но клиент не получает ответ — проблема может быть на обратном пути; - сервер сразу отвечает
RST— проверьте, тот ли порт и тот ли сервис; - подключение работает локально, но не работает снаружи — почти всегда стоит смотреть firewall/NAT/адресацию.
Даже простое сравнение tcpdump на клиенте и сервере часто быстрее, чем полчаса правок конфигов “на всякий случай”.
Как читать типовые ситуации
ss показывает LISTEN, но клиент не подключается
Сервис жив. Дальше проверяйте доступность снаружи: firewall, NAT, security group, route table, балансировщик, неправильный IP или порт.
ping работает, но TCP timeout
ICMP проходит, TCP нет. Такое бывает при фильтрации по порту, проблемах NAT или когда сервис слушает только локальный адрес.
tcpdump показывает RST
Удалённая сторона активно сбросила соединение. Обычно это закрытый порт, неправильный сервис или сброс на уровне firewall/proxy.
Handshake прошёл, но приложение молчит
TCP уже не главный подозреваемый. Смотрите journalctl, логи приложения, reverse proxy, таймауты backend и права доступа.
Соединение подвисает после части данных
Частые причины: потеря пакетов, MTU, проблемный VPN, перегруженный proxy, слишком короткие таймауты или приложение, которое не успевает читать данные.
Практический чеклист
Если разбирать проблему с нуля, я бы шёл так:
- На сервере:
ss -ltnpи проверка нужного порта. - С клиента:
ping, затемtracerouteилиtraceroute -T -p <port>. - С клиента:
curl -vилиnc -vz, чтобы создать TCP-попытку. - На клиенте и сервере:
tcpdumpпо IP и порту. - На сервере:
journalctl -u <service> -bиjournalctl -k -b. - Сравнить, где именно рвётся цепочка.
Обычно после этого остаётся не “сеть не работает”, а понятная формулировка: порт не слушается, SYN не доходит, ответ теряется на обратном пути, соединение сбрасывается или приложение не отвечает после успешного подключения.
Коротко
Для базовой диагностики TCP-соединений в Linux достаточно такого набора:
ss— понять, есть ли сокет и в каком он состоянии;ping— проверить базовую доступность и потери;traceroute— посмотреть маршрут;curlилиnc— создать реальную TCP-попытку;tcpdump— увидеть пакеты без догадок;journalctl— проверить сервис и ядро.
Главная мысль простая: не пытайтесь чинить всё сразу. Найдите участок, где ломается соединение, и уже потом трогайте конфиги, firewall или приложение.




