Надёжная работа любого сервиса опирается на возможности системы журналирования. С помощью логов можно решить широкий спектр задач: решение проблем, аналитика поведения пользователей, расследование инцидентов безопасности, мониторинг состояния системы и другие. В этой статье посмотрим на возможности и практические приёмы для работы с логами сервера Angie.

Навигация по циклу

  1. Почему стоит переходить на Angie.

  2. Установка Angie из пакетов и в докере.

  3. Переезд с Nginx на Angie. Пошаговая инструкция.

  4. Настройка location в Angie. Разделение динамических и статических запросов.

  5. Перенаправления в Angie: return, rewrite и примеры их применения.

  6. Сжатие текста в Angie: статика, динамика, производительность.

  7. Серверное кэширование в Angie: тонкости настройки.

  8. Настройка TLS в Angie: безопасность и скорость.

  9. Настройка Angie в роли обратного HTTP‑прокси.

  10. Балансировка нагрузки для HTTP(S) в Angie.

  11. Мониторинг Angie с помощью Console Light и API.

  12. Балансировка и проксирование L4-трафика в Angie.

  13. Клиентское кэширование в Angie.

  14. Динамические группы проксируемых серверов в Angie.

  15. Мониторинг Angie с Prometheus и Grafana.

  16. Отказоустойчивый кластер Angie с VRRP и Keepalived.

  17. Контроль доступа в Angie.

  18. Аутентификация клиентов в Angie с помощью TLS‑сертификатов.

  19. Кастомизация Angie (njs, Lua, Perl).

  20. Запуск CGI‑скриптов в Angie.

  21. Защита от DoS‑атак в Angie стандартными модулями.

  22. Защита от DoS‑атак в Angie (дополнительные средства).

  23. Автоматические TLS‑сертификаты в Angie с модулем ACME.

  24. HTTP/2 и HTTP/3: настройка, достоинства и недостатки.

  25. Работа с картинками в Angie.

  26. Инструменты для бенчмарка веб‑сервера.

  27. Тест современных компрессоров для HTTP.

  28. Визуализация кастомных метрик Angie в Grafana.

  29. Влияние TLS‑библиотек и настроек на производительность.

  30. Сборка Angie из исходных кодов.

  31. Оптимизация Angie для высоких нагрузок.

  32. Логирование в Angie.

Видеоверсия

Для вашего удобства подготовлена видеоверсия этой статьи, доступна на Rutube, VKVideo и YouTube.

Журнал запросов (access_log)

Изучение логирования начнём с журнала запросов. Сразу оговоримся, что пока мы будем разбирать работу Angie в качестве HTTP‑сервера или балансировщика. Работу в режиме Stream‑модуля (TCP/UDP проксирование и балансировка) разберём в отдельном разделе.

Этап журналирования является последней фазой в процессе обработки любого запроса. Этот момент особенно важен для длительных запросов, которые могут быть в процессе обработки значительное время, при этом запись о них появится в логе только после его завершения.

При установке Angie по умолчанию мы получаем два формата логов запросов: main и extended. При этом формат main используется для записи основного журнала (как правило /var/log/angie/access_log). Посмотрим на часть стандартной конфигурации angie.conf.

http {
   log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    log_format extended '$remote_addr - $remote_user [$time_local] "$request" '
                        '$status $body_bytes_sent "$http_referer" rt="$request_time" '
                        '"$http_user_agent" "$http_x_forwarded_for" '
                        'h="$host" sn="$server_name" ru="$request_uri" u="$uri" '
                        'ucs="$upstream_cache_status" ua="$upstream_addr" us="$upstream_status" '
                        'uct="$upstream_connect_time" urt="$upstream_response_time"';

}

В этой части можно найти две директивы log_format, которые определяют содержимое форматов логов запросов. Каждый формат имеет название (main, extended) и набор полей, которые обычно определяются через встроенные переменные. Для упрощения разбора журнала по полям можно использовать разделители (например, кавычки "$http_user_agent") или маркеты в стиле ключ=значение (например, urt=“$upstream_response_time”). В Angie по умолчанию определён базовый формат лога combined, который будет использоваться, если не указано иное. 

Определение формата лога зависит от задач. Общее правило: сохранить как можно больше данных о запросах для последующего анализа. Однако, в желании сохранять эти данные мы неминуемо столкнёмся с ограничением ресурсов на хранение и передачу логов. Например, стандартный формат main имеет небольшое количество полей, достаточных для фиксации факта запроса и нескольких свойств клиента.

192.168.122.1 - - [07/Apr/2026:12:11:10 +0000] "GET / HTTP/1.1" 200 65413 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36" "-"

