Диагностика времени ответа web-сервера по HTTPS с помощью curl если он защищен сервисом Cloudflare

Если Ваш web-сервер защищен с помощью сервиса Cloudflare и периодически при открытии сайта появляется ошибка Error 524: A timeout occurred, то для диагностики проблемы можно легко найти официальную статью Error 524: A timeout occurred в которой описывается причина этой ошибки и как тестировать время ответа Вашего web-сервера. Но статья описывает только вариант тестирования по HTTP и не затрагивает особенностей тестирования при HTTPS соединениях и как раз в этом случае могу возникать сложности.

В своей заметке я постараюсь быстро рассказать особенности тестирования времени ответа web-сервера с помощью curl при HTTPS соединениях.

Исходные данные: Debian 9.9 + nginx 1.15.5 + curl 7.52.1
Задача: Протестировать время ответа web-сервера по HTTPS с помощью curl если он защищен сервисом Cloudflare

В моем случае вся связь по цепочке «Браузер клиента» -> «Сервера Cloudflare» -> «Мой web-сервер» идет только с использованием HTTPS, то есть в панели dash.cloudflare.com на странице SSL режим «Modes of Operation» стоит «Full SSL», более детально о режимах читайте на этой странице, а если кратко, то картинка ниже все проиллюстрирует:

Cloudflare Full SSL

Итак, первым шагом мы должны убедиться, что у нас свежая версия консольной утилиты curl, нам нужна версия выше 7.18.1 т.к. именно с этой версии есть поддержка расширения SNI. Если Вы захотите тестировать кластер серверов, то Вам потребуется curl не ниже версии 7.49.0, т.к. именно с этой версии есть поддержка опции —connect-to (см. лог изменений curl).

Проверим версию curl:

# curl --version
curl 7.52.1 (x86_64-pc-linux-gnu) libcurl/7.52.1 OpenSSL/1.0.2r zlib/1.2.8 libidn2/0.16 libpsl/0.17.0 (+libidn2/0.16) libssh2/1.7.0 nghttp2/1.18.1 librtmp/2.3
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtmp rtsp scp sftp smb smbs smtp smtps telnet tftp
Features: AsynchDNS IDN IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL libz TLS-SRP HTTP2 UnixSockets HTTPS-proxy PSL

Отлично, в нашем дистрибутиве Debian версия 7.52.1

Теперь первым шагом мы проверяем время ответа нашего web-сервера через Cloudflare, тут все просто:

MYDOMAIN="mysite.ru"; curl -vso /dev/null -A "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3" -w "Connect: %{time_connect}\nTTFB: %{time_starttransfer}\nTotal time: %{time_total}\n" https://${MYDOMAIN}

В ответ нам будет выдано что-то подобное:

