Прямое подключение n8n к Telegram через один прокси — это риск. Если IP попадет под блокировку или прокси «умрет», ваши воркфлоу встанут. Единственное надежное решение — создание пула прокси с балансировкой (round-robin) и автоматическим переключением при сбоях.

В этой статье я разберу настройку 3proxy в качестве балансировщика для n8n внутри Docker. Мы вылечим специфические баги: затупы на 26 секунд из-за DNS и ошибки Permission denied внутри контейнера.

Инженерное решение: Балансировка «каруселью»

Вместо того чтобы n8n ходил в сеть напрямую, мы ставим рядом локальный контейнер 3proxy. Он принимает запросы от n8n и распределяет их по пулу внешних IPv4-прокси. Если один узел падает, трафик уходит на живые.

Docker-compose: сборка стека

Не ждем финала, даем «мясо» сразу. Обратите внимание на параметр user: "0:0" — без него 3proxy не сможет работать с портами внутри контейнера.

version: '3.8'

services:
  n8n:
    image: docker.n8n.io/n8nio/n8n:latest
    container_name: n8n
    environment:
      # Направляем весь трафик n8n на наш локальный балансировщик
      - GLOBAL_HTTP_PROXY=[http://3](http://3)proxy:3128
      - GLOBAL_HTTPS_PROXY=[http://3](http://3)proxy:3128
    networks:
      - n8n_net

  3proxy:
    image: ghcr.io/z3apa3a/3proxy:latest
    container_name: 3proxy
    restart: always
    # Критично: запуск от root для доступа к портам и ресурсам внутри Docker
    user: "0:0"
    volumes:
      - ./3proxy.cfg:/etc/3proxy/3proxy.cfg
    networks:
      - n8n_net

networks:
  n8n_net:
    name: n8n_net

Шаг 1. Конфигурация 3proxy (3proxy.cfg)

Здесь мы настраиваем логику «карусели». Трафик заходит на порт 3128 и распределяется по внешним прокси. Вместо реальных данных я использую плейсхолдеры — при настройке замените их на свои.

# Режим демона и логи
daemon
log /var/log/3proxy.log D

# ВНИМАНИЕ: Фикс DNS для Docker
# Вместо 8.8.8.8 используем внутренний резолвер Docker, чтобы избежать таймаутов
nserver 127.0.0.11
nscache 65536

# Настройка пула прокси (балансировка по принципу Round-Robin)
# parent [вес] [тип] [внешний_IP] [внешний_порт] [логин] [пароль]
parent 1000 connect IP_ПРОКСИ_1 ПОРТ_1 ЛОГИН_1 ПАРОЛЬ_1
parent 1000 connect IP_ПРОКСИ_2 ПОРТ_2 ЛОГИН_2 ПАРОЛЬ_2
parent 1000 connect IP_ПРОКСИ_3 ПОРТ_3 ЛОГИН_3 ПАРОЛЬ_3

# Запуск HTTP-прокси на порту 3128 внутри контейнера
proxy -p3128 -n -a

Разбор «граблей»: Почему это не работало с первого раза

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

1. Затуп на 26 секунд (Ошибка DNS)

Проблема: Изначально в конфиге стоял nserver 8.8.8.8. Из-за особенностей маршрутизации Docker, контейнер 3proxy не мог достучаться до внешних DNS напрямую. Балансировщик ждал ответа до таймаута — ровно 26 секунд на каждый запрос. n8n в это время просто «висел».

Решение: Прописать nserver 127.0.0.11. Это стандартный IP DNS-резолвера Docker. Как только мы переключили 3proxy на него, таймауты исчезли, запросы стали летать мгновенно.

2. Ошибка "Permission denied" в логах

Проблема: По умолчанию официальный образ 3proxy запускается от неавторизованного пользователя. При попытке привязать порт или прочитать конфиг из смонтированного тома (volume) процесс падал с ошибкой прав доступа.

Решение: В docker-compose.yml в секции сервиса 3proxy жестко прописываем user: "0:0". Это дает процессу необходимые права суперпользователя внутри изолированной сети контейнера.

Дебаг: Как проверить, что «карусель» крутится

Если n8n не видит сеть, выполняем проверку по этапам в терминале сервера:

  1. Проверяем логи балансировщика:

docker compose logs --tail 20 3proxy

Если видите спам Permission denied — проверяйте наличие строки user: "0:0" в compose-файле.

  1. Проверяем связь из n8n через балансировщик:

docker compose exec n8n curl -Ivx [http://3](http://3)proxy:3128 [https://api.telegram.org](https://api.telegram.org)

Если код ответа 200 OK, значит n8n успешно видит балансировщик, а тот успешно прокидывает запрос наружу через ваш пул прокси.

Итоги

В итоге мы получили отказоустойчивый узел. Если один из внешних прокси отвалится, 3proxy автоматически перекинет запрос на следующий живой узел. Для n8n этот процесс абсолютно прозрачен — он просто шлет всё на один локальный порт и всегда получает результат.

P.S. Я профессионально занимаюсь автоматизацией бизнеса и проектированием отказоустойчивых архитектур на n8n. Если ваш проект уперся в технический потолок или вы ищете специалиста для настройки инфраструктуры под высокие нагрузки — стучитесь ко мне в Telegram. Открыт к предметному диалогу и сложным задачам.

Комментарии (3)


  1. select26
    20.04.2026 07:57

    В итоге мы получили отказоустойчивый узел. Если один из внешних прокси отвалится, 3proxy автоматически перекинет запрос на следующий живой узел.

    Игорь поясните пожалуйста, а как 3proxy поймет что "один из внешних прокси отвалится" и каков механизм исключения и включения его обратно в пул рабочих арстримов?

    Я тут прочел что "3proxy does not inherently support liveness probes"...
    Если это действительно так, то вся ваша статья не имеет никакого смысла, т.к. по сути никакой отказоустойчивости не добавляется, а наоборот снижается за счет усложнинея цепочки.
    Поясните пожалуйста?


    1. select26
      20.04.2026 07:57

      как 3proxy поймет что "один из внешних прокси отвалится" и каков механизм исключения и включения его обратно в пул рабочих арстримов?

      Прочитал про работу этого меxанизма, в частности, тут: https://github.com/3proxy/3proxy/issues/583
      Кратко:

      механизм довольно “тупой”, но предсказуемый:

      1. Parent не “выкидывается из пула” надолго
      У 3proxy нет встроенного health-check и нет состояния вида “этот parent down, не использовать 30 секунд”. Сам автор прямо писал, что исключение нерабочих parent’ов реализовывать не планирует, и что для этого нужно отдельное ПО для проверки и управления списком прокси. Рекомендуют примеры с HA-proxy.

      2. Что происходит при ошибке: parent выбирается случайно внутри своей группы по весам, и цепочка строится для нового соединения. Если выбранный parent недоступен, запрос падает на этапе установления этого соединения. При этом keep-alive / pipelined запросы в рамках уже открытого соединения используют ту же самую цепочку, а не перевыбирают parent.

      То есть логика такая:

      parent P1 умер;
      часть запросов, попавших на него, начнёт фейлиться;
      новые соединения снова будут случайно выбирать из того же набора;
      как только parent Р1 снова станет доступен, он начнёт снова успешно обслуживать трафик — без какого-либо re-enable, reload или recovery.

      Т.е. ни о какой отказоустойчивости тут речь не идет. Вы, получается, просто снижаете blast radius от упашего прокси до значения (1 / [NUM_OF_PARENTS] ): при одном parent вы теряете сервис полность. а при двух - только наполовину, и т.д.

      p.s. Использую 3proxy уже лет 8 в проде. Подумал грешным делом, что теперь это реальная замена HA ) Но нет, все на своем месте.


      Автор - посмотрите на HA-proxy. Для вашего случая - то что доктор прописал. При этом, гораздо гибче. Можно, например, использовать пул дешeвых parent и, только в случае если все они умерли, использовать пул более дорогих. При этом вы явно можете описать механизм liveness probe.


      1. chernyaevi Автор
        20.04.2026 07:57

        Спасибо за развернутый комментарий и ссылку на issue! Вы абсолютно правы, и я должен был подсветить этот момент в статье, чтобы не вводить в заблуждение термином "полная отказоустойчивость".

        Действительно, встроенной системы health-check у 3proxy нет, и логика работы при падении parent'а именно такая, как вы описали: часть запросов будет отваливаться (blast radius снижается пропорционально количеству узлов).

        В моем кейсе это решение родилось как быстрая и легковесная "заплатка" для n8n. Из-за того, что в самом n8n (на уровне узлов) настроены автоматические retry (например, 3 попытки с интервалом в пару секунд), падение запроса на мертвом parent'е компенсируется повторными попытками. n8n стучится снова, балансировщик перебирает следующий узел из пула, и запрос в итоге проходит.

        То есть, связка 3proxy (снижение радиуса поражения) + n8n retries дает приемлемую стабильность для небольших и средних воркфлоу, не требуя разворачивать тяжелую обвязку.

        Но вы абсолютно правы: для серьезного продакшена, где нельзя терять ни одного соединения и нужны умные liveness probes, HAProxy — это must-have. Забрал ваш совет в бэклог, спасибо! Буду тестировать HAProxy для более нагруженных архитектур.