Однако, здесь нет информации о работе проксируемого сервера, временных метриках, также непонятно, какое доменное имя использовалось в запросе. При использовании формата extended мы получим более полные данные. Для этого изменим строку конфигурации в angie.conf на следующую:

access_log  /var/log/angie/access.log  extended;

Не забываем протестировать и обновить конфигурацию:

angie -t
systemctl reload angie

Теперь тот же запрос будет залогирован более подробно:

192.168.122.1 - - [07/Apr/2026:12:16:20 +0000] "GET / HTTP/1.1" 200 65413 "-" rt="0.039" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36" "-" h="wp.metodlab.ru" sn="wp.metodlab.ru" ru="/" u="/index.php" ucs="-" ua="unix:/run/php/php8.3-fpm.sock" us="200" uct="0.000" urt="0.039"

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

Однако, если стоит специфичная задача, может пригодиться собственный формат лога. Например, нам нужно получить в журнале тело запроса (переменная $request_body). Зададим специальный формат лога:

http {

log_format postdata '$remote_addr - $time_local - $request - $request_body';

}

Теперь нужно включить логирование таких запросов. Обычно, логировать все запросы с таким форматом не нужно. Поэтому мы можем определить директиву access_log на уровне локации.

server {
  listen 80;

  location / {
    root /var/www/html;
    access_log /var/log/angie/post.log postdata;
  }
}

В этой конфигурации мы добавили директиву access_log в локацию и она будет работать для запросов, которые попадут в неё. Но при этом, такие запросы не попадут в общий лог сервера, то есть мы переопределили логирование запросов на уровне локации. Если нужно сохранить логирование в оба журнала, добавим вторую директиву access_log:

server {
  listen 80;

  location / {
    root /var/www/html;
    access_log /var/log/angie/post.log postdata;
    access_log  /var/log/angie/access.log  extended; 
  }
}

Кстати, для серверов с несколькими сайтами можно применять разные подходы к объединению логов:

  • отдельный лог на каждый сайт;

  • общий лог сервера;

  • совмещение общего лога и отдельных по сайтам.

Первый подход позволяет разделить логи по различным директориям, упростить поиск запросов, если известен сайт. Второй вариант подходит для упрощения оценки состояния сервера в целом, особенно при поиске аномалий. Третий подход объединяет преимущества первых двух, но достигается это за счет повышенных расходов на логирование.

Помимо классической записи логов в виде строк с разделителями, можно создать формат журнала в виде JSON-сообщений. Для этого пригодится параметр escape директивы log_format:

log_format logger-json escape=json 
'{'
'"source": "angie",'
'"message":"angie log captured",'
'"time": $time_iso8601,'
'"resp_body_size": $body_bytes_sent,'
'"host": "$http_host",' 
'"address": "$remote_addr",' 
'"request_length": $request_length,'
'"method": "$request_method",' 
'"uri": "$request_uri",' 
'"status": $status,'  
'"user_agent": "$http_user_agent",' 
'"resp_time": $request_time,' 
'"upstream_addr": "$upstream_addr"'
'}';

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

Исторически логирование запросов происходило с точностью до секунд. При высокой частоте запросов этой точности будет недостаточно для определения связанных с запросом событий в системе. Начиная с версии 1.12 в Angie можно задавать собственный формат времени директивой time_format

http {
  time_format $time_ms "%Y-%m-%dT%H:%M:%S.%L%Z";
  log_format tf '$time_ms $remote_addr "$request" $status';
}

Как видно из примера, директива time_format создаёт переменную $time_ms, которая используется при определении формата лога tf, который содержит эту переменную.

Оптимизация логирования запросов

Поговорим про снижение нагрузки при журналировании. Первый приём поможет, если сервер обрабатывает статику в отдельных локациях и мы готовы пожертвовать данными об этих запросах. Для большинства веб‑приложений количество статических запросов в разы больше динамических, поэтому снижение объёма логирования будет очень заметным. Достаточно отключить логирование статических запросов. Сделать это можно следующим образом:

server {
  listen 80;

  location / {
    proxy_pass http://backend;
  }
  location /static/ {
	access_log off;
	root /var/www/html;
  }
}

В этой конфигурации мы отключили логирование запросов в location /static/, а остальные части сайта будут наследовать общий лог запросов.

Еще один метод снижения нагрузки от журналирования: буферизация и сжатие при записи в файл. Буферизация позволяет отложить запись на диск до накопления буфера, а сжатие снижает объём записи на диск (ценой расхода процессора). При включении сжатия автоматически включается буферизация. Ниже пример этих двух параметров:

access_log  /var/log/angie/access.log.gz extended gzip=3 flush=1s buffer=64k;

