GitHub открывается медленно или git clone зависает: DNS, IPv6 и MTU
Знакомая картина: страница репозитория грузится подозрительно долго, 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 statusGIT_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".