Перейти к содержанию

2. Настройка HAProxy

Синтаксис файлов, кавычки, переменные, условия, форматы времени и размера, адреса и примеры

2.1. Формат файла конфигурации

Процесс конфигурации HAProxy включает 3 основных источников параметров:

  • аргументы из командной строки, которые всегда имеют приоритет
  • конфигурационный файл, формат которого описан здесь
  • окружение запущенного процесса, в случае если явно указаны переменные среды

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

1. a configuration file is an ordered sequence of statements

2. a statement is a single non-empty line before any unprotected "#" (hash)

3. a line is a series of tokens or "words" delimited by unprotected spaces or
   tab characters

4. the first word or sequence of words of a line is one of the keywords or
   keyword sequences listed in this document

5. all other words are all arguments of the first one, some being well-known
   keywords listed in this document, others being values, references to other
   parts of the configuration, or expressions

6. certain keywords delimit a section inside which only a subset of keywords
   are supported

7. a section ends at the end of a file or on a special keyword starting a new
   section

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

Во-первых, существуют несколько следствий из вышеуказанных правил. Правило 6 и 7 означает, что ключевые слова, используемые для определения новой секции, действительны повсюду и не могут иметь иного смысла в конкретной секции. Эти ключевые слова всегда являются одним словом (в отличие от последовательности слов), и традиционно секция, следующая за ними, обозначается тем же именем. Например, при упоминании «секции глобального уровня» имеется в виду секция конфигурации, следующая за ключевым словом “global”. Такое обозначение часто используется в сообщениях об ошибках для определения частей, которые необходимо исправить.

Некоторые секции создают внутренний объект или пространство конфигурации, которое необходимо отличать от других. В таких случаях они будут использовать дополнительное слово, устанавливающее имя этой конкретной секции. В некоторых случаях имя секции является обязательным. Например, “frontend foo” создаёт новую секцию типа “frontend” с именем «foo». Обычно имя является специфичным для своей секции, и две секции разных типов могут использовать одно и то же имя, однако это не рекомендуется, поскольку приводит к усложнению управления конфигурацией.

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

Правило 1 уточняет, что порядок имеет значение. Действительно, некоторые ключевые слова создают директивы, которые могут повторяться несколько раз, чтобы сформировать упорядоченные последовательности правил, применяемых в определённом порядке. Например, “tcp-request” может использоваться для альтернативы правил “accept” и “reject” в зависимости от критериев. Следовательно, обработчик конфигурации должен всегда сохранять порядок секции при редактировании файла. Порядок секций обычно не имеет значения, за исключением глобальной секции, которая должна располагаться перед другими секциями, но может повторяться при необходимости. Кроме того, некоторые автоматические идентификаторы могут автоматически присваиваться некоторым из создаваемых объектов (например, прокси), и при перестановке секций их идентификаторы изменяются. Такие идентификаторы отображаются, например, в статистике. Следовательно, конфигурация ниже присвоит “foo” номер идентификатора, меньший, чем у “bar”. Этот порядок будет изменён, если секции “foo” и “bar” будут переставлены:

listen foo
    bind:80

listen bar
    bind:81

Важным моментом является то, что в соответствии с правилами 2 и 3 выше, пустые строки, пробелы, табуляции и
комментарии, следующие за и не защищённым символом “#”, не входят в конфигурацию, поскольку они используются только как разделители. Это означает, что следующие конфигурации строго эквивалентны:

    global#this is the global section
daemon#daemonize
    frontend         foo
mode             http   # or tcp

и:

global
    daemon

# this is the public web frontend
frontend foo
    mode http

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

Табуляция удобна для отступов, но плохо переносится при копировании и вставке. Если вместо неё используются пробелы, рекомендуется ограничиться небольшим числом (от 2 до 4), чтобы редактирование на месте не становилось обременительным в простых редакторах без автоматических отступов.

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

2.2. Кавычки и экранирование

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

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

Если в слове требуется обратный слеш, он должен либо быть экранирован самим собой (то есть двойной обратный слеш), либо быть заключён в сильные кавычки.

Экранирование вне кавычек достигается путём предварительного размещения специального символа перед обратным слешом (’\’):

\    to mark a space and differentiate it from a delimiter
\#   to mark a hash and differentiate it from a comment
\\   to use a backslash
\'   to use a single quote and differentiate it from strong quoting
\"   to use a double quote and differentiate it from weak quoting

Кроме того, несколько непечатаемых символов могут быть выведены с помощью их обычного представления на языке C:

\n   to insert a line feed (LF, character \x0a or ASCII 10 decimal)
\r   to insert a carriage return (CR, character \x0d or ASCII 13 decimal)
\t   to insert a tab (character \x09 or ASCII 9 decimal)
\xNN to insert character having ASCII code hex NN (e.g \x0a for LF).

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

     space or tab as a word separator
'    single quote as a strong quoting delimiter
#    hash as a comment start

Слабое кавычевание позволяет интерпретировать переменные среды (которые не оцениваются вне кавычек) путем предварительного размещения перед ними знака доллара (’$’). Если требуется знак доллара внутри двойных кавычек, он должен быть экранирован с помощью обратной косынки.

Сильное кавычевание достигается путем окружения символа или последовательности символов кавычками (’’). Внутри одинарных кавычек ничего не интерпретируется, это эффективный способ кавычевания регулярных выражений.