В этой директиве мы пишем сжатый лог (gzip со степенью 3), буфером в 64 КБ и принудительной записью раз в секунду (даже если буфер не заполнен). Минус сжатого лога — неудобство оперативного просмотра последних записей. Для этого лог нужно сначала распаковать, а потом получить последние строки. Например, так:

zcat access.log.gz | tail

Стоит заметить, что буферизацию можно использовать без сжатия, что позволяет реже сбрасывать данные на диск и создавать меньше операций блочного ввода‑вывода.

Наконец, снизить нагрузку от логирования можно настройкой условия для записи в журнал. Например, можно создать специальную переменную, которая будет индикатором нужного запроса и поставить её в условие записи лога. Например:

http {
  map $status $loggable {
	~^[3]  1;
	default 0;
  }
  access_log /var/log/angie/access-redir.log redir if=$loggable;
}

В этом примере установлена переменная $loggable, которая будет иметь значение 1, если код ответа начинается с цифры 3. Далее эта переменная используется для параметра if директивы access_log. Значения 0 или пустая строка интерпретируются как «ложь». В таком логе будут только те запросы, которые имели код ответа 3xx.

Для логов ошибок с версии 1.12 появилась возможность ограничения частоты записи сообщений (параметр rate):

error_log logs/error.log error rate=100;

Параметр rate ограничивает частоту записи сообщений в секунду, что снижает нагрузку на дисковую систему. По умолчанию это 1000 сообщений в секунду.

Если локальная работа с логами вас не устраивает, можно организовать отправку логов с помощью протокола syslog. Можно использовать как локальный сервис, так и удалённый сервер. Пример для Ubuntu 24.04:

access_log syslog:server=unix:/run/systemd/journal/socket,nohostname;

Здесь запись направлена в UNIX‑сокет rsyslogd, сообщения попадают по умолчанию в файл /var/log/syslog. В большинстве современных дистрибутивов основной системой логирования является journald со своим бинарным форматом хранения сообщений. Можно организовать запись сразу в сервис systemd‑journald:

access_log syslog:server=unix:/dev/log,nohostname extended;

В этом случае просмотреть логи можно через утилиту journalctl

journalctl -u angie

Здесь мы увидим все сообщения, связанные с systemd-юнитом angie.service. В этой части речь шла только о журнале запросов, но не менее важны сообщения об ошибках. Поговорим о них подробнее.

Журнал ошибок (error_log)

Логирование ошибок — критически важная задача для любого сервера. Поэтому, конфигурация лога ошибок директивой error_log значительно отличается от настройки лога запросов.

Так как лог ошибок должен фиксировать сообщения об ошибках в любом случае, то полностью отключить его нельзя. По умолчанию, даже если директивы error_log нет в конфигурации, будут работать следующие настройки:

error_log logs/error.log error;

Обратите внимание, что директива error_log для всего сервера указывается в контексте main. Именно в этом логе нужно искать сообщения о проблемах при старте сервера. 

Все ошибки разделяются по уровню сообщения: от самых подробных (debug) до критически важных (emerg). При указании уровня error как в примере выше мы увидим все ошибки уровня error или более важные (crit, alert, emerg). Для более полного контроля за событиями сервера желательно поставить уровень важности info или notice

error_log  /var/log/angie/error.log notice;

Это полезно при работе с различными модулями: Limit Req (ограничение частоты запросов), ACME (автоматическое получение TLS-сертификатов) и других.

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

Сократить объём логирования ошибок можно за счет отключения сообщений по поводу ненайденных файлов (ошибка 404):

server {
  log_not_found off;
}

В этом примере на уровне сайта логирование ошибок поиска файлов отключено. Здесь стоит вспомнить одну неочевидную особенность директивы try_files, которая может использоваться для условной отдачи файлов. При возникновении ошибки поиска файла в директиве try_files в лог ошибок она не попадёт.

Отладочный лог (уровень debug) предоставляет максимальную детализацию сообщений и подходит для решения отдельных проблем, но не для постоянного использования. Для активации этого уровня нужно заменить исполняемый файл, заменив символическую ссылку на angie

sudo ln -fs angie-debug /usr/sbin/angie
sudo systemctl restart angie

Нужно учитывать, что отладочный исполняемый файл будет работать медленнее обычного и количество записи сообщений в лог ошибок будет очень большим. Чтобы сократить количество отладочных сообщений можно ограничить действие лога для конкретных клиентов с помощью директивы debug_connection:

error_log logs/error.log error;
events {
  debug_connection	127.0.0.1;
}

То есть, общий лог будет иметь уровень error, а для локальных подключений будет работать отладочный лог.