* Rebuilt URL to: https://mysite.ru/
*   Trying 104.27.189.205...
* TCP_NODELAY set
* Connected to mysite.ru (104.27.189.205) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: /etc/ssl/certs
* TLSv1.2 (OUT), TLS header, Certificate Status (22):
} [5 bytes data]
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
} [512 bytes data]
* TLSv1.2 (IN), TLS handshake, Server hello (2):
{ [96 bytes data]
* TLSv1.2 (IN), TLS handshake, Certificate (11):
{ [2209 bytes data]
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
{ [147 bytes data]
* TLSv1.2 (IN), TLS handshake, Server finished (14):
{ [4 bytes data]
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
} [70 bytes data]
* TLSv1.2 (OUT), TLS change cipher, Client hello (1):
} [1 bytes data]
* TLSv1.2 (OUT), TLS handshake, Finished (20):
} [16 bytes data]
* TLSv1.2 (IN), TLS change cipher, Client hello (1):
{ [1 bytes data]
* TLSv1.2 (IN), TLS handshake, Finished (20):
{ [16 bytes data]
* SSL connection using TLSv1.2 / ECDHE-ECDSA-AES128-GCM-SHA256
* ALPN, server accepted to use h2
* Server certificate:
*  subject: C=US; ST=CA; L=San Francisco; O=CloudFlare, Inc.; CN=sni.cloudflaressl.com
*  start date: Mar 31 00:00:00 2019 GMT
*  expire date: Mar 31 12:00:00 2020 GMT
*  subjectAltName: host "mysite.ru" matched cert's "*.mysite.ru"
*  issuer: C=US; ST=CA; L=San Francisco; O=CloudFlare, Inc.; CN=CloudFlare Inc ECC CA-2
*  SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
} [5 bytes data]
* Using Stream ID: 1 (easy handle 0x55fc957fada0)
} [5 bytes data]
> GET / HTTP/1.1
> Host: mysite.ru
> User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
> Accept: */*
>
{ [5 bytes data]
* Connection state changed (MAX_CONCURRENT_STREAMS updated)!
} [5 bytes data]
< HTTP/2 200
< date: Tue, 14 May 2019 16:51:24 GMT
< content-type: text/html; charset=UTF-8
< set-cookie: __cfduid=d13c3e9a1156e6edba1e2a13d0c30a8bd1557852684; expires=Wed, 13-May-20 16:51:24 GMT; path=/; domain=.mysite.ru; HttpOnly; Secure
< set-cookie: PHPSESSID=6a5ac8ff445b861b55e311c631e9226c; path=/; secure; HttpOnly
< expires: Thu, 19 Nov 1981 08:52:00 GMT
< cache-control: no-store, no-cache, must-revalidate
< pragma: no-cache
< x-content-type-options: nosniff
< x-xss-protection: 1; mode=block
< x-frame-options: SAMEORIGIN
< strict-transport-security: max-age=7776000; preload
< expect-ct: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
< server: cloudflare
< cf-ray: 4d6e606b9fd1bd9b-AMS
<
{ [888 bytes data]
* Curl_http_done: called premature == 0
* Connection #0 to host mysite.ru left intact
Connect: 0.068082
TTFB: 0.582591
Total time: 0.582884

Нас конечно же будет интересовать HTTP код ответа web-сервера, это строка с HTTP/2 200 — значит все хорошо.

Далее нас интересуют строки:

Connect: 0.068082
TTFB: 0.582591
Total time: 0.582884

Первая строка (Connect) — это время потраченное на соединение;

Вторая (TTFB — Time To First Byte или Время до первого байта) — время до получения первого байта (сетевого пакета) веб-страницы после отправки запроса со стороны клиента. Измерение включает DNS-запрос (разрешение имени), время подключения к web-серверу и время ожидания обработанного запроса (обработка, перепаковка, отправка страницы). Термин TTFB часто путают c временем отклика web-сервера — этот показатель дает возможность оценить скорость реакции на HTTP-запрос при отсутствии сетевой задержки. На TTFB влияет почти все: сетевые проблемы и задержки, объем входящего трафика, настройки web-сервера, объем и оптимизированность контента (качество графики, размер html/css/js), если например у вас сайт на php, то сюда же включается время ответа php-скриптов для формирования динамического контента, а если php-скрипты забирают данные из удаленной БД, то и время ответа БД так же будет участвовать в TTFB. В общем это довольно длинная цепочка зависимостей. Более детальный анализ всех стадий соединения и загрузки удобнее проводить с помощью специализированного сервиса, например webpagetest.org, но нам для наших целей сгодиться и curl

И третья строка (Total time) — это общее время.

Теперь нам нужно узнать TTFB в обход серверов Cloudflare и тут база знаний Cloudflare ответа не дает, поэтому вооружившись man curl мы найдем ответ сами, вот он:

MYDOMAIN="mysite.ru"; MYIP="185.125.231.XXX"; curl -vso /dev/null --insecure --resolve ${MYDOMAIN}:443:${MYIP} -A "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3" -w "Connect: %{time_connect}\nTTFB: %{time_starttransfer}\nTotal time: %{time_total}\n" -H "Host: ${MYDOMAIN}" https://${MYIP}

,где переменная

MYDOMAIN=mysite.ru — это наш сайт

MYIP=185.125.231.XXX — это реальный IP адрес нашего web-сервера

В ответ нам будет выдано что-то подобное:

* Added mysite.ru:443:185.125.231.XXX to DNS cache
* Rebuilt URL to: https://185.125.231.XXX/
*   Trying 185.125.231.XXX...
* TCP_NODELAY set
* Connected to 185.125.231.XXX (185.125.231.XXX) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: /etc/ssl/certs
* TLSv1.2 (OUT), TLS header, Certificate Status (22):
} [5 bytes data]
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
} [512 bytes data]
* TLSv1.2 (IN), TLS handshake, Server hello (2):
{ [103 bytes data]
* TLSv1.2 (IN), TLS handshake, Certificate (11):
{ [808 bytes data]
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
{ [333 bytes data]
* TLSv1.2 (IN), TLS handshake, Server finished (14):
{ [4 bytes data]
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
} [70 bytes data]
* TLSv1.2 (OUT), TLS change cipher, Client hello (1):
} [1 bytes data]
* TLSv1.2 (OUT), TLS handshake, Finished (20):
} [16 bytes data]
* TLSv1.2 (IN), TLS change cipher, Client hello (1):
{ [1 bytes data]
* TLSv1.2 (IN), TLS handshake, Finished (20):
{ [16 bytes data]
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* ALPN, server accepted to use h2
* Server certificate:
*  subject: C=CA; ST=None; L=NB; O=None; CN=185.125.231.XXX
*  start date: Mar 27 19:17:02 2019 GMT
*  expire date: Mar 24 19:17:02 2029 GMT
*  issuer: C=CA; ST=None; L=NB; O=None; CN=185.125.231.XXX
*  SSL certificate verify result: self signed certificate (18), continuing anyway.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
} [5 bytes data]
* Using Stream ID: 1 (easy handle 0x5580c7871da0)
} [5 bytes data]
> GET / HTTP/1.1
> Host: mysite.ru
> User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3
> Accept: */*
>
{ [5 bytes data]
* Connection state changed (MAX_CONCURRENT_STREAMS updated)!
} [5 bytes data]
< HTTP/2 200
< server: nginx
< date: Tue, 14 May 2019 16:53:18 GMT
< content-type: text/html; charset=UTF-8
< set-cookie: PHPSESSID=f1be30edfc7680d6680f0aaa2ac3725c; path=/; secure; HttpOnly
< expires: Thu, 19 Nov 1981 08:52:00 GMT
< cache-control: no-store, no-cache, must-revalidate
< pragma: no-cache
< x-content-type-options: nosniff
< x-xss-protection: 1; mode=block
< x-frame-options: SAMEORIGIN
< strict-transport-security: max-age=31557600
<
{ [3039 bytes data]
* Curl_http_done: called premature == 0
* Connection #0 to host 185.125.231.XXX left intact
Connect: 0.054492
TTFB: 0.492668
Total time: 0.493891

Время TTFB в случае прямого соединения с нашим web-сервером оказалось чуть ниже чем если соединение шло через Cloudflare, но иногда оно может быть и больше.

На этом все, до скорых встреч.

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


Хотите оставить комментарий?