Ошибка TLS handshake timeout в Debian и Ubuntu неприятна тем, что почти никогда не указывает на реальную причину. Сегодня падает docker pull, через час подвисает curl, а потом начинает сыпаться apt update. На первый взгляд кажется, что сломан конкретный инструмент, но на практике проблема почти всегда лежит ниже: в сетевом пути, DNS, MTU, proxy, IPv6, NAT, фильтрации трафика или нестабильном канале.
Само TLS-рукопожатие — это лишь этап установки защищённого соединения. Если до него пакеты идут с потерями, фрагментируются, теряются ответы DNS, медленно отвечает прокси или где-то по дороге ломается Path MTU Discovery, клиент видит одинаковый симптом: таймаут во время handshake. Поэтому лечить тут нужно не «TLS вообще», а конкретный сетевой участок.
Проблема особенно часто проявляется на серверах за VPN, в контейнерных сетях, на хостах с изменённым MTU, при криво настроенном корпоративном proxy, а также при частично рабочем IPv6. В Docker ситуация усугубляется ещё и тем, что у демона, контейнера и самой системы могут быть разные DNS-настройки и разные сетевые маршруты.
Если вы поднимаете проекты на VDS, такой подход особенно полезен: сначала отделяем локальную проблему хоста от внешней сетевой деградации, а уже потом трогаем конфиги приложений.
Главная идея простая: если
TLS handshake timeoutпоявляется сразу в нескольких инструментах, начинайте не с переустановки пакетов и не с замены репозитория, а с проверки сетевого стека от DNS до MTU.
Как проявляется проблема
Симптомы могут немного отличаться в зависимости от клиента, но логика у них общая:
docker pullилиdocker loginзависает и завершается ошибкой таймаута;curlдолго ждёт ответ и пишет про timeout на этапе TLS;apt updateне может скачать индексы из HTTPS-репозиториев;часть сайтов открывается, а часть — нет;
по HTTP всё работает, а по HTTPS начинаются задержки или обрывы;
ошибка плавающая: утром работает, вечером нет.
Именно плавающий характер часто указывает на проблемы канала связи, перегруженный NAT, плохой аплинк, конфликт IPv4 и IPv6 или неподходящий MTU.
С чего начать: определить масштаб
Первый вопрос — проблема только в одном приложении или во всей системе. Если сбоит только Docker, это может быть локальная настройка демона, DNS внутри контейнерной подсети или proxy для сервиса Docker. Если одинаково страдают Docker, curl и apt, смотрим сеть и резолвинг на уровне хоста.
Проверьте несколько сценариев подряд: доступ к домену по DNS-имени, доступ по IPv4, попытку без IPv6, обращение к разным внешним узлам. Ваша задача — не просто воспроизвести ошибку, а найти закономерность.
curl -I -v https://deb.debian.org/
curl -4 -I -v https://deb.debian.org/
curl -6 -I -v https://deb.debian.org/
curl -I -v https://registry-1.docker.io/
apt update
docker pull hello-world
Если curl -4 работает, а обычный вызов виснет или падает, это сильный сигнал на проблемы с IPv6. Если ломаются только обращения к реестрам Docker или отдельным репозиториям, возможны вопросы к DNS, CDN-маршруту или промежуточному proxy.
Проверка времени и базового TLS-контекста
Прежде чем идти глубже, убедитесь, что на сервере корректное системное время. Сильно уехавшие часы обычно дают ошибки валидации сертификатов, а не timeout, но этот фактор лучше исключить сразу.
timedatectl status
date
Дальше полезно посмотреть, удаётся ли вообще дойти до TLS-сервера и на каком этапе происходит остановка.
openssl s_client -connect registry-1.docker.io:443 -servername registry-1.docker.io
openssl s_client -connect deb.debian.org:443 -servername deb.debian.org
Если соединение даже не устанавливается стабильно, проблема ниже TLS. Если TCP открывается, но дальше всё зависает, часто виноваты MTU, DPI, proxy или нестабильный маршрут. Если здесь всё нормально, а ошибка остаётся только в одном клиенте, уже сужаем поиск до его конфигурации.

