GitHub открывается медленно или git clone зависает: DNS, IPv6 и MTU

, 7 мин чтения

Знакомая картина: страница репозитория грузится подозрительно долго, git clone замирает на Receiving objects, а git push то проходит, то нет. Перебои с GitHub чаще всего объясняются одной из трёх причин: DNS, IPv6 или MTU. Каждую можно проверить из терминала за несколько минут.

Сначала исключите сбой у GitHub

Прежде чем чинить свою сеть, откройте githubstatus.com. Там отдельно показано состояние Git Operations, API Requests, Actions, Packages и других компонентов. Если в списке есть инцидент, ждать полезнее, чем менять настройки.

Затем измерьте этапы запроса:

curl -o /dev/null -s -w 'dns %{time_namelookup}  connect %{time_connect}  tls %{time_appconnect}  total %{time_total}\n' https://github.com

Долгий dns указывает на резолвер. Большая разница между dns и connect говорит о задержке или потерях на маршруте. Зависание на этапе tls часто связано с MTU. Для SSH проверьте рукопожатие командой ssh -T git@github.com. Если приветствие приходит быстро, а клонирование всё равно тянется, соединения устанавливаются нормально, и проблема в передаче данных.

Причина 1: DNS

Сравните ответы системного резолвера и публичных:

dig github.com
dig @1.1.1.1 github.com
dig @8.8.8.8 github.com

Смотрите на Query time, на статус в заголовке ответа и на сами адреса. Нормальный ответ имеет статус NOERROR. Статус SERVFAIL или сообщение connection timed out; no servers could be reached означают, что резолвер не справляется, и браузер с git ждут его вместе с вами. Если системный резолвер отвечает заметно дольше публичных, смените DNS в настройках системы или роутера. Если адреса отличаются, сверьте их с официальным списком: GitHub публикует свои диапазоны IP по адресу https://api.github.com/meta, в полях web, api и git.

Частая причина странной медленной работы: старые записи в файле hosts. Когда-то их советовали добавлять вручную, а адреса GitHub с тех пор менялись. Проверьте:

grep -i github /etc/hosts

В Windows файл лежит в C:\Windows\System32\drivers\etc\hosts. Удалите записи для доменов GitHub и сбросьте кэш DNS: sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder на macOS, ipconfig /flushdns в Windows, resolvectl flush-caches в Linux с systemd-resolved.

Причина 2: IPv6 с перебоями

На момент написания основной домен github.com отдаёт только IPv4-адреса, а домены со статикой и файлами отвечают и по IPv6: github.githubassets.com со стилями и скриптами, avatars.githubusercontent.com, raw.githubusercontent.com. Проверьте сами:

dig AAAA github.com +short
dig AAAA raw.githubusercontent.com +short

Если у вашего провайдера IPv6 работает нестабильно, получается характерная картина: HTML страницы приходит быстро, а картинки, стили и скачивание сырых файлов тянутся или обрываются. Программа сначала пробует IPv6-адрес и тратит время на ожидание. Сравните оба протокола:

curl -4 -o /dev/null -s -w 'IPv4 %{time_total}\n' https://raw.githubusercontent.com/git/git/master/README.md
curl -6 -o /dev/null -s -w 'IPv6 %{time_total}\n' https://raw.githubusercontent.com/git/git/master/README.md

Если команда с -6 сразу завершается ошибкой, у вашей сети просто нет IPv6, и эта причина к вам не относится. Подозрительно другое: когда -6 подключается, но работает в разы медленнее или зависает посреди передачи. Если IPv6 заметно хуже или не работает стабильно, есть два пути. Правильный: починить IPv6 на роутере или выключить его там, пока провайдер не исправит. Точечный: заставить отдельные программы использовать IPv4.

  • curl: флаг -4.
  • SSH: в ~/.ssh/config для нужного хоста добавьте AddressFamily inet, разово используйте ssh -4.
  • git по SSH: git -c core.sshCommand="ssh -4" clone git@github.com:owner/repo.git.
  • git по HTTPS: у git fetch, git pull и git push есть флаг -4.
  • Проверка на macOS: networksetup -setv6off Wi-Fi выключает IPv6 на интерфейсе, networksetup -setv6automatic Wi-Fi возвращает настройку.

Причина 3: MTU, когда большие пакеты не проходят

MTU это максимальный размер пакета, который проходит по сети без фрагментации. В обычной сети Ethernet это 1500 байт, но туннели, PPPoE у провайдера и мобильные сети его уменьшают. Поэтому проблема часто появляется после смены роутера или провайдера, при работе через туннель или при раздаче интернета с телефона. Если маршрутизатор на пути не может передать большой пакет, он сообщает об этом отправителю ICMP-сообщением. Когда такие сообщения где-то теряются, большие пакеты просто исчезают.

Симптомы узнаваемы. Маленькие запросы работают, ssh -T git@github.com здоровается, но git clone большого репозитория зависает на нулевой скорости, страницы грузятся наполовину, а TLS-рукопожатие замирает на передаче сертификата. Проверка: отправьте пакет нужного размера с запретом фрагментации. 1472 байта данных плюс 28 байт заголовков дают ровно 1500:

ping -M do -s 1472 1.1.1.1     # Linux
ping -D -s 1472 1.1.1.1        # macOS
ping -f -l 1472 1.1.1.1        # Windows