Ранее формат лога ошибок не поддавался настройке, но с версии 1.12 можно поменять формат на JSON. Достаточно установить параметр format в директиве error_log:

error_log logs/error.log error format=json;

Строка лога будет иметь следующий вид:

{"time":"2026-07-20T13:27:30.723Z","level":"error","pid":3415,"tid":3415,"connection":27,"message":"open() \"/var/www/html/static/dddd3ddd\" failed","error":{"code":2,"message":"No such file or directory"},"http":{"client":"192.168.122.1","request":{"server":"angie.metodlab.ru","request_line":"GET /static/dddd3ddd HTTP/1.1","host":"192.168.122.141"}},"tags":["http","static_err"]}

Обратите внимание, что формат временной метки содержит миллисекунды.

Также начиная с версии 1.12 в Angie появилась возможность установки тегов (error_log_user_tag) на сообщения об ошибках, на основании которых можно фильтровать сообщения. Теги поддерживают переменные, их можно видеть в сообщениях лога в формате JSON. Например, можно настроить лог для выбранной локации, логируя ошибки только для протоколов HTTP/2 и HTTP/3 в отдельные файлы:

server {
	location /static/ {
        error_log /var/log/angie/error-h2.log filter=tag:h2;
		error_log /var/log/angie/error-h3.log filter=tag:h3;
		error_log_user_tag $http2;
		error_log_user_tag $http3;
    }
}

В такой конфигурации ошибки из локации /static/ будут попадать в лог /var/log/angie/error‑static.log. При настройке error_log на вложенных уровнях нужно помнить правило наследования директив: общий лог ошибок для локации /static/ уже не ведётся, если это требуется, то нужно добавить еще одну директиву error_log с нужными параметрами.

Фильтрация сообщений об ошибках может работать в различных режимах:

  • logline — по полному тексту сообщения (только для format=default);

  • message — по тексту сообщения без системной ошибки;

  • tag — по тегу, определённому директивой error_log_user_tag;

  • sourcefile — по файлу исходного кода, который породил сообщение (только для версии с отладочным логом);

  • любое поле лога — поле контекста сообщения об ошибке, например поля JSON или обычного формата (filter=client:127.0.0.1).

Различные режимы фильтрации логов ошибок значительно упростят поиск проблем в работе приложений и мониторинг систем.

Логирование TCP/UDP серверов

При работе с модулем Stream (TCP/UDP) логирование запросов по умолчанию не ведётся. Точнее сказать, что запросов в этом контексте не существует, логируются сессии. Поэтому возможности детализации логирования намного меньше, чем при работе с HTTP.

Создадим базовый лог доступа:

stream {
    log_format basic '$remote_addr [$time_local] '
                 '$protocol $status $bytes_sent $bytes_received '
                 '$session_time' "$upstream_addr";

    access_log /var/log/angie/stream-access.log basic buffer=32k;
}

Сообщения лога будут иметь следующий вид:

192.168.122.1 [20/Jan/2026:20:59:16 +0300] TCP 200 148203 134855 814.990192.168.122.142:8443
192.168.122.1 [20/Jan/2026:21:00:00 +0300] TCP 200 240 2066 0.005192.168.122.142:8443

При этом можно заметить коды статуса, напоминающие HTTP (например, 200), но это всего лишь аналогия для упрощения парсинга, варианты значений указаны в описании переменной $status.

Разбор (парсинг) логов

Анализ логов это стандартная задача для администратора сервера. Для работы с текстовыми логами отлично подходят стандартные инструменты Linux. 

Как правило удобно составить конвейер из нескольких команд фильтрации для получения нужного результата. Конкретные параметры будут зависеть от формата лога. Посмотрим несколько примеров:

awk '{print $1}' access.log | sort | uniq -c | sort -nr | head -20

Эта команда составит список 20 самых активных IP клиентов по количеству запросов.

Для формата extended можно составить регулярные выражения для поиска самых активных клиентов, формирующих медленные запросы для бэкенда (более 1 секунды) в последних записях лога:

tail -n 100000 access.log | fgrep -v 'urt="-"' | grep -P 'urt="[1-9]+' | sort | uniq -c | sort -nr | head -20

Найти и посчитать ошибки 404 (здесь поле со статусом ответа имеет номер 9):

awk '($9 ~ /404/)' access.log | awk '{print $7}' | sort | uniq -c | sort -rn

Такие и подобные им конструкции позволяют получать разнообразные данные, причём эффективность обработки довольно высока за счет применения конвейеризации. 

Итоги

Сервер Angie предоставляет широкие возможности для настройки журналирования запросов и ошибок. Грамотное использование журналов это ключевой навык администратора сервера для решения стандартных задач или реагирования на инциденты.