DNS: частая причина сразу после сети
Когда администратор видит «TLS handshake timeout», он нередко пропускает DNS, потому что ошибка кажется уже «после резолвинга». Но в реальности медленный или глючный DNS часто ломает всю картину: клиент подключается к недоступному IP, долго перебирает IPv6 и IPv4, получает нестабильные ответы от локального резолвера или утыкается в timeout на стороне systemd-resolved.
Проверьте, какие серверы DNS реально используются:
resolvectl status
cat /etc/resolv.conf
getent ahosts registry-1.docker.io
getent ahosts deb.debian.org
Важно не только наличие ответа, но и его структура. Если сначала приходят AAAA-записи, а IPv6-маршрут фактически нерабочий, клиент может терять секунды на неудачные попытки. Для внешнего наблюдателя это выглядит как «Docker timeout» или «curl timeout».
Отдельно полезно сравнить результат через разные резолверы, если это допустимо в вашей инфраструктуре. Если один DNS-сервер стабильно отдаёт ответы, а другой тормозит или возвращает неполный набор записей, круг поиска резко сужается.
dig registry-1.docker.io
getent hosts registry-1.docker.io
Если используется systemd-resolved, проверьте его состояние и ошибки в журнале.
systemctl status systemd-resolved
journalctl -u systemd-resolved -n 100 --no-pager
Прокси и переменные окружения
На Debian и Ubuntu проблемы с HTTPS очень часто оказываются связаны не с интернетом как таковым, а с забытым proxy. Особенно на серверах, которые раньше работали в корпоративной сети, CI или за промежуточным кэширующим узлом. Один процесс берёт настройки из переменных окружения, другой — из системного конфига, третий — из собственного файла.
Проверьте переменные окружения:
env | grep -i proxy
Для apt дополнительно проверьте конфигурацию:
grep -R "Proxy" /etc/apt/apt.conf /etc/apt/apt.conf.d 2>/dev/null
Для Docker нужно смотреть отдельно конфигурацию сервиса и drop-in-файлы systemd.
systemctl show docker --property=Environment
systemctl cat docker
Типичный сценарий: в оболочке proxy уже убрали, curl начинает работать, а Docker-демон всё ещё пытается ходить через старый адрес. Или наоборот: apt использует proxy, который умеет HTTP, но плохо обрабатывает CONNECT для HTTPS и обрывает сессии на handshake.
Если подозреваете proxy, сравните поведение команды с окружением и без него.
env -u HTTP_PROXY -u HTTPS_PROXY -u http_proxy -u https_proxy curl -I -v https://registry-1.docker.io/
MTU и PMTU black hole: классика для TLS timeout
Одна из самых неприятных и частых причин — неправильный MTU. Это особенно характерно для серверов за туннелями, VPN, PPPoE, облачными оверлейными сетями, Docker bridge-сетями и нестандартными маршрутами. HTTPS и TLS чувствительны к этому сильнее, чем кажется: начальный обмен данными, сертификатная цепочка, расширения TLS и TCP options легко упираются в проблему фрагментации.
Если Path MTU Discovery работает плохо, а ICMP по дороге режется, соединение может выглядеть так: маленькие пакеты проходят, TCP SYN и SYN-ACK есть, DNS работает, а вот дальше handshake зависает. Это почти учебный пример для TLS handshake timeout.
Посмотрите текущий MTU интерфейсов:
ip link show
ip addr
Если сервер стоит за VPN или внутри контейнерной сети, реальные безопасные значения часто оказываются ниже стандартных 1500. Для диагностики можно временно уменьшить MTU на интерфейсе и проверить, исчезает ли проблема.
ip link set dev eth0 mtu 1400
Для Docker это особенно важно: у bridge-сети и у внешнего интерфейса может быть разный MTU, и тогда на хосте curl работает, а внутри контейнера — нет.
docker network inspect bridge
Если есть основания подозревать именно Docker-сеть, задайте MTU явно в конфигурации демона.
{
"mtu": 1400
}
Этот фрагмент должен находиться в /etc/docker/daemon.json, после чего нужен перезапуск демона:
systemctl restart docker
Подбирать значение лучше не наугад, а исходя из реального сетевого пути. Но на практике снижение до 1400 или 1450 часто быстро подтверждает гипотезу.
Если у вас несколько сайтов и сервисов крутятся на одном сервере, полезно заранее документировать сетевые параметры хоста так же тщательно, как конфиги веб-стека. Этот же подход помогает и в смежных задачах, например при разнесении пулов PHP-FPM и Nginx в разных окружениях: настройка нескольких PHP-FPM pool в Nginx.
Нестабильная сеть и потери пакетов
Если соединение то работает, то нет, не игнорируйте банальные потери пакетов и высокий джиттер. TLS сам по себе плохо переносит нестабильный старт соединения: нескольких потерянных пакетов в начале сессии уже достаточно для больших задержек, а клиент завершит попытку timeout-ошибкой.
Проверьте базовую связность и маршрут:
ping -c 20 1.1.1.1
ping -c 20 8.8.8.8
ping -c 20 deb.debian.org
mtr -rw deb.debian.org
mtr -rw registry-1.docker.io
Если на промежуточных хопах видны странности, не спешите делать вывод по одному только mtr: часть маршрутизаторов режет ICMP или занижает приоритет ответов. Но если потери видны на конечной точке или есть резкий скачок задержки на последнем участке, это уже предметный симптом.
На виртуальных машинах отдельно обращайте внимание на перегрузку хоста, burst-трафик, лимиты канала и нестабильность соседней инфраструктуры. Иногда TLS handshake timeout — это просто побочный эффект плохого сетевого качества.
IPv6: частично работает — уже проблема
Очень частая история на Debian и Ubuntu: IPv6 формально включён, адрес есть, AAAA-записи резолвятся, но внешний маршрут работает нестабильно или не работает вовсе. В результате клиенты сначала пытаются подключиться по IPv6, ждут timeout, и только потом переключаются на IPv4. Для пользователя это выглядит как долгая пауза или полная ошибка.
Проверка простая:
curl -6 -I -v https://deb.debian.org/
curl -4 -I -v https://deb.debian.org/
ping -6 -c 4 deb.debian.org
ip -6 route
Если по IPv4 всё хорошо, а по IPv6 начинаются зависания, временное отключение IPv6 для диагностики быстро показывает картину. Важно именно для диагностики: не всегда нужно отключать его навсегда, но проверить гипотезу полезно.
sysctl -w net.ipv6.conf.all.disable_ipv6=1
sysctl -w net.ipv6.conf.default.disable_ipv6=1
После теста верните настройки обратно или оформите изменение корректно через системную конфигурацию, если действительно решили отказаться от IPv6.
Почему Docker страдает особенно часто
Когда администратор видит Docker timeout, он естественно ищет проблему в registry, daemon или образе. Но Docker просто очень чувствителен к качеству сети и правильности низкоуровневых настроек.
Демон Docker работает как отдельный сервис и может использовать не те DNS или proxy-настройки, что ваша оболочка.
Контейнерные bridge-сети добавляют свой слой NAT и свой
MTU.Обращение к registry идёт к CDN и нескольким доменам, поэтому частичный DNS-сбой проявляется сильнее.
В CI/CD часто используется смешанная среда: локальный mirror, внешний proxy, ограниченный egress, кастомный firewall.
Полезный минимум для диагностики Docker выглядит так:
docker info
journalctl -u docker -n 200 --no-pager
docker run --rm alpine:3.20 sh -c "apk add --no-cache curl && curl -I -v https://registry-1.docker.io/"
Если на хосте curl работает, а в контейнере нет, почти наверняка проблема в контейнерной сети, DNS Docker или MTU bridge-интерфейса.

