<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Curl on DevOps Way - Практические гайды</title>
    <link>https://devopsway.ru/tags/curl/</link>
    <description>Recent content in Curl on DevOps Way - Практические гайды</description>
    <image>
      <title>DevOps Way - Практические гайды</title>
      <url>https://devopsway.ru/images/devopsway-og.png</url>
      <link>https://devopsway.ru/images/devopsway-og.png</link>
    </image>
    <generator>Hugo -- 0.164.0</generator>
    <language>ru</language>
    <lastBuildDate>Thu, 30 Jul 2026 18:13:57 +0300</lastBuildDate>
    <atom:link href="https://devopsway.ru/tags/curl/feed.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Networking 20/80, уровень 4: HTTP и TLS – протокол, на котором всё держится</title>
      <link>https://devopsway.ru/posts/networking-04-http-tls/</link>
      <pubDate>Thu, 30 Jul 2026 12:00:00 +0300</pubDate>
      <guid>https://devopsway.ru/posts/networking-04-http-tls/</guid>
      <description>Пятый уровень: анатомия HTTP-запроса и ответа, методы и статус-коды по группам, curl как инструмент диагностики, TLS-рукопожатие и сертификаты, Let&amp;#39;s Encrypt, различия HTTP/1.1/2/3. Три подвоха с собеса: 401 против 403, дебаг 502 Bad Gateway, зачем TLS внутри VPC.</description>
      <content:encoded><![CDATA[<p>Пятый из семи уровней. Соединение установлено – теперь про то, что по нему говорят. HTTP как язык, на котором общается почти весь веб, и TLS как конверт, в который этот язык заворачивается. Читать статус-коды и вывод <code>curl -v</code> как родной текст – базовый навык любого дежурного.</p>
<blockquote>
<p>&quot;HTTP – язык, на котором общается 99% веб-сервисов. TLS – конверт, в который этот язык заворачивается. DevOps должен читать HTTP как родной.&quot;</p>
</blockquote>
<hr>
<h2 id="откуда-это-пошло">Откуда это пошло</h2>
<p><strong>1991 – Tim Berners-Lee (CERN) создаёт HTTP/0.9.</strong> Одна команда: <code>GET /page.html</code>. Одно соединение – один документ. Никаких заголовков, только текст.</p>
<p><strong>1996 – HTTP/1.0 (RFC 1945).</strong> Заголовки, методы POST/HEAD, статус-коды. Каждый запрос – новое TCP-соединение (медленно).</p>
<p><strong>1997 – HTTP/1.1 (RFC 2068).</strong> Keep-alive (постоянное соединение): одно TCP-соединение для нескольких запросов. Заголовок <code>Host</code>: виртуальные хосты. До сих пор используется.</p>
<p><strong>1994 – SSL (Netscape).</strong> Kipp Hickman разрабатывает Secure Sockets Layer для безопасной передачи кредитных карт. SSL 2.0 → SSL 3.0 → TLS 1.0 (1999) → TLS 1.2 (2008) → <strong>TLS 1.3 (2018)</strong> – текущий стандарт.</p>
<p><strong>2015 – HTTP/2 (RFC 7540).</strong> Мультиплексирование: несколько запросов одновременно по одному соединению. Бинарный протокол (не текстовый). Сжатие заголовков.</p>
<p><strong>2022 – HTTP/3 (RFC 9114).</strong> Поверх QUIC (UDP), а не TCP. Установка соединения без предварительного кругового обмена (Zero-RTT).</p>
<hr>
<h2 id="http-запрос-и-ответ--анатомия">HTTP-запрос и ответ – анатомия</h2>
<h3 id="запрос">Запрос</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">GET /api/health HTTP/1.1        ← метод, путь, версия
</span></span><span class="line"><span class="cl">Host: api.example.com           ← обязательный заголовок (с HTTP/1.1)
</span></span><span class="line"><span class="cl">User-Agent: curl/7.88.1        ← кто отправляет
</span></span><span class="line"><span class="cl">Accept: application/json        ← какой формат хочу получить
</span></span><span class="line"><span class="cl">Authorization: Bearer eyJ...    ← аутентификация
</span></span><span class="line"><span class="cl">Content-Type: application/json  ← формат тела (для POST/PUT)
</span></span><span class="line"><span class="cl">                                ← пустая строка = конец заголовков
</span></span><span class="line"><span class="cl">{&#34;name&#34;: &#34;test&#34;}                ← тело (body) – только для POST/PUT/PATCH
</span></span></code></pre></div><h3 id="ответ">Ответ</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">HTTP/1.1 200 OK                 ← версия, статус-код, причина
</span></span><span class="line"><span class="cl">Content-Type: application/json  ← формат тела
</span></span><span class="line"><span class="cl">Content-Length: 27              ← размер тела в байтах
</span></span><span class="line"><span class="cl">Cache-Control: no-cache         ← не кешировать
</span></span><span class="line"><span class="cl">X-Request-Id: abc-123           ← пользовательский заголовок (трассировка)
</span></span><span class="line"><span class="cl">Set-Cookie: session=xyz         ← установить cookie
</span></span><span class="line"><span class="cl">                                ← пустая строка
</span></span><span class="line"><span class="cl">{&#34;status&#34;: &#34;healthy&#34;}           ← тело ответа
</span></span></code></pre></div><hr>
<h2 id="http-методы--20-покрывают-80">HTTP-методы – 20% покрывают 80%</h2>
<table>
	<thead>
			<tr>
					<th>Метод</th>
					<th>Что делает</th>
					<th>Идемпотентный</th>
					<th>Тело</th>
					<th>Пример</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td><strong>GET</strong></td>
					<td>Получить данные</td>
					<td>Да</td>
					<td>Нет</td>
					<td><code>GET /api/users</code></td>
			</tr>
			<tr>
					<td><strong>POST</strong></td>
					<td>Создать ресурс</td>
					<td>Нет</td>
					<td>Да</td>
					<td><code>POST /api/users</code></td>
			</tr>
			<tr>
					<td><strong>PUT</strong></td>
					<td>Заменить ресурс целиком</td>
					<td>Да</td>
					<td>Да</td>
					<td><code>PUT /api/users/42</code></td>
			</tr>
			<tr>
					<td><strong>PATCH</strong></td>
					<td>Частичное обновление</td>
					<td>Нет</td>
					<td>Да</td>
					<td><code>PATCH /api/users/42</code></td>
			</tr>
			<tr>
					<td><strong>DELETE</strong></td>
					<td>Удалить ресурс</td>
					<td>Да</td>
					<td>Нет</td>
					<td><code>DELETE /api/users/42</code></td>
			</tr>
			<tr>
					<td><strong>HEAD</strong></td>
					<td>GET без тела (только заголовки)</td>
					<td>Да</td>
					<td>Нет</td>
					<td>Проверки живости (health checks)</td>
			</tr>
			<tr>
					<td><strong>OPTIONS</strong></td>
					<td>Какие методы поддерживает URL</td>
					<td>Да</td>
					<td>Нет</td>
					<td>Предзапрос CORS (preflight)</td>
			</tr>
	</tbody>
</table>
<blockquote>
<p><strong>Идемпотентность</strong> = повторный запрос даёт тот же результат. GET <code>/users/42</code> дважды → одно и то же. POST <code>/users</code> дважды → два пользователя. Это важно для логики повторов (retry) и проектирования API.</p>
</blockquote>
<hr>
<h2 id="статус-коды--выучить-группы-не-конкретные-коды">Статус-коды – выучить группы, не конкретные коды</h2>
<table>
	<thead>
			<tr>
					<th>Группа</th>
					<th>Значение</th>
					<th>Частые коды</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td><strong>1xx</strong></td>
					<td>Информационные</td>
					<td><code>101 Switching Protocols</code> (WebSocket)</td>
			</tr>
			<tr>
					<td><strong>2xx</strong></td>
					<td>Успех</td>
					<td><code>200 OK</code>, <code>201 Created</code>, <code>204 No Content</code></td>
			</tr>
			<tr>
					<td><strong>3xx</strong></td>
					<td>Перенаправление</td>
					<td><code>301 Moved Permanently</code>, <code>302 Found</code>, <code>304 Not Modified</code></td>
			</tr>
			<tr>
					<td><strong>4xx</strong></td>
					<td>Ошибка клиента</td>
					<td><code>400 Bad Request</code>, <code>401 Unauthorized</code>, <code>403 Forbidden</code>, <code>404 Not Found</code>, <code>429 Too Many Requests</code></td>
			</tr>
			<tr>
					<td><strong>5xx</strong></td>
					<td>Ошибка сервера</td>
					<td><code>500 Internal Server Error</code>, <code>502 Bad Gateway</code>, <code>503 Service Unavailable</code>, <code>504 Gateway Timeout</code></td>
			</tr>
	</tbody>
</table>
<h3 id="коды-которые-devops-видит-каждый-день">Коды, которые DevOps видит каждый день</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">502 Bad Gateway:
</span></span><span class="line"><span class="cl">  nginx (reverse proxy) не может подключиться к backend-у
</span></span><span class="line"><span class="cl">  → backend упал, неправильный upstream, порт не слушается
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">503 Service Unavailable:
</span></span><span class="line"><span class="cl">  Сервер перегружен или на обслуживании
</span></span><span class="line"><span class="cl">  → слишком много запросов, deployment в процессе
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">504 Gateway Timeout:
</span></span><span class="line"><span class="cl">  nginx ждал ответ от backend-а, но не дождался
</span></span><span class="line"><span class="cl">  → backend тормозит, timeout слишком маленький
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">401 Unauthorized:
</span></span><span class="line"><span class="cl">  Нет или невалидный токен аутентификации
</span></span><span class="line"><span class="cl">  → протухший JWT, неправильный API key
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">403 Forbidden:
</span></span><span class="line"><span class="cl">  Аутентифицирован, но нет прав
</span></span><span class="line"><span class="cl">  → RBAC, недостаточные permissions
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">429 Too Many Requests:
</span></span><span class="line"><span class="cl">  Rate limiting
</span></span><span class="line"><span class="cl">  → слишком частые запросы, нужен backoff
</span></span></code></pre></div><hr>
<h2 id="curl--швейцарский-нож-devops">curl – швейцарский нож DevOps</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Базовый GET:</span>
</span></span><span class="line"><span class="cl">curl http://api:8080/health
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Verbose (показать ВСЁ: DNS, TCP, TLS, HTTP):</span>
</span></span><span class="line"><span class="cl">curl -v https://api.example.com/health
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Только HTTP-код:</span>
</span></span><span class="line"><span class="cl">curl -s -o /dev/null -w <span class="s2">&#34;%{http_code}&#34;</span> http://api:8080/health
</span></span><span class="line"><span class="cl"><span class="c1"># 200</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># POST с JSON:</span>
</span></span><span class="line"><span class="cl">curl -X POST http://api:8080/users <span class="se">\
</span></span></span><span class="line"><span class="cl">  -H <span class="s2">&#34;Content-Type: application/json&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">  -d <span class="s1">&#39;{&#34;name&#34;: &#34;test&#34;, &#34;email&#34;: &#34;test@example.com&#34;}&#39;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># С авторизацией:</span>
</span></span><span class="line"><span class="cl">curl -H <span class="s2">&#34;Authorization: Bearer eyJ...&#34;</span> http://api:8080/admin
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Тайминги (для диагностики латентности):</span>
</span></span><span class="line"><span class="cl">curl -w <span class="s2">&#34;\n  DNS: %{time_namelookup}s\n  TCP: %{time_connect}s\n  TLS: %{time_appconnect}s\n  TTFB: %{time_starttransfer}s\n  Total: %{time_total}s\n&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">  -o /dev/null -s https://api.example.com
</span></span><span class="line"><span class="cl"><span class="c1">#   DNS: 0.012s       ← время резолвинга</span>
</span></span><span class="line"><span class="cl"><span class="c1">#   TCP: 0.025s       ← время TCP handshake</span>
</span></span><span class="line"><span class="cl"><span class="c1">#   TLS: 0.089s       ← время TLS handshake</span>
</span></span><span class="line"><span class="cl"><span class="c1">#   TTFB: 0.102s      ← Time To First Byte (до первого байта ответа)</span>
</span></span><span class="line"><span class="cl"><span class="c1">#   Total: 0.115s</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Следовать редиректам:</span>
</span></span><span class="line"><span class="cl">curl -L http://example.com     <span class="c1"># 301 → https://example.com → 200</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Скачать файл:</span>
</span></span><span class="line"><span class="cl">curl -O https://example.com/file.tar.gz
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Игнорировать невалидный сертификат (ТОЛЬКО для отладки!):</span>
</span></span><span class="line"><span class="cl">curl -k https://self-signed.example.com
</span></span></code></pre></div><hr>
<h2 id="tls--как-работает-https">TLS – как работает HTTPS</h2>
<h3 id="tls-рукопожатие-handshake-упрощённо">TLS-рукопожатие (handshake, упрощённо)</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">Клиент                                    Сервер
</span></span><span class="line"><span class="cl">   │                                         │
</span></span><span class="line"><span class="cl">   │── ClientHello ─────────────────────────→│  &#34;Умею TLS 1.3, шифры + мой ключ (key share)&#34;
</span></span><span class="line"><span class="cl">   │                                         │
</span></span><span class="line"><span class="cl">   │←─ ServerHello + сертификат + Finished ──│  &#34;Мой ключ, серт и подпись – уже шифрованно&#34;
</span></span><span class="line"><span class="cl">   │                                         │
</span></span><span class="line"><span class="cl">   │   [Клиент проверяет сертификат:         │
</span></span><span class="line"><span class="cl">   │     - подписан доверенным CA?           │
</span></span><span class="line"><span class="cl">   │     - не просрочен?                     │
</span></span><span class="line"><span class="cl">   │     - совпадает имя домена?]            │
</span></span><span class="line"><span class="cl">   │                                         │
</span></span><span class="line"><span class="cl">   │── Finished ────────────────────────────→│  &#34;Проверил – готов&#34;
</span></span><span class="line"><span class="cl">   │                                         │
</span></span><span class="line"><span class="cl">   │═══ ШИФРОВАННЫЙ КАНАЛ (1 round-trip) ════│
</span></span><span class="line"><span class="cl">   │                                         │
</span></span><span class="line"><span class="cl">   │── GET /health HTTP/1.1 (зашифровано) ──→│
</span></span></code></pre></div><h3 id="сертификаты--что-проверяется">Сертификаты – что проверяется</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Посмотреть сертификат сервера:</span>
</span></span><span class="line"><span class="cl">openssl s_client -connect api.example.com:443 -servername api.example.com &lt;/dev/null 2&gt;/dev/null <span class="p">|</span> openssl x509 -text -noout
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Ключевые поля:</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Subject: CN=api.example.com            ← для какого домена</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Issuer: C=US, O=Let&#39;s Encrypt          ← кто выдал (CA)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Not Before: May 1 00:00:00 2024 GMT    ← начало действия</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Not After:  Jul 30 00:00:00 2024 GMT   ← конец действия (!)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Subject Alternative Name:</span>
</span></span><span class="line"><span class="cl"><span class="c1">#   DNS:api.example.com, DNS:*.example.com  ← все допустимые имена</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Проверить дату истечения:</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="p">|</span> openssl s_client -connect api.example.com:443 -servername api.example.com 2&gt;/dev/null <span class="p">|</span> openssl x509 -noout -dates
</span></span><span class="line"><span class="cl"><span class="c1"># notBefore=May  1 00:00:00 2024 GMT</span>
</span></span><span class="line"><span class="cl"><span class="c1"># notAfter=Jul 30 00:00:00 2024 GMT</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Одной командой – сколько дней до истечения:</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="p">|</span> openssl s_client -connect api.example.com:443 -servername api.example.com 2&gt;/dev/null <span class="se">\
</span></span></span><span class="line"><span class="cl">  <span class="p">|</span> openssl x509 -noout -enddate -checkend <span class="m">2592000</span>
</span></span><span class="line"><span class="cl"><span class="c1"># Certificate will expire  ← если меньше 30 дней (2592000 сек)</span>
</span></span></code></pre></div><h3 id="lets-encrypt--бесплатные-сертификаты">Let&rsquo;s Encrypt – бесплатные сертификаты</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># Получить сертификат:</span>
</span></span><span class="line"><span class="cl">certbot certonly --standalone -d api.example.com
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Автообновление (cron):</span>
</span></span><span class="line"><span class="cl"><span class="m">0</span> <span class="m">0</span> * * * certbot renew --quiet
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Сертификаты:</span>
</span></span><span class="line"><span class="cl"><span class="c1"># /etc/letsencrypt/live/api.example.com/fullchain.pem  ← сертификат + chain</span>
</span></span><span class="line"><span class="cl"><span class="c1"># /etc/letsencrypt/live/api.example.com/privkey.pem    ← приватный ключ</span>
</span></span></code></pre></div><hr>
<h2 id="http11-vs-http2-vs-http3">HTTP/1.1 vs HTTP/2 vs HTTP/3</h2>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">HTTP/1.1:
</span></span><span class="line"><span class="cl">  [TCP connect] → [TLS] → [GET /] → [response] → [GET /style.css] → [response]
</span></span><span class="line"><span class="cl">  Последовательно! Head-of-line blocking.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">HTTP/2:
</span></span><span class="line"><span class="cl">  [TCP connect] → [TLS] → [GET / + GET /style.css + GET /app.js] → [responses]
</span></span><span class="line"><span class="cl">  Мультиплексирование: все запросы одновременно по одному соединению.
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">HTTP/3 (QUIC):
</span></span><span class="line"><span class="cl">  [QUIC connect + TLS одновременно] → [requests] → [responses]
</span></span><span class="line"><span class="cl">  Поверх UDP. Нет TCP head-of-line blocking. Быстрее при потере пакетов.
</span></span></code></pre></div><hr>
<h2 id="подвохи-для-собеса">Подвохи для собеса</h2>
<h3 id="подвох-1-в-чём-разница-между-401-и-403">Подвох 1: &quot;В чём разница между 401 и 403?&quot;</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">401 Unauthorized (плохое название – на самом деле &#34;Unauthenticated&#34;):
</span></span><span class="line"><span class="cl">  &#34;Я не знаю, кто ты. Покажи удостоверение.&#34;
</span></span><span class="line"><span class="cl">  → Нет токена, или токен невалидный/просроченный
</span></span><span class="line"><span class="cl">  → Решение: залогиниться, обновить токен
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">403 Forbidden:
</span></span><span class="line"><span class="cl">  &#34;Я знаю, кто ты, но тебе сюда нельзя.&#34;
</span></span><span class="line"><span class="cl">  → Токен валидный, но у пользователя нет прав
</span></span><span class="line"><span class="cl">  → Решение: выдать роль/permission, проверить RBAC
</span></span></code></pre></div><p><strong>На собесе:</strong> &quot;401 – проблема аутентификации (кто ты?), 403 – проблема авторизации (что тебе разрешено?). Название 401 Unauthorized вводит в заблуждение – по смыслу это Unauthenticated. Часть фреймворков путают эти коды, что усложняет диагностику.&quot;</p>
<hr>
<h3 id="подвох-2-что-такое-502-bad-gateway-и-как-его-дебажить">Подвох 2: &quot;Что такое 502 Bad Gateway и как его дебажить?&quot;</h3>
<p><strong>Ответ через архитектуру:</strong></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">Клиент → nginx (reverse proxy) → backend (app)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">502 = nginx получил невалидный ответ от backend-а (или не смог подключиться)
</span></span></code></pre></div><p><strong>Чеклист:</strong></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 1. Backend жив?</span>
</span></span><span class="line"><span class="cl">curl http://backend:8080/health     <span class="c1"># из того же хоста, где nginx</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 2. Backend слушает?</span>
</span></span><span class="line"><span class="cl">ss -tlnp <span class="p">|</span> grep <span class="m">8080</span>               <span class="c1"># на хосте backend-а</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 3. Сеть между nginx и backend?</span>
</span></span><span class="line"><span class="cl">nc -zv backend <span class="m">8080</span>                 <span class="c1"># с хоста nginx</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 4. Логи nginx:</span>
</span></span><span class="line"><span class="cl">tail -f /var/log/nginx/error.log
</span></span><span class="line"><span class="cl"><span class="c1"># &#34;upstream prematurely closed connection&#34; → backend упал mid-request</span>
</span></span><span class="line"><span class="cl"><span class="c1"># &#34;connect() failed (111: Connection refused)&#34; → backend не слушает</span>
</span></span><span class="line"><span class="cl"><span class="c1"># &#34;upstream timed out (110: Connection timed out)&#34; → backend тормозит → 504</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 5. Логи backend-а:</span>
</span></span><span class="line"><span class="cl">docker logs backend --tail <span class="m">50</span>
</span></span></code></pre></div><p><strong>На собесе:</strong> &quot;502 – nginx не смог получить валидный ответ от апстрима (upstream). Причины: бэкенд упал, не слушает, файрвол блокирует, OOM-kill. Диагностика: curl к бэкенду напрямую (мимо nginx), проверка ss/netstat на бэкенде, логи nginx error.log.&quot;</p>
<hr>
<h3 id="подвох-3-зачем-нужен-tls-если-трафик-идёт-внутри-vpc">Подвох 3: &quot;Зачем нужен TLS, если трафик идёт внутри VPC?&quot;</h3>
<p><strong>Ответ:</strong></p>
<ol>
<li><strong>Соответствие требованиям</strong> – PCI DSS, HIPAA, GDPR требуют шифрование данных при передаче</li>
<li><strong>Zero Trust</strong> – модель &quot;не доверяй сети&quot;: VPC может быть скомпрометирован</li>
<li><strong>Горизонтальное перемещение (lateral movement)</strong> – закрепившийся на одном хосте атакующий может снифать незашифрованный трафик соседних сервисов</li>
<li><strong>mTLS (mutual TLS)</strong> – обе стороны предъявляют сертификат. Service mesh (Istio, Linkerd) автоматизирует это</li>
</ol>
<p><strong>На собесе:</strong> &quot;В модели Zero Trust шифрование необходимо даже внутри VPC. Service mesh решает это автоматически: Istio/Linkerd внедряют mTLS между сервисами без изменения кода. Это текущий отраслевой стандарт для K8s.&quot;</p>
<hr>
<h2 id="код-челлендж">Код-челлендж</h2>
<p><strong>Задача:</strong> выполни HTTP-диагностику:</p>
<ol>
<li>Получи HTTP-код ответа от <code>https://github.com</code> без тела (только код)</li>
<li>Измерь время DNS, TCP, TLS и TTFB для <code>https://google.com</code></li>
<li>Проверь, когда истекает TLS-сертификат <code>github.com</code></li>
<li>Отправь POST-запрос с JSON на httpbin.org: <code>curl -X POST https://httpbin.org/post -H &quot;Content-Type: application/json&quot; -d '{&quot;test&quot;:true}'</code></li>
</ol>
<details>
<summary>Решение</summary>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 1. HTTP-код:</span>
</span></span><span class="line"><span class="cl">curl -s -o /dev/null -w <span class="s2">&#34;%{http_code}\n&#34;</span> https://github.com
</span></span><span class="line"><span class="cl"><span class="c1"># 200</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 2. Тайминги:</span>
</span></span><span class="line"><span class="cl">curl -w <span class="s2">&#34;DNS:%{time_namelookup}s TCP:%{time_connect}s TLS:%{time_appconnect}s TTFB:%{time_starttransfer}s Total:%{time_total}s\n&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">  -o /dev/null -s https://google.com
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 3. Сертификат:</span>
</span></span><span class="line"><span class="cl"><span class="nb">echo</span> <span class="p">|</span> openssl s_client -connect github.com:443 2&gt;/dev/null <span class="p">|</span> openssl x509 -noout -dates
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 4. POST:</span>
</span></span><span class="line"><span class="cl">curl -X POST https://httpbin.org/post <span class="se">\
</span></span></span><span class="line"><span class="cl">  -H <span class="s2">&#34;Content-Type: application/json&#34;</span> <span class="se">\
</span></span></span><span class="line"><span class="cl">  -d <span class="s1">&#39;{&#34;test&#34;:true}&#39;</span>
</span></span></code></pre></div></details>
<hr>
<h2 id="дальше--уровень-5">Дальше → Уровень 5</h2>
<p>Ты владеешь HTTP: методы, коды, заголовки, curl для диагностики. Понимаешь TLS: рукопожатие (handshake), сертификаты, openssl для проверки. Это &quot;прикладной&quot; уровень сетей.</p>
<p>Но кто решает, КАКОЙ трафик может пройти, а какой – нет? Файрвол. В Linux – iptables/nftables. В облаках – Security Groups. В K8s – NetworkPolicy. Сетевая безопасность – следующий слой.</p>
<p><strong>→ Уровень 5: Firewall и сетевая безопасность</strong></p>
]]></content:encoded>
    </item>
  </channel>
</rss>