В результате, приведена матрица, показывающая, как вводить специальные символы в различных контекстах (непечатаемые символы заменяются на их название в угловых скобках). Примечание, что некоторые символы, которые могут быть представлены только в виде экранирования, не имеют возможного представления внутри одинарных кавычек, поэтому их отсутствие там.

  Character  |  Unquoted     |  Weakly quoted              |  Strongly quoted
  -----------+---------------+-----------------------------+-----------------
    <TAB>    |  \<TAB>, \x09 |  "<TAB>", "\<TAB>", "\x09"  |  '<TAB>'
  -----------+---------------+-----------------------------+-----------------
    <LF>     |  \n, \x0a     |  "\n", "\x0a"               |
  -----------+---------------+-----------------------------+-----------------
    <CR>     |  \r, \x0d     |  "\r", "\x0d"               |
  -----------+---------------+-----------------------------+-----------------
    <SPC>    |  \<SPC>, \x20 |  "<SPC>", "\<SPC>", "\x20"  |  '<SPC>'
  -----------+---------------+-----------------------------+-----------------
    "        |  \", \x22     |  "\"", "\x22"               |  '"'
  -----------+---------------+-----------------------------+-----------------
    #        |  \#, \x23     |  "#", "\#", "\x23"          |  '#'
  -----------+---------------+-----------------------------+-----------------
    $        |  $, \$, \x24  |  "\$", "\x24"               |  '$'
  -----------+---------------+-----------------------------+-----------------
    '        |  \', \x27     |  "'", "\'", "\x27"          |
  -----------+---------------+-----------------------------+-----------------
    \        |  \\, \x5c     |  "\\", "\x5c"               |  '\'
  -----------+---------------+-----------------------------+-----------------

Пример:

# those are all strictly equivalent:
log-format %{+Q}o\ %t\ %s\ %{-Q}r
log-format "%{+Q}o %t %s %{-Q}r"
log-format '%{+Q}o %t %s %{-Q}r'
log-format "%{+Q}o %t"' %s %{-Q}r'
log-format "%{+Q}o %t"' %s'\ %{-Q}r

Существует один особый случай, когда может потребоваться второе уровневое кавычковое или экранирование. Некоторые ключевые слова принимают аргументы в скобках, иногда разделённые запятыми. Эти аргументы обычно являются целыми числами или заранее определёнными словами, но при наличии произвольных строк может потребоваться отдельное экранирование, чтобы различать символы, принадлежащие аргументу, от символов, используемых для разделения аргументов. Очень распространённый случай — это преобразователь “regsub”. Он принимает регулярное выражение в качестве аргумента, и если внутри требуется закрывающая скобка, то она должна быть экранирована отдельно.

Парсер аргументов ключевых слов идентичен верхнему уровню по вопросам кавычек, за исключением того, что экранирования \#, \$, и \xNN не обрабатываются. Однако то, что не всегда очевидно, заключается в том, что разделители внутри должны быть сначала экранированы или заключены в кавычки, чтобы они не распознавались на верхнем уровне.

Рассмотрим следующий пример, использующий преобразователь “regsub”, который принимает аргументы 3: одно регулярное выражение, строку замены и набор флагов:

# replace all occurrences of "foo" with "blah" in the path:
http-request set-path %[path,regsub(foo,blah,g)]

Здесь не требовалось специальное кавычевание. Но если сейчас мы хотим заменить либо “foo”, либо “bar” на “blah”, нам потребуется регулярное выражение “(foo|bar)”. Нельзя написать:

http-request set-path %[path,regsub((foo|bar),blah,g)]

потому что мы хотим, чтобы строка была разрезана так:

    http-request set-path %[path,regsub((foo|bar),blah,g)]
                                       |---------|----|-|
                                 arg1 _/         /    /
                                 arg2 __________/    /
                                 arg3 ______________/