Подойдёт любой внешний узел, который отвечает на ping: узкое место чаще всего рядом с вами, у провайдера или в туннеле, поэтому оно проявится на любом дальнем адресе. Если вместо ответа приходит сообщение, что пакет нужно фрагментировать (Message too long, Frag needed, Packet needs to be fragmented but DF set) или тишина, уменьшайте размер, пока пакеты не начнут проходить. Рабочий MTU равен найденному размеру плюс 28. В Linux то же самое автоматически покажет tracepath github.com.

Что делать дальше:

  • Уменьшите MTU интерфейса до найденного значения: sudo ip link set dev wlan0 mtu 1400 в Linux, sudo ifconfig en0 mtu 1400 на macOS, netsh interface ipv4 set subinterface "Wi-Fi" mtu=1400 store=persistent в Windows. Подставьте имя своего интерфейса, а 1400 здесь только пример.
  • Если у вас свой роутер на Linux, включите выравнивание MSS: iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu.
  • В Linux можно включить определение MTU без опоры на ICMP: sudo sysctl -w net.ipv4.tcp_mtu_probing=1.

SSH через порт 443

Если порт 22 в вашей сети работает медленно или с перебоями, GitHub официально принимает SSH на порту 443 через отдельное имя ssh.github.com. Это выручает и в корпоративных или гостевых сетях, где порт 22 закрыт: порт 443 там почти всегда открыт, потому что через него работает весь HTTPS. Проверка:

ssh -T -p 443 git@ssh.github.com

Если приветствие пришло, закрепите настройку в ~/.ssh/config:

Host github.com
  Hostname ssh.github.com
  Port 443
  User git

При первом подключении SSH спросит, доверять ли новому ключу хоста. Сверьте отпечаток с опубликованными в документации GitHub и только после этого отвечайте yes. Адреса репозиториев менять не нужно: git@github.com:owner/repo.git продолжит работать, но уже через порт 443.

HTTPS или SSH: смените транспорт

Если один способ работает с перебоями, попробуйте другой. Посмотрите текущий адрес и смените его:

git remote -v
git remote set-url origin https://github.com/owner/repo.git

Чтобы переключить все репозитории разом, используйте подмену адресов в глобальном конфиге: git config --global url."git@github.com:".insteadOf "https://github.com/". Убрать её можно командой git config --global --unset url."git@github.com:".insteadOf.

Для HTTPS полезны ещё две настройки. Если загрузка повисает без ошибки, задайте порог скорости:

git config --global http.lowSpeedLimit 1000
git config --global http.lowSpeedTime 60

С такими значениями git прервёт передачу, которая дольше 60 секунд идёт медленнее 1000 байт в секунду, и вы сможете повторить её, а не ждать бесконечно. Если промежуточный прокси плохо работает с HTTP/2, попробуйте git config --global http.version HTTP/1.1.

Если тормозит только клонирование большого репозитория, а остальное работает нормально, сократите объём передачи. git clone --depth 1 скачивает только последний коммит, а git clone --filter=blob:none получает историю без содержимого старых файлов и докачивает его по требованию. На медленном канале это часто превращает долгое клонирование в короткое.

Диагностика: GIT_TRACE и GIT_CURL_VERBOSE

Когда непонятно, на каком шаге git ждёт, включите трассировку:

GIT_TRACE=1 GIT_CURL_VERBOSE=1 git clone https://github.com/owner/repo.git
GIT_TRACE_PACKET=1 git fetch
GIT_SSH_COMMAND="ssh -v" git fetch
GIT_TRACE_PERFORMANCE=1 git status

GIT_CURL_VERBOSE показывает, к какому IP-адресу идёт подключение, по IPv4 или IPv6, и на каком этапе HTTPS всё останавливается. GIT_TRACE_PACKET выводит обмен пакетами протокола git, ssh -v показывает этапы SSH-подключения, а GIT_TRACE_PERFORMANCE время выполнения команд. Перед тем как отправить такой журнал кому-то, проверьте, что в нём нет токенов и заголовков авторизации.

Если все три проверки чистые, а соединение с GitHub по-прежнему медленное, проблема в маршруте между вашим провайдером и серверами GitHub. В этом случае помогает защищённое подключение через ближайшую к ним локацию.

Коротко

  • Начните с githubstatus.com и curl -w с разбивкой по этапам.
  • DNS: сравните dig github.com с dig @1.1.1.1 github.com, проверьте файл hosts.
  • IPv6: сравните curl -4 и curl -6, при перебоях используйте AddressFamily inet и флаг -4.
  • MTU: ping -M do -s 1472 в Linux или ping -D -s 1472 на macOS; если пакет не проходит, уменьшайте размер.
  • SSH на 443: Hostname ssh.github.com и Port 443 в ~/.ssh/config.
  • Сравните HTTPS и SSH, при зависаниях задайте http.lowSpeedLimit и http.lowSpeedTime.
  • Для подробностей: GIT_TRACE=1, GIT_CURL_VERBOSE=1, GIT_SSH_COMMAND="ssh -v".

Стабильный канал для работы

Один ключ, 20 стран, до 5 устройств на Standard. Возврат в течение 7 дней.

Все тарифы