Особенности apt timeout
С apt ситуация похожая, но есть свои нюансы. Во-первых, пакетный менеджер может обращаться к зеркалу, которое через DNS ведёт на разные CDN-узлы. Во-вторых, в корпоративных средах для него часто задают отдельный proxy. В-третьих, некоторые ошибки выглядят как TLS timeout, хотя корень проблемы в DNS или IPv6 fallback.
Начните с подробного вывода:
apt update -o Debug::Acquire::https=true
Если подозреваете IPv6, можно временно заставить apt использовать только IPv4:
apt update -o Acquire::ForceIPv4=true
Если это помогает, проблема почти наверняка связана не с самим apt, а с маршрутизацией или DNS для IPv6.
При работе через proxy отдельно проверьте файлы в /etc/apt/apt.conf.d/. Очень часто там остаётся старая строка с Acquire::https::Proxy, о которой уже никто не помнит.
curl как универсальный тест
curl удобен тем, что позволяет быстро проверить и DNS, и IPv4/IPv6, и proxy, и стадию TLS. В большинстве случаев именно с него стоит начинать ручную диагностику.
curl -I -v https://example.org/
curl -4 -I -v https://example.org/
curl -6 -I -v https://example.org/
curl --connect-timeout 10 -I -v https://registry-1.docker.io/
Если в выводе видно, что резолвинг проходит быстро, TCP-подключение устанавливается, а зависание начинается после отправки ClientHello, это хороший кандидат на MTU, DPI, фильтрацию или неадекватный proxy.
Что смотреть в логах и пакетах
Когда базовые проверки не дали ответа, переходите к журналам и захвату трафика. Для Docker это журнал сервиса. Для DNS — логи systemd-resolved или локального резолвера. Для общего сетевого уровня — tcpdump.
journalctl -u docker -f
journalctl -u systemd-resolved -f
tcpdump -ni any host registry-1.docker.io and port 443
На что смотреть в дампе: есть ли повторные SYN, проходит ли TCP three-way handshake, уходит ли ClientHello, приходит ли ответ сервера, не видно ли постоянных retransmission. Если TCP начинается нормально, а крупные пакеты после ClientHello теряются, гипотеза про MTU только усиливается.
Практический порядок исправления
Чтобы не стрелять вслепую, удобнее идти по короткому чек-листу.
Проверить, сбой общий или только в одном инструменте.
Сравнить
curl,curl -4иcurl -6.Посмотреть DNS через
resolvectl,getentи журналы резолвера.Проверить все proxy-настройки: shell,
apt, systemd, Docker.Проверить
MTUна внешнем интерфейсе и в Docker bridge.Сделать тест с временно уменьшенным
MTU.Проверить маршрут и потери через
pingиmtr.При необходимости снять трафик через
tcpdump.
Такой порядок экономит время: сначала вы отсеиваете самые вероятные и быстрые причины, а уже потом углубляетесь в пакеты и нюансы TLS.
Типовые рабочие решения
Если собрать реальные кейсы администраторов, то чаще всего помогают не «магические» настройки TLS, а довольно приземлённые исправления:
замена нестабильного DNS-резолвера или исправление
systemd-resolved;удаление старого proxy из конфигов Docker или
apt;временное или постоянное принудительное использование IPv4;
уменьшение
MTUна внешнем интерфейсе и в Docker;исправление маршрутизации или firewall, который режет ICMP и ломает PMTUD;
устранение пакетных потерь на uplink или VPN.
Если после уменьшения MTU всё сразу оживает, не оставляйте это как «костыль без понимания». Значит, в сети есть проблема с PMTU black hole, и её стоит документировать: где именно туннель, какой реальный overhead, какие интерфейсы должны быть настроены одинаково.
Если таймаут возникает не из-за сети, а из-за реальной проблемы доверия к сертификату, дальше уже стоит отдельно разбираться с цепочкой и автоматизацией сертификатов. По этой теме может пригодиться материал про автоматизацию wildcard SSL через DNS-01. А если для проекта нужны новые SSL-сертификаты, лучше сразу закладывать корректную схему продления и проверки.
Итог
TLS handshake timeout в Debian и Ubuntu — это почти никогда не «проблема TLS сама по себе». Для Docker, curl и apt это общий симптом сетевых сбоев: нестабильный канал, плохой DNS, неверный proxy, частично сломанный IPv6, ошибочный MTU или проблема на промежуточном оборудовании.
Самая практичная стратегия — не гадать по тексту ошибки, а быстро локализовать слой, на котором начинается деградация. Сравните IPv4 и IPv6, проверьте DNS, вычистите proxy, посмотрите MTU, не поленитесь прогнать mtr и при необходимости снимите трафик. В большинстве случаев причина находится намного быстрее, чем кажется в начале.
И если нужно запомнить одну вещь из всей статьи, пусть это будет простое правило: когда одновременно проявляются Docker timeout, curl timeout и apt timeout, первым делом проверяйте не сертификаты, а сеть.