но на самом деле передаётся строка между открывающей и закрывающей скобками, затем мусор:

    http-request set-path %[path,regsub((foo|bar),blah,g)]
                                       |--------|--------|
                        arg1=(foo|bar _/        /
                    trailing garbage  _________/

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

http-request set-path %[path,regsub("(foo|bar)",blah,g)]
------------ -------- ----------------------------------
   word1       word2    word3=%[path,regsub((foo|bar),blah,g)]

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

    http-request set-path %[path,regsub(\"(foo|bar)\",blah,g)]
    ------------ -------- ------------------------------------
       word1       word2    word3=%[path,regsub("(foo|bar)",blah,g)]
                                                |---------||----|-|
                                arg1=(foo|bar) _/          /    /
                                    arg2=blah  ___________/    /
                                        arg3=g _______________/

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

    http-request set-path '%[path,regsub("(foo|bar)",blah,g)]'
    ------------ --------  ----------------------------------
       word1       word2    word3=%[path,regsub("(foo|bar)",blah,g)]
                                                |---------||----|-|
                                arg1=(foo|bar) _/          /    /
                                          arg2 ___________/    /
                                          arg3 _______________/

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

    http-request set-path '%[path, regsub("(foo|bar)", blah, g)]'
    ------------ --------  --------------------------------------
       word1       word2    word3=%[path, regsub("(foo|bar)", blah, g)]
                                        |--------|---------||-----|--|
                       converter=" regsub" _/        /         /   /
                                    arg1=(foo|bar) _/         /   /
                                     arg2=" blah" ___________/   /
                                        arg3=" g" ______________/

Факт наличия пробелов вокруг запятых привел к тому, что пробелы стали частью самого поля, поэтому преобразователь " regsub" (начинающийся с пробела), который не будет найден и вызовет ошибку, но более тонко, строка замены " blah" вставит пробел в выходные данные. Хорошим правилом является никогда не вставлять ненужные пробелы внутри выражений.

При использовании регулярных выражений может возникнуть ситуация, когда символ доллара (’$’) присутствует в выражении или используется обратный слеш (’\’) в строке замены. В таком случае эти символы будут обработаны внутри двойных кавычек, поэтому предпочтительны одинарные кавычки (или двойное экранирование). Пример:

    http-request set-path '%[path,regsub("^/(here)(/|$)","my/\1",g)]'
    ------------ --------  -----------------------------------------
       word1       word2    word3=%[path,regsub("^/(here)(/|$)","my/\1",g)]
                                                |-------------| |-----||-|
                              arg1=(here)(/|$) _/               /      /
                                    arg2=my/\1 ________________/      /
                                          arg3 ______________________/

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

К сожалению, поскольку одинарные кавычки не могут быть экранированы внутри сильных кавычек, если вам нужно включить одинарные кавычки в аргумент, вам нужно экранировать или кавычить их дважды. Существует несколько способов это сделать:

http-request set-var(txn.foo) str("\\'foo\\'")
http-request set-var(txn.foo) str(\"\'foo\'\")
http-request set-var(txn.foo) str(\\\'foo\\\')

Когда в сомнении, просто не используйте кавычки вовсе, и начните обрамлять аргументы в одинарные или двойные кавычки, если они требуют запятой или закрывающей скобки, и подумайте о том, чтобы экранировать эти кавычки с помощью обратной кавычки, если строка содержит символ доллара или обратную кавычку. Опять же, это очень похоже на то, что используется в оболочке Bourne при двойной экранировке команды, передаваемой функции “eval”. Для API разработчиков, вероятно, лучше всего обрамлять каждый аргумент в экранированные кавычки, независимо от содержимого. Пользователи, скорее всего, обнаружат, что использование одинарных кавычек вокруг всего выражения и двойных кавычек вокруг каждого аргумента обеспечивает более читаемые конфигурации.

2.3. Переменные окружения

Конфигурация HAProxy поддерживает переменные среды. Эти переменные интерпретируются только в двойных кавычках. Переменные расширяются во время парсинга конфигурации. Названия переменных должны начинаться с символа доллара ("$") и, при необходимости, быть заключёнными в фигурные скобки ("{}"), как это делается в оболочке Bourne. Названия переменных могут содержать алфавитно-цифровые символы или знак подчёркивания ("_"), но не должны начинаться с цифры. Если переменная содержит список нескольких значений, разделённых пробелами, она может быть расширена как отдельные аргументы, заключив переменную в фигурные скобки и добавив суффикс ‘[*]’ перед закрывающей скобкой. Также возможно указать значение по умолчанию, которое будет использоваться при отсутствии переменной, добавив это значение после дефиса (’-’) рядом с именем переменной. Примечание: значение по умолчанию заменяет только несуществующие переменные, а не пустые.

Пример:

bind "fd@${FD_APP1}"

log "${LOCAL_SYSLOG-127.0.0.1}:514" local0 notice  # send to local server

user "$HAPROXY_USER"

Некоторые переменные определяются HAProxy, они могут использоваться в конфигурации. Эти переменные приведены в матрице ниже и классифицируются по четырём категориям:

  • используемые: переменная доступна в конфигурации, либо может быть разрешена как есть, либо использована в блоках условий или предикатах для включения или отключения некоторых фрагментов конфигурации, как описано в секции 2.4 “Conditional blocks”.

  • modifiable: переменная может быть переопределена или удалена в конфигурации через “setenv”/“unsetenv”
    keywords.

  • listed: переменная присутствует в выводе команды CLI, описанной в секции “show env” section 9.3 “Unix
    Sockets commands” руководства по управлению.

Также есть две подкатегории «master» и «worker», соответственно отмеченные ‘M’ и ‘W’ в таблице ниже, демонстрирующие различия между двумя процессами при запуске HAProxy в master-worker режиме.

  • master: переменная задана и доступна из процесса master. Следовательно, она будет отображаться в
    master CLI’s “show env” выводе и может использоваться в условных блоках или директивах для включения
    некоторых специальных настроек для master (см. примеры в секции 2.4 “Условные блоки”).

  • worker: переменная задана и доступна из процесса worker. Она будет отображаться в worker
    CLI’s “show env” (или в выводе master CLI’s “@1 show env”) и может использоваться для
    условного настройки параметров процесса worker (см. примеры из секции 2.4 “Условные блоки”).

В режиме standalone (без опции “-W” и без ключевого слова “master-worker”) процесс ведёт себя как worker,
кроме переменных “HAPROXY_MASTER_CLI” и “HAPROXY_MWORKER”, которые не определены.

Некоторые переменные помечены как недоступные и неизменяемые:

  • HAPROXY_CFGFILES
  • HAPROXY_MWORKER
  • HAPROXY_CLI
  • HAPROXY_MASTER_CLI
  • HAPROXY_LOCALPEER

При разборе конфигурации их значения не определены: они устанавливаются позднее, на этапе инициализации. Поэтому рекомендуется не использовать эти переменные в условных блоках и не ссылаться на них в директивах “setenv”/“resetenv”/“unsetenv” секции global.

Таблица ниже содержит краткое описание состояния каждой переменной для различных режимов работы:

  +---------------------------+---------+------------+-----------+
  |          variable         | usable  | modifiable |  listed   |
  |                           +---------+------------+-----------+
  |                           |  M | W  |   M  |  W  |  M  |  W  |
  +---------------------------+----+----+------+-----+-----+-----+
  | HAPROXY_STARTUP_VERSION   |  X | X  |      |     |  X  |  X  |
  | HAPROXY_BRANCH            |  X | X  |      |     |  X  |  X  |
  | HAPROXY_CFGFILES          |    |    |      |     |  X  |  X  |
  | HAPROXY_MWORKER           |    |    |      |     |  X  |  X  |
  | HAPROXY_CLI               |    |    |      |     |     |  X  |
  | HAPROXY_MASTER_CLI        |    |    |      |     |  X  |     |
  | HAPROXY_LOCALPEER         |    | X  |      |     |     |  X  |
  | HAPROXY_HTTP_LOG_FMT      |    | X  |      |  X  |     |     |
  | HAPROXY_HTTP_CLF_LOG_FMT  |    | X  |      |  X  |     |     |
  | HAPROXY_HTTPS_LOG_FMT     |    | X  |      |  X  |     |     |
  | HAPROXY_TCP_LOG_FMT       |    | X  |      |  X  |     |     |
  | HAPROXY_TCP_CLF_LOG_FMT   |    | X  |      |  X  |     |     |
  | HAPROXY_KEYLOG_FC_LOG_FMT |    | X  |      |  X  |     |     |
  | HAPROXY_KEYLOG_BC_LOG_FMT |    | X  |      |  X  |     |     |
  +---------------------------+----+----+------+-----+-----+-----+

Речь идёт о следующих переменных:

  • HAPROXY_LOCALPEER: определяется при запуске процесса и содержит имя локального однорангового узла. См. “-L” в руководстве по управлению.

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

  • HAPROXY_HTTP_LOG_FMT: содержит значение формата журнала HTTP по умолчанию, описанного в разделе 8.2.3 “Формат журнала HTTP”. Позволяет переопределить формат журнала по умолчанию без копирования всего исходного определения.

  • HAPROXY_HTTP_CLF_LOG_FMT: содержит значение формата журнала HTTP CLF по умолчанию, описанного в разделе 8.2.3 “Формат журнала HTTP”. Позволяет переопределить формат журнала по умолчанию без копирования всего исходного определения.

Пример:

# Add the rule that gave the final verdict to the log
log-format "${HAPROXY_TCP_LOG_FMT} lr=%[last_rule_file]:%[last_rule_line]"
  • HAPROXY_HTTPS_LOG_FMT: аналогичен HAPROXY_HTTP_LOG_FMT, но для формата ведения журнала HTTPS, определенного в
    секции 8.2.4 “формат ведения журнала HTTPS”.

  • HAPROXY_TCP_LOG_FMT: аналогичен HAPROXY_HTTP_LOG_FMT, но для формата ведения журнала TCP, определенного в секции
    8.2.2
    “формат ведения журнала TCP”.

  • HAPROXY_TCP_CLF_LOG_FMT: аналогичен HAPROXY_HTTP_CLF_LOG_FMT, но для TCP CLF формата ведения журнала, определенного
    в секции 8.2.2 “TCP формат ведения журнала”.

  • HAPROXY_KEYLOG_FC_LOG_FMT: содержит формат ключевого ведения журнала для фронтенда (клиентской стороны) TLS
    соединения, с ключевыми полями, разделенными переносами строк, поэтому он может быть несовместим с вашим сервером ведения журнала syslog. “tune.ssl.keylog on” обязательен.

  • HAPROXY_KEYLOG_BC_LOG_FMT: аналогичен HAPROXY_KEYLOG_FC_LOG_FMT, но для бэкенда
    (с сервера) TLS соединения. Ключевые записи разделяются переносами строк, поэтому может не быть совместимы с вашим сервером syslog. “tune.ssl.keylog on” необходим.

  • HAPROXY_MWORKER: В режиме master-worker, эта переменная устанавливается в 1.

  • HAPROXY_CLI: настроенные адреса слушателей сокета статистики каждого процесса, эти адреса
    разделяются точками с запятой.

  • HAPROXY_MASTER_CLI: В режиме master-worker, адреса слушателей главного CLI, разделённые точками с запятой.

  • HAPROXY_STARTUP_VERSION: содержит версию, использованную при запуске, в режиме master-worker это версия, использованная при запуске главного узла, даже после обновления бинарника и перезагрузки.

  • HAPROXY_BRANCH: содержит версию ветки HAProxy (например, “2.8”). В ней не содержится полная версия. Может быть полезна при миграции, если ресурсы (например, карты или сертификаты) находятся в пути, содержащем номер ветки.

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

  • .FILE: имя конфигурационного файла, который сейчас разрешается.

  • .LINE: номер строки конфигурационного файла, который сейчас разрешается, начиная с единицы.

  • .SECTION: имя секции, которая сейчас разрешается, или её тип, если секция не имеет имени (например, “global”), или пустая строка до первой секции.

Эти переменные разрешаются на месте их разрешения. Например, если используется переменная “.LINE” в директиве “log-format”, расположенной в секции по умолчанию, её номер строки будет разрешён до разбора и компиляции директивы “log-format”, поэтому этот же номер строки будет повторно использоваться последующими прокси.

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

2.4. Условные блоки

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

  • .if <condition>
  • .elif <condition>
  • .else
  • .endif

Директива “.if” вкладывает новый уровень, “.elif” остается на том же уровне, “.else” также остаётся на том же уровне, и
“.endif” закрывает уровень. Каждая “.if” должна быть завершена соответствующей “.endif”. Директива “.elif” может быть размещена только после “.if” или “.elif”, и на число “.elif” в цепочке не налагается ограничений. Можно иметь только одну “.else” на “.if” и она всегда должна находиться после “.if” или последней “.elif” блока.

Комментарии могут быть размещены на той же строке, если необходимо, после ‘#’, они будут проигнорированы. Директивы токенизируются так же, как и другие директивы конфигурации, и, следовательно, возможно использование переменных среды в условиях.

Условия также могут быть оценены при запуске с параметром -cc. См. «3. Запуск HAProxy» в документации по управлению.

Условия могут быть либо пустой строкой (в этом случае возвращается ложь), либо выражением, состоящим из любой комбинации:

  • целое нулевое значение (‘0’), всегда возвращает “false”
  • ненулевое целое значение (например, ‘1’), всегда возвращает “true”.
  • предикат, опционально за которым следует один или несколько аргументов в скобках.
  • условие, расположенное между парой скобок ‘(’ и ‘)’
  • знак восклицания (’!’), стоящий перед любым из непустых элементов выше, и который отрицает его
    статус.
  • выражения, объединённые с логическим И (’&&’), которые оцениваются слева направо до тех пор,
    пока одно из них не вернёт ложь
  • выражения, объединённые с логическим ИЛИ (’||’), которые оцениваются справа налево до тех пор,
    пока одно из них не вернёт истина

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

.if defined( HAPROXY_MWORKER )

проверит наличие переменной " HAPROXY_MWORKER " (с пробелами), и это:

.if streq("$ENABLE_SSL",     1)

сравнивает переменную окружения “ENABLE_SSL” со значением " 1" (с одним ведущим пробелом).
Причина заключается в том, что строка сначала разбивается на слова так:

   .if streq("$ENABLE_SSL",     1)
  |---|--------------------|   |--|
    1           2               3

затем применяется слабое кавычевание и разрешается переменная среды “$ENABLE_SSL” (предположим, что ENABLE_SSL=0), и, наконец, слова собираются в одну строку, разделяя их одним пробелом:

   .if streq(0, 1)
  |---|-------|--|
    1     2     3

и только тогда он интерпретируется как одно выражение. Пробел, вставленный между запятой и
“1”, остаётся частью значения аргумента, что делает этот аргумент « 1»:

   .if streq(0, 1)
  |---|-----|-|--|
    \    \    \  \_ argument2: " 1"
     \    \    \___ argument1: "0"
      \    \_______ function: "streq"
       \___________ directive: ".if"

Здесь видно, что даже если ENABLE_SSL был равен “1”, это не совпадало с " 1", поскольку строка отличалась одним пробелом.

Примечание: как объяснено в секции “2.2. Цитирование и экранирование”, хорошим правилом является никогда не вставлять ненужные пробелы внутри выражений.

Примечание, что, как в других языках, оператор И имеет приоритет над оператором ИЛИ, поэтому “A && B || C && D” оценивается как “(A && B) || (C && D)”.

Список поддерживаемых на данный момент предикатов следующий:

  • awslc_api_atleast(<ver>): возвращает true, если текущее значение awslc API не старше <ver>, иначе false. Пример: awslc_api_atleast(35)

  • awslc_api_before(<ver>): возвращает true, если текущий номер awslc API строго старше
    <ver> иначе false. Пример: awslc_api_before(26)

  • defined(<name>) : возвращает true, если переменная среды <name> существует, независимо от её
    содержимого

  • feature(<name>) : возвращает true, если функция <name> присутствует в списке функций, отчётно предоставленных “haproxy -vv” (что означает, что <name> появляется после ‘+’)

  • openssl_version_atleast(<ver>): возвращает true, если текущая версия OpenSSL не старше <ver>, в противном случае — false. Библиотеки, такие как LibreSSL, AWS-LC и WolfSSL, также предоставляют псевдо-версию OpenSSL. Пример:

ssllib_name_startswith(OpenSSL) && openssl_version_atleast(1.1.1)
  • openssl_version_before(<ver>): возвращает true, если текущая версия OpenSSL строго старше <ver>, иначе false. Библиотеки, такие как LibreSSL, AWS-LC и WolfSSL, также предоставляют псевдоверсию OpenSSL. Пример: openssl_version_before(3.5.0)

  • ssllib_name_startswith(<name>) : возвращает true, если имя библиотеки HAProxy содержит SSL, начинается с <name>. Пример: ssllib_name_startswith(wolfSSL)

  • streq(<str1>,<str2>) : возвращает true только в случае равенства двух строк

  • strneq(<str1>,<str2>): возвращает true только если две строки различаются

  • strstr(<str1>,<str2>): возвращает true только если вторая строка содержится в первой.

  • version_atleast(<ver>): возвращает true, если текущая версия HAProxy не старше <ver>, в противном случае — false. Синтаксис версии совпадает с тем, что показано командой “haproxy -v”, отсутствующие компоненты считаются равными нулю.

  • version_before(<ver>): возвращает true, если текущая версия HAProxy строго старше
    <ver> в противном случае — false. Синтаксис версии соответствует тому, что показывает “haproxy -v” и отсутствующие компоненты считаются нулевыми.

  • enabled(<opt>) : возвращает true, если опция <opt> включена на этапе запуска. Поддерживаются только часть опций:

POLL, EPOLL, KQUEUE, EVPORTS, SPLICE,
GETADDRINFO, REUSEPORT, FAST-FORWARD,
SERVER-SSL-VERIFY-NONE

Пример:

# 1. HAPROXY_MWORKER variable is set automatically by HAProxy in master and
# in worker process environments (see HAProxy variables matrix from
# 2.3. Environment variables). Its presence enables an additional listener.

global
  master-worker

.если определено(HAPROXY_MWORKER) слушать mwcli_px привязка:1111 … .конецесли

# 2. HAPROXY_BRANCH is set automatically by HAProxy in master and in worker
# process environments (see HAProxy variables matrix from 2.3. Environment
# variables). We check HAPROXY_BRANCH value and conditionally enable
# mworker-max-reloads parameter.

global
  master-worker

.если streq("$HAPROXY_BRANCH",3.1) mworker-max-reloads 5 .конец

# 3. Some arbitrary environment variables are set by user in the global
# section. If HAProxy is started in master-worker mode, they are presented in
# master and in worker process environments. We check values of these
# variables and conditionally enable ports 80 and 443. Environment variables
# checks can be mixed with features and version checks.

global
  setenv WITH_SSL yes
  unsetenv SSL_ONLY

.если не равны("$SSL_ONLY",yes) привязка:80 .конец

.если streq("$WITH_SSL",yes) .если feature(OPENSSL) bind:443 ssl crt … .конецесли .конецесли

.если функция(OPENSSL) && (streq("$WITH_SSL",yes) || streq("$SSL_ONLY",yes)) привязка:443 ssl crt …
.конец

.если version_atleast(2.4-dev19) profiling.memory на .конец

.если !feature(OPENSSL) .предупреждение “поддержка SSL обязательна” .конецесли

Четыре другие директивы предоставляются для отображения некоторых состояний:

  • .diag “message” : выдавать это сообщение только при включении режима диагностики (-dD)
  • .notice “message” : выдавать это сообщение на уровне NOTICE
  • .warning “message”: выдавать это сообщение на уровне ПРЕДУПРЕЖДЕНИЕ
  • .alert “message” : выдавать это сообщение на уровне ALERT

Сообщения, выдаваемые на уровне предупреждения, могут привести к тому, что процесс не запустится, если “zero-warning” включён. Сообщения, выдаваемые на уровне ALERT, всегда приводят к критической ошибке. Эти сообщения могут быть использованы для обнаружения некоторых неправильных условий и предоставления рекомендаций пользователю.

Пример:

.if "${A}"
  .if "${B}"
     .notice "A=1, B=1"
  .elif "${C}"
     .notice "A=1, B=0, C=1"
  .elif "${D}"
     .warning "A=1, B=0, C=0, D=1"
  .else
     .alert "A=1, B=0, C=0, D=0"
  .endif
.else
     .notice "A=0"
.endif

.diag "WTA/2021-05-07: replace 'redirect' with 'return' after switch to 2.4"
      http-request redirect location /goaway if ABUSE

2.5. Формат времени

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

  • us: микросекунды. 1 микросекунда = 1/1000000 секунда
  • ms: миллисекунды. 1 миллисекунда = 1/1000 секунда. Это значение по умолчанию.
  • s : секунды. 1s = 1000ms
  • m : минуты. 1m = 60s = 60000ms
  • h : часы. 1h = 60m = 3600s = 3600000ms
  • d : дни. 1d = 24h = 1440m = 86400s = 86400000ms

2.6. Формат размера

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

  • k: килобайты. 1 килобайт = 1024 байт
  • m: мегабайты. 1 мегабайт = 1048576 байт
  • g: гигабайты. 1 гигабайт = 1073741824 байт

Оба формата времени и объёма требуют целых чисел; дробная запись не допускается.

2.7. Формат имён карт отображения и ACL

Возможно использовать список шаблонов для карт или ACL. Список шаблонов определяется его именем и может использоваться в разных местах конфигурации. Списки шаблонов делятся на три категории в зависимости от формата имени:

  • Списки шаблонов, основанные на регулярных файлах: это стандартный случай. Имя файла, абсолютное или относительное, используется как имя. Файл должен существовать иначе возникает ошибка. Однако он может быть пустым. Можно указывать префикс “file@”, но он не входит в идентификатор списка. Имя файла с префиксом или без него ссылается на один и тот же список шаблонов.

  • Списки шаблонов, основанные на опциональных файлах: имя файла должно предшествовать префиксу “opt@”. Существование файла является опциональным. Если файл существует, его содержимое загружается, но при отсутствии файла не сообщается об ошибке. Префикс не входит в идентификатор списка. Это означает, что для заданного имени файла опциональные файлы и регулярные файлы ссылаются на один и тот же список шаблонов.

  • Списки шаблонов, основанные на виртуальных файлах: имя служит лишь идентификатором. Оно не ссылается на какой-либо файл. Обязательно использовать префикс “virt@”. Он входит в идентификатор. Следовательно, такие списки не могут смешиваться с другими типами списков.

Виртуальные файлы полезны при полной динамической управлении шаблонами без шаблонов при запуске и при перезагрузке. Опциональные файлы могут использоваться при таких условиях. Однако шаблоны могут сохраняться в файле через внешний скрипт, основанный на команде “show map” CLI, например. Таким образом, возможно сохранять шаблоны при перезагрузке.

Примечание: Даже если это маловероятно, это означает, что регулярные файлы, начинающиеся с “file@”, “opt@” или “virt@”, не могут быть загружены, кроме добавления “./” в начало имени файла (например, “file@./virt@map”).

2.8. Переменные

В конфигурации HAProxy переменные могут использоваться в функциях извлечения образца, преобразователях, log-format
строках или TCP/HTTP действиях. Переменные, охватывающие весь процесс, могут быть определены и доступны во всём жизненном цикле процесса. Некоторые из них имеют более короткий срок существования. Переменные схожи с теми, что встречаются в скриптах на языке shell. Это символическое имя для фрагмента памяти. Размер переменной не ограничен и динамически выделяется. Поэтому их следует использовать с осторожностью, особенно при интенсивном использовании. Однако возможно ограничить максимальное количество памяти, используемое переменными, задав “tune.vars” глобальные параметры.

Переменные должны обозначаться в формате “<scope>.<name>”. Часть <scope> указывает на срок жизни переменной. Часть <name>, находящаяся в области, может содержать только символы ‘a-z’, ‘A-Z’, ‘0-9’ и ‘_’. Она уникальна в этой области, но одинаковое имя в разных областях может использоваться и относится к разным переменным. Поддерживаемые области:

  • proc : для переменных, известных на протяжении всего жизненного цикла процесса и доступных глобально. Переменные “proc” могут быть изменены с помощью CLI с помощью команд “get var” и “set var”. Они также могут быть установлены в секциях “global” с помощью директив “set-var” и “set-var-fmt”.

  • sess : для переменных, известных на протяжении всего жизненного цикла сессии. Переменные “sess” являются приватными для сессии, недоступными снаружи и не делятся между сессиями.

  • txn : для переменных, известных на протяжении всего жизненного цикла транзакции. Переменные “txn” являются приватными для потока, недоступными снаружи и не делятся между потоками.

  • req : для переменных, известных в процессе обработки запроса для конкретного потока. Переменные “req” доступны с момента создания потока и до первого попытки соединения с сервером. Они являются приватными для потока, недоступными снаружи и не делятся между потоками. Между переменными “req” и “res” нет пересечений вовсе.

  • res : для переменных, известных во время обработки ответа для конкретного потока. Переменные “res” видны с первого попытки соединения с сервером и до уничтожения потока. Они являются приватными для потока, недоступными снаружи и не делятся между другими потоками. Между переменными “req” и “res” нет никакого пересечения.

  • check: для переменных, известных во время выполнения проверки работоспособности. “check” переменные являются приватными для проверки работоспособности, недоступными снаружи и не делятся между другими проверками работоспособности. Их можно задавать с помощью специализированных “tcp-check” или “http-check” директив.

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

  • psess: то же, что и “sess”, но с использованием сессии родительского потока, если такой имеется.

  • ptxn : то же, что и “txn”, но с использованием транзакции родительского потока, если такой имеется.

  • preq : то же, что и “req”, но с использованием родительского потока, если такой имеется. Переменные “preq” доступны только во время обработки запроса родительского потока.

  • pres : то же, что и “res”, но с использованием родительского потока, если такой имеется. Переменные “pres” доступны только во время обработки ответа родительского потока.

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

Содержимое переменной является результатом оценки выражения извлечения образца и наследует тип вывода этого выражения. Это важно при использовании переменной, поскольку её тип должен быть совместим с её применением. Например, переменная, содержащая строку, используемая в “add()” преобразователе, должна быть преобразуема в действительное целое число для успешного выполнения. Это особенно актуально при сравнении переменных с статическими значениями. Должен быть использован правильный метод соответствия.

2.9. Форматы адресов

Несколько утверждений в виде «bind», «server», “nameserver” и “log” требует адреса.

Этот адрес может быть доменным именем, IPv4-адресом, IPv6-адресом или ‘’. Адрес ‘’ равен специальному адресу “0.0.0.0” и может использоваться при “bind” или “dgram-bind” для прослушивания всех IPv4-адресов system.The; эквивалент IPv6 — ‘::’.

В зависимости от утверждения, после адреса IP следует порт или диапазон портов. Это обязательное требование для утверждения ‘bind’, необязательное для утверждения ‘server’.

Этот адрес также может начинаться со слэша ‘/’. Он считается из семейства “unix”, и ‘/’ и последующие символы должны быть указаны как путь.

Тип сокета или метод передачи по умолчанию “datagram” или “stream” зависит от конфигурации, указанной для адреса. В самом деле, ‘bind’ и ‘server’ будут использовать тип сокета “stream” по умолчанию, в то время как ’log’, ’nameserver’ или ‘dgram-bind’ будут использовать тип “datagram”.

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

2.9.1. Префиксы семейств адресов

‘abns@<name>’ после <name> следует абстрактное пространство имен (для Linux только).

‘abnsz@<name>’ после <name> — это нулевое завершающее абстрактное пространство имен (для Linux только).

‘fd@<n>’ после адреса — это файловый дескриптор <n>, наследуемый от родительского процесса. Дескриптор должен быть привязан и может быть уже слушающим или нет.

‘ip@<address>[:port1[-port2]]’ после <address> считается адресом IPv4 или IPv6 в зависимости от синтаксиса. В зависимости от используемого в этом случае утверждения, может быть указан порт или диапазон портов, и это может быть обязательно или не обязательно.

‘ipv4@<address>[:port1[-port2]]’ после <address> всегда считается адресом IPv4. В зависимости от используемого в этом случае утверждения, может быть указан порт или диапазон портов, и это может быть обязательно или не обязательно.

‘ipv6@<address>[:port1[-port2]]’ после <address> всегда считается адресом IPv6. В зависимости от используемого в этом случае утверждения, может быть указан порт или диапазон портов, и это может быть обязательно или не обязательно.

‘sockpair@<n>’ следующий дескриптор — это дескриптор файла подключённого Unix-сокета или сокет-пары. В ходе соединения инициатор создаёт пару подключённых сокетов и передаёт один из них через дескриптор другому концу. Слушатель ожидает получение дескриптора от Unix-сокета и использует его, как если бы это был дескриптор соединения accept(). Должен использоваться с осторожностью.

           Ошибки: Этот протокол известен как нестабильный на macOS из-за недостатка в реализации функции sendmsg(2) в macOS. Соединение может не быть корректно принято.

‘unix@<path>’ следующая строка считается сокетом UNIX <path>. этот префикс полезен для объявления пути сокета UNIX, который не начинается слешом ‘/’.

2.9.2. Префиксы типов сокетов

Предыдущие префиксы “адресных семей” также могут быть приставлены для принудительного выбора типа сокета и метода передачи. По умолчанию значение определяется соответствующим утверждением, однако в некоторых случаях пользователь может принудительно задать другое значение. Это касается утверждения “log”, где по умолчанию используется syslog через UDP, но возможно принудительное использование syslog через TCP.

Эти префиксы были разработаны для внутреннего использования и пользователи должны вместо этого использовать алиасы секции “2.9.3 Протокольные префиксы”. Однако такие префиксы могут быть удобны в определённых случаях, например, при использовании наследуемых сокетов, известных по их номеру файлового описателя, в котором адресная семья равна “fd”, а тип сокета должен быть указан явно.

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

‘stream+<family>@<address>’ задаёт тип сокета и метод передачи к “stream”.

‘dgram+<family>@<address>’ задаёт тип сокета и метод передачи к “datagram”.

‘quic+<family>@<address>’ задаёт тип сокета к “datagram” и метод передачи к “stream”.

2.9.3. Префиксы протоколов

‘quic4@<address>[:port1[-port2]]’ следующий <address> всегда считается IPv4-адресом, но тип сокета принудительно устанавливается в “datagram”, а метод транспорта — в “stream”. В зависимости от утверждения, использующего этот адрес, может или должен быть указан порт или диапазон портов UDP. Эквивалентно “quic+ipv4@”.

‘quic6@<address>[:port1[-port2]]’ после <address> всегда считается как IPv6-адрес, но тип сокета вынужден быть “datagram”, а метод передачи — “stream”. В зависимости от используемого в этом адресе утверждения, может или должно быть указано UDP порт или диапазон портов. Это эквивалентно “quic+ipv6@”.

’tcp@<address>[:port1[-port2]]’ следующее <address> считается адресом IPv4 или IPv6
в зависимости от синтаксиса, но тип сокета и метод передачи вынуждены быть “stream”. В зависимости от
используемого утверждения с этим адресом, может или должно указываться порт или диапазон портов. Оно считается алиасом ‘stream+ip@’.

’tcp4@<address>[:port1[-port2]]’ после <address> всегда считается как IPv4-адрес
но тип сокета и метод передачи вынуждены быть “stream”. В зависимости от используемого в этом случае утверждения, может или должно быть указано порт или диапазон портов. Рассматривается как алиас ‘stream+ipv4@’.

’tcp6@<address>[:port1[-port2]]’ после <address> всегда считается как IPv6-адрес
но тип сокета и метод передачи вынуждены быть “stream”. В зависимости от используемого в этом случае утверждения, может или должно быть указано порт или диапазон портов. Рассматривается как алиас ‘stream+ipv4@’.

‘mptcp@<address>[:port1[-port2]]’ после <address> считается как IPv4 или IPv6-адрес в зависимости от синтаксиса, но тип сокета и метод передачи вынуждены быть “stream”, с протоколом MPTCP. В зависимости от используемого в этом случае утверждения, может или должно быть указано порт или диапазон портов.

‘mptcp4@<address>[:port1[-port2]]’ после <address> всегда считается адресом IPv4, но тип сокета и метод передачи вынуждены быть “stream”, с протоколом MPTCP.
В зависимости от используемого в этом адресе утверждения, может или должно быть указано порт или диапазон портов.

‘mptcp6@<address>[:port1[-port2]]’ после <address> всегда считается адресом IPv6, но тип сокета и метод передачи вынуждены быть “stream”, с протоколом MPTCP.
В зависимости от используемого в этом адресе утверждения, может или должно быть указано порт или диапазон портов.

‘udp@<address>[:port1[-port2]]’ после <address> считается адресом IPv4 или IPv6 в зависимости от синтаксиса, но тип сокета и метод передачи вынуждены быть “datagram”. В зависимости от используемого в этом адресе утверждения, может или должно быть указано порт или диапазон портов. Оно считается алиасом ‘dgram+ip@’.

‘udp4@<address>[:port1[-port2]]’ после <address> всегда считается адресом IPv4, но тип сокета и метод передачи вынуждены быть “datagram”. В зависимости от используемого в этом адресе утверждения, может или должно быть указано порт или диапазон портов. Оно считается алиасом ‘dgram+ipv4@’.

‘udp6@<address>[:port1[-port2]]’ после <address> всегда считается адресом IPv6, но тип сокета и метод передачи вынуждены быть “datagram”. В зависимости от используемого в этом адресе утверждения, может или должно быть указано порт или диапазон портов. Оно считается алиасом ‘dgram+ipv4@’.

‘uxdg@<path>’ после строки считается unix-сокетом <path>, но метод передачи вынужден быть “datagram”. Оно считается алиасом ‘dgram+unix@’.

‘uxst@<path>’ после строки считается unix-сокетом <path>, но метод передачи вынужден быть “stream”. Оно считается алиасом ‘stream+unix@’.

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

2.10. Примеры

# Simple configuration for an HTTP proxy listening on port 80 on all
    # interfaces and forwarding requests to a single backend "servers" with a
    # single server "server1" listening on 127.0.0.1:8000
    global
        daemon
        maxconn 256

    defaults
        mode http
        timeout connect 5000ms
        timeout client 50000ms
        timeout server 50000ms

    frontend http-in
        bind *:80
        default_backend servers

    backend servers
        server server1 127.0.0.1:8000 maxconn 32


    # The same configuration defined with a single listen block. Shorter but
    # less expressive, especially in HTTP mode.
    global
        daemon
        maxconn 256

    defaults
        mode http
        timeout connect 5000ms
        timeout client 50000ms
        timeout server 50000ms

    listen http-in
        bind *:80
        server server1 127.0.0.1:8000 maxconn 32

Предполагая, что HAProxy находится в $PATH, проверяйте эти конфигурации в терминале с:

$ sudo haproxy -f configuration.conf -c