Прокси в Docker: настройка через контейнер, сеть и переменные окружения — пошаговый гайд
Содержание статьи
- Введение: что вы получите и кому пригодится этот гайд
- Предварительная подготовка: инструменты, доступы и системные требования
- Базовые понятия: как устроен docker и где в нем живет прокси
- Шаг 1: проверяем docker и готовим данные прокси
- Шаг 2: настраиваем прокси для одного контейнера через переменные окружения
- Шаг 3: настраиваем прокси для docker-клиента, чтобы переменные передавались автоматически
- Шаг 4: настраиваем прокси для docker-демона, чтобы образы скачивались через прокси
- Шаг 5: настраиваем прокси в docker compose
- Шаг 6: настраиваем прокси на уровне сети через контейнер-шлюз
- Проверка результата: чек-лист работающего прокси в docker
- Типичные ошибки при настройке прокси в docker и их решения
- Дополнительные возможности для продвинутых: прозрачное проксирование, ротация ip и безопасность
- Faq: частые вопросы о настройке прокси в docker
- Заключение: что вы сделали и куда двигаться дальше
Docker давно стал стандартом для запуска парсеров, ботов, рекламных автоматизаций и небольших сервисов. Но у контейнеров есть особенность: они живут в изолированной среде и ничего не знают о прокси, которые вы настроили на своем компьютере. В результате скрипт внутри контейнера выходит в интернет с вашего реального IP, а вы думаете, что работаете через мобильный прокси. Это руководство закрывает этот пробел раз и навсегда.
Введение: что вы получите и кому пригодится этот гайд
После прохождения инструкции вы будете уметь настраивать прокси в Docker на всех трех уровнях, где это вообще возможно: для отдельного контейнера через переменные окружения, для всего Docker-клиента и демона через конфигурационные файлы, а также на уровне сети через отдельный контейнер-шлюз. Вы поймете, чем эти уровни отличаются, когда какой использовать и как убедиться, что трафик действительно идет через прокси, а не мимо него.
Для кого этот пошаговый гайд
- Маркетологи и SMM-специалисты, которые запускают в Docker сервисы автопостинга, аналитики или мониторинга и хотят, чтобы каждый инструмент работал со своим мобильным IP.
- Арбитражники, у которых десятки контейнеров с трекерами, парсерами офферов и спай-сервисами, и каждому нужен отдельный гео.
- Разработчики, которым надо протестировать приложение из другого региона или прогнать интеграционные тесты через прокси.
- Владельцы бизнеса, чьи сотрудники или подрядчики разворачивают инфраструктуру в контейнерах, и нужно понимать, как там устроена работа с прокси.
Что нужно знать заранее
Мы не предполагаем глубоких знаний. Достаточно, если вы умеете открыть терминал, скопировать команду и прочитать, что она вывела. Если вы никогда не работали с Docker, не пугайтесь: в разделе с базовыми понятиями мы объясним все термины простым языком. Kubernetes, оркестрацию кластеров и облачные платформы мы сознательно не трогаем: это отдельная тема, и здесь мы остаемся строго на уровне Docker.
Сколько времени потребуется
На полное прохождение с проверками уйдет от 60 до 120 минут. Если вам нужен только один сценарий, например прокси для одного контейнера, хватит 15 минут. Если Docker еще не установлен, добавьте 20–30 минут на установку.
Предварительная подготовка: инструменты, доступы и системные требования
Прежде чем настраивать прокси в Docker, соберите все необходимое. Так вы не будете отвлекаться на поиски логина или установку утилит посреди процесса.
Что понадобится
- Компьютер или сервер с Docker. Подойдет Linux (Ubuntu 22.04 или 24.04, Debian 12), macOS с Docker Desktop или Windows 10/11 с Docker Desktop и WSL2. В 2026 году актуальны Docker Engine версии 27 и выше и Docker Compose v2, который вызывается командой docker compose (через пробел, без дефиса).
- Данные мобильного прокси. Вам нужны четыре вещи: адрес хоста (IP или доменное имя), порт, логин и пароль. Их вы найдете в личном кабинете провайдера. Также уточните, какой протокол доступен: HTTP или SOCKS5. У большинства провайдеров мобильных прокси, включая mobileproxy.space, есть оба варианта на разных портах.
- Терминал. На Linux и macOS он встроен. На Windows используйте PowerShell или терминал WSL2 (второй вариант удобнее, потому что команды будут идентичны Linux).
- Текстовый редактор. Любой: nano, vim, VS Code, Notepad++. Нужен для правки конфигурационных файлов.
- Утилита curl. Обычно уже установлена. Она поможет проверять, через какой IP выходит трафик.
Системные требования
- Минимум 2 ГБ оперативной памяти и 10 ГБ свободного места на диске для Docker и образов.
- Права администратора: на Linux это доступ к sudo, на Windows и macOS — учетная запись администратора для установки Docker Desktop.
- Стабильное интернет-соединение для скачивания образов.
Резервные копии
В процессе мы будем редактировать файлы конфигурации Docker. Ошибка в них может привести к тому, что Docker не запустится. Поэтому перед правкой любого файла делайте копию. На Linux это одна команда:
sudo cp /etc/docker/daemon.json /etc/docker/daemon.json.bakАналогично для файла ~/.docker/config.json. Если файла еще нет, создавать резервную копию не нужно, но запишите себе, что вы его создали с нуля: тогда для отката его достаточно просто удалить.
Совет: Заведите текстовый файл с шаблоном ваших прокси-данных в формате protocol://login:password@host:port. Вы будете вставлять эту строку много раз, и готовый шаблон избавит от опечаток.
Базовые понятия: как устроен Docker и где в нем живет прокси
Чтобы настройка прокси в Docker не превратилась в магию, разберемся с терминами. Если вы уже уверенно работаете с контейнерами, пробегитесь по разделу быстро, но обратите внимание на подраздел про три уровня прокси: именно там кроется большинство ошибок.
Ключевые термины простым языком
- Образ (image) — это шаблон, «замороженный» набор файлов и программ. Например, образ с Python или образ с браузером.
- Контейнер (container) — запущенная копия образа. Из одного образа можно запустить сколько угодно контейнеров, и каждый будет изолирован от других.
- Docker-демон (daemon, dockerd) — фоновая служба, которая создает контейнеры, скачивает образы и управляет сетями. Именно демон ходит в интернет за образами, когда вы пишете docker pull.
- Docker-клиент (docker CLI) — команда docker в терминале. Она отправляет ваши приказы демону.
- Переменные окружения (environment variables) — именованные значения, доступные программам внутри контейнера. Например, HTTP_PROXY=http://user:pass@host:port. Многие программы автоматически читают такие переменные и начинают ходить через указанный прокси.
- Сеть Docker (network) — виртуальная сеть, объединяющая контейнеры. Контейнеры в одной пользовательской сети видят друг друга по именам.
- Docker Compose — инструмент, который описывает несколько контейнеров, их переменные и сети в одном YAML-файле и запускает их одной командой.
Три уровня прокси в Docker
Это самая важная часть теории. Когда говорят «прокси в Docker», могут иметь в виду три совершенно разные вещи, и настраиваются они по-разному.
- Прокси для демона. Нужен, чтобы сам Docker скачивал образы через прокси. Это про команды docker pull и docker build, когда они тянут базовые образы. На трафик ваших приложений внутри контейнеров этот уровень не влияет.
- Прокси для контейнеров через переменные окружения. Внутрь контейнера передаются HTTP_PROXY, HTTPS_PROXY и NO_PROXY, а приложение само решает, использовать их или нет. Это самый популярный и простой способ, но он работает только с программами, которые уважают эти переменные.
- Прокси на уровне сети. Трафик контейнера направляется через другой контейнер-шлюз или через специально настроенную сеть. Приложение внутри может вообще не знать о прокси. Это надежнее, но требует больше настройки.
Что важно понимать перед началом
Переменные окружения с прокси — это только рекомендация для программы. Утилита curl, пакетный менеджер pip, библиотека requests в Python, Node.js с пакетом global-agent, wget, apt — все они читают HTTP_PROXY. А вот браузеры в headless-режиме, некоторые Go-приложения и многие бинарные утилиты могут переменные игнорировать. Поэтому после настройки всегда проверяйте фактический внешний IP, а не полагайтесь на то, что переменная выставлена.
Еще один нюанс — регистр. Исторически сложилось, что часть программ читает http_proxy в нижнем регистре, часть — HTTP_PROXY в верхнем. Надежная практика — задавать оба варианта одновременно. Переменная NO_PROXY перечисляет адреса, для которых прокси использовать не нужно: localhost, 127.0.0.1, внутренние домены, имена соседних контейнеров.
Наконец, формат адреса прокси. Для HTTP-прокси строка выглядит как http://login:password@host:port. Для SOCKS5 — socks5://login:password@host:port или socks5h://login:password@host:port. Буква h в конце означает, что DNS-запросы тоже уходят через прокси, что для мобильных прокси обычно предпочтительнее: так целевой сайт не увидит DNS-резолвер вашего провайдера.
Шаг 1: Проверяем Docker и готовим данные прокси
Цель этапа: убедиться, что Docker работает, а ваши прокси-данные корректны и доступны с этого компьютера. Без этой проверки вы рискуете полчаса искать ошибку в конфигурации, когда проблема была в опечатке в пароле.
Проверка Docker
- Откройте терминал.
- Введите команду docker --version и нажмите Enter. Вы должны увидеть строку вида Docker version 27.x.x. Если терминал пишет, что команда не найдена, Docker не установлен: установите Docker Desktop (Windows, macOS) или Docker Engine (Linux) по официальной документации и вернитесь сюда.
- Введите docker compose version. Ожидаемый вывод: Docker Compose version v2.x.x.
- Введите docker run --rm hello-world. Docker скачает крошечный тестовый образ и выведет приветствие со словами Hello from Docker. Это значит, что демон работает и у вас есть права на запуск контейнеров.
Совет: Если на Linux команда docker требует sudo, добавьте себя в группу docker: sudo usermod -aG docker $USER, затем выйдите из системы и войдите снова. Дальше все команды в гайде будут работать без sudo.
Проверка прокси с хоста
Перед тем как нести прокси внутрь контейнера, проверим, что он вообще отвечает. Подставьте свои данные вместо примера. В примерах мы будем использовать адрес 185.10.10.10, порт 1050 для HTTP и 1051 для SOCKS5, логин user123 и пароль secret. У вас, разумеется, будут свои значения.
- Сначала узнайте свой обычный IP без прокси: curl -s ifconfig.me. Запишите или запомните результат.
- Теперь запрос через HTTP-прокси: curl -s -x http://user123:secret@185.10.10.10:1050 ifconfig.me
- Если у вас SOCKS5: curl -s -x socks5h://user123:secret@185.10.10.10:1051 ifconfig.me
- Сравните результат с шагом 1. IP должен отличаться и принадлежать мобильному оператору.
Спецсимволы в пароле
Если в логине или пароле есть символы @, :, /, #, ? или пробел, их надо закодировать в URL-виде, иначе строка прокси сломается. Символ @ превращается в %40, : в %3A, / в %2F, # в %23, ? в %3F, пробел в %20. Например, пароль pa@ss в строке прокси записывается как pa%40ss.
✅ Проверка: Команда curl через прокси вернула IP, отличный от вашего домашнего, и ответ пришел за одну-три секунды. Если получили ошибку 407, проверьте логин и пароль. Если Connection refused или таймаут — проверьте хост, порт и то, добавлен ли ваш текущий IP в белый список в личном кабинете провайдера (у некоторых тарифов авторизация по IP включена по умолчанию).
Шаг 2: Настраиваем прокси для одного контейнера через переменные окружения
Цель этапа: запустить контейнер, весь HTTP-трафик которого идет через мобильный прокси, и убедиться в этом по внешнему IP. Это базовый сценарий, с которого стоит начать всем: он не трогает системные настройки и легко отменяется.
Запуск с флагом -e
Флаг -e (или --env) команды docker run передает переменную окружения внутрь контейнера. Мы передадим сразу четыре переменные: прокси для HTTP, для HTTPS и исключения, каждую в двух регистрах.
- Скопируйте команду ниже в редактор и замените данные прокси на свои.
- Выполните команду в терминале. Она запустит временный контейнер с curl, который сделает запрос и завершится.
docker run --rm -e HTTP_PROXY=http://user123:secret@185.10.10.10:1050 -e HTTPS_PROXY=http://user123:secret@185.10.10.10:1050 -e http_proxy=http://user123:secret@185.10.10.10:1050 -e https_proxy=http://user123:secret@185.10.10.10:1050 -e NO_PROXY=localhost,127.0.0.1 -e no_proxy=localhost,127.0.0.1 curlimages/curl -s ifconfig.meОбратите внимание: для HTTPS_PROXY мы тоже указываем http:// в начале. Это не ошибка. Так задается прокси, через который пойдут HTTPS-запросы, а само соединение с прокси-сервером при этом обычное. Схема https:// в значении HTTPS_PROXY означала бы, что до самого прокси надо подключаться по TLS, что у большинства провайдеров не поддерживается.
Файл с переменными вместо длинной команды
Команда получилась громоздкой. Docker умеет читать переменные из файла через флаг --env-file. Так удобнее и безопаснее: пароль не остается в истории терминала.
- Создайте файл proxy.env в рабочей папке: nano proxy.env
- Впишите в него строки, по одной переменной на строку, без кавычек и без пробелов вокруг знака равенства:
HTTP_PROXY=http://user123:secret@185.10.10.10:1050 HTTPS_PROXY=http://user123:secret@185.10.10.10:1050 http_proxy=http://user123:secret@185.10.10.10:1050 https_proxy=http://user123:secret@185.10.10.10:1050 NO_PROXY=localhost,127.0.0.1 no_proxy=localhost,127.0.0.1В реальном файле каждая переменная должна быть на отдельной строке. Сохраните файл (в nano это Ctrl+O, Enter, затем Ctrl+X) и запустите контейнер:
docker run --rm --env-file proxy.env curlimages/curl -s ifconfig.meПроверка изнутри работающего контейнера
Часто нужно посмотреть, что видит долгоживущий контейнер. Запустим Alpine Linux в интерактивном режиме и проверим переменные.
- Выполните docker run -it --rm --env-file proxy.env alpine sh. Вы окажетесь внутри контейнера, приглашение сменится на решетку или знак доллара.
- Введите env | grep -i proxy. Вы увидите список ваших переменных.
- Введите apk add --no-cache curl. Пакетный менеджер apk сам подхватит https_proxy и скачает пакет через прокси.
- Введите curl -s ifconfig.me и убедитесь, что IP мобильный.
- Наберите exit, чтобы выйти. Контейнер удалится автоматически благодаря флагу --rm.
Совет: Для проверки IP помимо ifconfig.me удобно использовать сервисы, отдающие JSON с информацией о стране, городе и провайдере. Так вы сразу увидите, что IP принадлежит мобильному оператору нужного региона, а не просто «какой-то другой».
✅ Проверка: Оба запуска с curl вернули IP мобильного прокси. Команда env внутри контейнера показала переменные HTTP_PROXY и HTTPS_PROXY с вашими данными.
Возможные проблемы на этом шаге
- IP не изменился. Приложение в контейнере игнорирует переменные. Для curl такого не бывает, поэтому если curl показывает мобильный IP, а ваше приложение — нет, переходите к сетевому способу из шага 6.
- Ошибка invalid reference format. Обычно это лишний пробел или перенос строки в команде. Соберите команду в одну строку.
- Переменные не видны. В файле env-file не должно быть кавычек вокруг значений: Docker передаст их буквально, и адрес прокси станет некорректным.
Шаг 3: Настраиваем прокси для Docker-клиента, чтобы переменные передавались автоматически
Цель этапа: сделать так, чтобы каждый новый контейнер и каждая сборка образа автоматически получали переменные прокси без флагов -e. Это экономит время, если вы постоянно запускаете разные контейнеры через один и тот же мобильный прокси.
Как это работает
Docker-клиент читает файл config.json в папке ~/.docker (на Windows это папка .docker в профиле пользователя). Если в нем есть секция proxies, клиент при каждом docker run и docker build добавляет указанные переменные в контейнер. Демон при этом не затрагивается, поэтому docker pull будет по-прежнему идти напрямую.
Пошаговая настройка
- Проверьте, есть ли файл: cat ~/.docker/config.json. Если файл существует и в нем уже есть настройки (например, auths с данными входа в реестр), сделайте копию: cp ~/.docker/config.json ~/.docker/config.json.bak
- Откройте файл в редакторе: nano ~/.docker/config.json. Если файла нет, редактор создаст его.
- Добавьте секцию proxies. Если файл был пустым, его содержимое целиком будет таким:
{ "proxies": { "default": { "httpProxy": "http://user123:secret@185.10.10.10:1050", "httpsProxy": "http://user123:secret@185.10.10.10:1050", "noProxy": "localhost,127.0.0.1,*.local" } } }Если в файле уже были другие ключи, добавьте proxies как еще один ключ верхнего уровня через запятую, не удаляя существующие. Следите за парностью фигурных скобок и кавычек: JSON не прощает пропущенной запятой.
- Сохраните файл.
- Проверьте синтаксис. На Linux и macOS удобно так: python3 -m json.tool ~/.docker/config.json. Если вывод повторяет ваш файл красиво отформатированным, все в порядке. Если появилась ошибка с номером строки, исправьте ее.
- Запустите проверочный контейнер без каких-либо флагов: docker run --rm curlimages/curl -s ifconfig.me. IP должен быть мобильным.
- Посмотрите переменные любого контейнера: docker run --rm alpine env. В выводе будут HTTP_PROXY, HTTPS_PROXY, NO_PROXY и их варианты в нижнем регистре: Docker добавляет оба регистра сам.
⚠ Внимание: Секция proxies в config.json влияет на все контейнеры, которые вы запускаете от этого пользователя, включая базы данных, локальные веб-серверы и все остальное. Если какой-то сервис общается с внешним API, который недоступен через ваш прокси, он сломается. Добавляйте такие адреса в noProxy или временно убирайте секцию.
Разные прокси для разных подключений
Ключ default применяется ко всем подключениям к демону. Если вы управляете несколькими Docker-хостами через контексты или переменную DOCKER_HOST, вместо default можно указать адрес конкретного демона, например tcp://192.168.1.50:2376, и прокси будет применяться только к нему. Для локальной работы default достаточно.
Прокси при сборке образов
Настройки из config.json также передаются в docker build как аргументы сборки. Это значит, что команды RUN apt-get install или RUN pip install внутри Dockerfile пойдут через прокси. Важный момент: эти переменные не сохраняются в итоговом образе, что хорошо с точки зрения безопасности: пароль от прокси не утечет к тем, кому вы передадите образ.
Совет: Если хотите передать прокси только для одной сборки, не трогая config.json, используйте флаги docker build --build-arg HTTP_PROXY=http://user123:secret@185.10.10.10:1050 --build-arg HTTPS_PROXY=http://user123:secret@185.10.10.10:1050 . Docker понимает эти предопределенные аргументы без объявления ARG в Dockerfile.
✅ Проверка: Контейнер, запущенный без флагов -e, выходит в интернет с IP прокси. Команда docker run --rm alpine env показывает переменные прокси.
Как откатить
Удалите секцию proxies из config.json или восстановите файл из резервной копии: cp ~/.docker/config.json.bak ~/.docker/config.json. Перезапуск не нужен, изменения применяются к следующему запуску контейнера.
Шаг 4: Настраиваем прокси для Docker-демона, чтобы образы скачивались через прокси
Цель этапа: заставить сам Docker (демон) ходить за образами через прокси. Это нужно, когда прямой доступ к реестру образов с вашего сервера ограничен корпоративной политикой, медленный или когда вы хотите, чтобы вся сетевая активность сервера шла через один канал. Для маркетинговых задач этот шаг часто не нужен, но знать его стоит: ошибки уровня демона регулярно путают с ошибками уровня контейнера.
Способ 1: файл daemon.json (Linux, Docker 23 и новее)
- Сделайте копию: sudo cp /etc/docker/daemon.json /etc/docker/daemon.json.bak (если файла нет, команда выдаст ошибку, это нормально).
- Откройте файл: sudo nano /etc/docker/daemon.json
- Добавьте секцию proxies:
{ "proxies": { "http-proxy": "http://user123:secret@185.10.10.10:1050", "https-proxy": "http://user123:secret@185.10.10.10:1050", "no-proxy": "localhost,127.0.0.1" } }Обратите внимание, что ключи здесь пишутся через дефис и в нижнем регистре: это отличается от config.json клиента, где ключи в стиле httpProxy. Путать их — классическая ошибка.
- Сохраните файл и перезапустите демон: sudo systemctl restart docker
- Проверьте, что демон поднялся: sudo systemctl status docker. В выводе должно быть active (running).
- Проверьте применение: docker info | grep -i proxy. Вы увидите строки HTTP Proxy и HTTPS Proxy с вашим адресом, при этом пароль в выводе будет скрыт звездочками.
Способ 2: drop-in файл systemd (Linux, любая версия)
Это классический способ, который работает даже на старых версиях Docker.
- Создайте папку: sudo mkdir -p /etc/systemd/system/docker.service.d
- Создайте файл: sudo nano /etc/systemd/system/docker.service.d/http-proxy.conf
- Впишите содержимое, каждая директива на своей строке:
[Service] Environment="HTTP_PROXY=http://user123:secret@185.10.10.10:1050" Environment="HTTPS_PROXY=http://user123:secret@185.10.10.10:1050" Environment="NO_PROXY=localhost,127.0.0.1"- Сохраните, затем перечитайте конфигурацию systemd: sudo systemctl daemon-reload
- Перезапустите Docker: sudo systemctl restart docker
- Проверьте: sudo systemctl show --property=Environment docker. В выводе будут ваши переменные.
⚠ Внимание: Не настраивайте прокси демона одновременно двумя способами. Если и daemon.json, и systemd-файл содержат разные адреса, поведение станет непредсказуемым, а отладка — мучительной. Выберите один способ и придерживайтесь его.
Способ 3: Docker Desktop (Windows и macOS)
- Откройте Docker Desktop, нажмите на значок шестеренки в правом верхнем углу.
- В левом меню выберите Resources, затем Proxies.
- Переключите тумблер Manual proxy configuration в положение включено.
- В поля Web Server (HTTP) и Secure Web Server (HTTPS) вставьте адрес прокси в формате http://user123:secret@185.10.10.10:1050.
- В поле Bypass proxy settings for these hosts впишите localhost,127.0.0.1.
- Нажмите Apply and restart. Docker Desktop перезапустится, это займет 30–60 секунд.
Docker Desktop применяет эти настройки и к демону, и к контейнерам одновременно, поэтому отдельная правка config.json на десктопных системах часто не нужна.
Проверка результата
- Удалите какой-нибудь маленький образ, если он есть: docker rmi alpine
- Скачайте его снова: docker pull alpine. Скачивание должно пройти успешно.
- Если на стороне прокси есть статистика трафика (в личном кабинете mobileproxy.space она есть), вы увидите, что объем потребленного трафика вырос на несколько мегабайт.
✅ Проверка: docker info показывает адрес прокси, docker pull скачивает образы без ошибок, служба docker находится в состоянии active.
Возможные проблемы
- Docker не запускается после правки daemon.json. Почти всегда виноват синтаксис JSON. Проверьте файл командой python3 -m json.tool /etc/docker/daemon.json или восстановите копию.
- docker pull зависает. Прокси не пропускает соединения к реестру или превышен лимит трафика на тарифе. Проверьте прокси с хоста через curl, как в шаге 1.
- Ошибка x509 certificate. Прокси подменяет сертификаты (актуально для корпоративных прокси, для мобильных прокси это редкость). Уточните у провайдера.
Шаг 5: Настраиваем прокси в Docker Compose
Цель этапа: описать прокси в файле compose.yaml так, чтобы группа контейнеров запускалась одной командой с нужными настройками, а разные сервисы могли использовать разные мобильные прокси. Именно этот сценарий чаще всего нужен арбитражникам и маркетологам: один парсер работает через прокси Москвы, второй — через прокси Казани, а база данных — вообще без прокси.
Подготовка проекта
- Создайте папку проекта и перейдите в нее: mkdir proxy-demo, затем cd proxy-demo
- Создайте файл .env (именно с точкой в начале) для хранения секретов: nano .env
- Впишите переменные, по одной на строку:
PROXY_MSK=http://user123:secret@185.10.10.10:1050 PROXY_KZN=http://user456:secret2@185.10.10.20:1050Файл .env Compose читает автоматически, и значения из него можно подставлять в compose.yaml через синтаксис ${ИМЯ}. Добавьте .env в .gitignore, если проект под системой контроля версий: пароли не должны попадать в репозиторий.
Файл compose.yaml
Создайте файл compose.yaml (nano compose.yaml) и опишите три сервиса. В YAML отступы важны: используйте два пробела на уровень, не табуляцию.
services: parser-msk: image: curlimages/curl command: -s ifconfig.me environment: HTTP_PROXY: ${PROXY_MSK} HTTPS_PROXY: ${PROXY_MSK} http_proxy: ${PROXY_MSK} https_proxy: ${PROXY_MSK} NO_PROXY: localhost,127.0.0.1,db no_proxy: localhost,127.0.0.1,db parser-kzn: image: curlimages/curl command: -s ifconfig.me environment: HTTP_PROXY: ${PROXY_KZN} HTTPS_PROXY: ${PROXY_KZN} http_proxy: ${PROXY_KZN} https_proxy: ${PROXY_KZN} NO_PROXY: localhost,127.0.0.1,db no_proxy: localhost,127.0.0.1,db db: image: postgres:16-alpine environment: POSTGRES_PASSWORD: exampleЗдесь в реальном файле каждая строка стоит отдельно с правильными отступами: services на нулевом уровне, имена сервисов с отступом в два пробела, их параметры — в четыре, переменные окружения — в шесть. Обратите внимание на имя db в NO_PROXY: так парсеры будут обращаться к базе данных напрямую по внутренней сети Docker, а не пытаться достучаться до нее через мобильный прокси, что заведомо не сработает.
Запуск и проверка
- Проверьте, как Compose подставил переменные: docker compose config. Команда выведет итоговый файл с раскрытыми значениями. Убедитесь, что вместо ${PROXY_MSK} стоит реальный адрес.
- Запустите: docker compose up. Compose скачает образы и запустит все три сервиса, выводя их логи в терминал.
- В логах вы увидите строки вида parser-msk-1 | 91.xxx.xxx.xxx и parser-kzn-1 | 176.xxx.xxx.xxx: два разных IP от двух разных прокси. Postgres запустится и будет ждать подключений.
- Остановите все сочетанием Ctrl+C, затем удалите контейнеры: docker compose down
Альтернатива: env_file для каждого сервиса
Если переменных много, вместо блока environment удобнее указать файл:
services: parser-msk: image: curlimages/curl command: -s ifconfig.me env_file: - proxy-msk.envФайл proxy-msk.env при этом содержит те же шесть строк, что и proxy.env из шага 2. Так каждый прокси лежит в своем файле, и заменить его можно, не открывая compose.yaml.
Прокси при сборке в Compose
Если сервис собирается из Dockerfile, а не берется готовым, передайте прокси в сборку через build.args:
services: app: build: context: . args: HTTP_PROXY: ${PROXY_MSK} HTTPS_PROXY: ${PROXY_MSK}Так pip, npm или apt внутри Dockerfile будут работать через прокси, а в итоговый образ значения не попадут.
Совет: Compose поддерживает несколько файлов. Держите базовый compose.yaml без прокси, а в compose.proxy.yaml опишите только блоки environment. Запускайте docker compose -f compose.yaml -f compose.proxy.yaml up, когда прокси нужен, и просто docker compose up, когда нет. Это удобно при отладке: вы за секунду переключаетесь между режимами.
✅ Проверка: docker compose config показывает подставленные адреса прокси, а в логах docker compose up сервисы с разными прокси выводят разные IP.
Шаг 6: Настраиваем прокси на уровне сети через контейнер-шлюз
Цель этапа: поднять отдельный контейнер, который принимает соединения от соседей в Docker-сети и переправляет их в мобильный прокси. Остальные контейнеры обращаются к шлюзу по имени и не хранят у себя логин и пароль. Это решает три задачи сразу: централизует управление прокси, убирает пароли из десятков конфигов и позволяет менять прокси, не перезапуская рабочие контейнеры.
Зачем нужен шлюз, если есть переменные
Представьте, что у вас двадцать контейнеров с парсерами и провайдер выдал новый порт. С переменными окружения вам придется править двадцать конфигов и перезапускать все. Со шлюзом вы меняете одну строку в одном месте. Кроме того, некоторые приложения не поддерживают авторизацию в прокси по логину и паролю, но прекрасно работают с прокси без авторизации. Шлюз внутри закрытой Docker-сети авторизацию не требует, а сам подключается к мобильному прокси уже с вашими данными.
Создаем сеть
- Создайте пользовательскую сеть: docker network create proxynet
- Убедитесь, что она появилась: docker network ls. В списке будет proxynet с драйвером bridge.
Пользовательская сеть нужна потому, что только в ней работает разрешение имен: контейнер сможет обратиться к шлюзу по имени gateway, а не по IP, который меняется при каждом перезапуске.
Запускаем шлюз
В качестве шлюза используем gost — компактный прокси-сервер, умеющий принимать соединения на одном протоколе и переправлять их на другой с авторизацией. Образ доступен в публичном реестре под именем gogost/gost.
- Запустите контейнер-шлюз:
docker run -d --name gateway --network proxynet --restart unless-stopped gogost/gost -L=http://:8118 -F=http://user123:secret@185.10.10.10:1050Разберем параметры. Флаг -d запускает контейнер в фоне. Флаг --name gateway задает имя, по которому к нему будут обращаться соседи. Флаг --network proxynet подключает его к нашей сети. Флаг --restart unless-stopped поднимает шлюз после перезагрузки сервера. Параметр -L=http://:8118 говорит gost принимать HTTP-прокси-соединения на порту 8118 без авторизации. Параметр -F указывает, куда переправлять: в ваш мобильный прокси с логином и паролем.
- Проверьте, что шлюз работает: docker logs gateway. В логе должна быть строка о том, что сервер слушает на порту 8118, без ошибок.
⚠ Внимание: Не публикуйте порт шлюза наружу флагом -p, если в этом нет прямой необходимости. Шлюз работает без авторизации, и открытый порт 8118 на публичном сервере означает, что кто угодно в интернете сможет пользоваться вашим мобильным прокси и расходовать ваш трафик. Внутри сети proxynet он доступен только вашим контейнерам, и этого достаточно.
Подключаем рабочие контейнеры
- Запустите проверочный контейнер в той же сети, указав шлюз как прокси:
docker run --rm --network proxynet -e HTTP_PROXY=http://gateway:8118 -e HTTPS_PROXY=http://gateway:8118 curlimages/curl -s ifconfig.me- Вы должны увидеть IP мобильного прокси. Заметьте: в переменных нет ни логина, ни пароля, ни реального адреса прокси. Все это знает только шлюз.
То же самое в Compose
Для постоянной работы опишите шлюз и рабочие сервисы в одном compose.yaml:
services: gateway: image: gogost/gost command: -L=http://:8118 -F=${PROXY_MSK} restart: unless-stopped networks: - proxynet worker: image: curlimages/curl command: -s ifconfig.me environment: HTTP_PROXY: http://gateway:8118 HTTPS_PROXY: http://gateway:8118 NO_PROXY: localhost,127.0.0.1 depends_on: - gateway networks: - proxynet networks: proxynet: driver: bridgeДиректива depends_on гарантирует, что шлюз стартует раньше воркера. Значение PROXY_MSK берется из файла .env, как в шаге 5.
Несколько шлюзов для нескольких гео
Хотите разные прокси для разных групп контейнеров? Поднимите несколько шлюзов: gateway-msk, gateway-kzn, gateway-spb, каждый со своим -F. Рабочие контейнеры просто указывают нужное имя в HTTP_PROXY. Можно пойти дальше и создать отдельную сеть на каждый гео, тогда контейнеры из группы Москвы физически не смогут случайно попасть в шлюз Казани.
Изоляция: контейнер без прямого выхода в интернет
Самый строгий вариант — запретить рабочему контейнеру любой выход в интернет, кроме как через шлюз. Для этого создайте внутреннюю сеть флагом --internal: docker network create --internal isolated. Контейнеры в такой сети не имеют маршрута наружу. Подключите шлюз к двум сетям сразу (isolated и обычной proxynet), а воркеры — только к isolated. Теперь даже если приложение проигнорирует переменные прокси, оно просто не сможет выйти в интернет напрямую и утечки реального IP не произойдет.
- docker network create --internal isolated
- docker network connect isolated gateway
- docker run --rm --network isolated -e HTTP_PROXY=http://gateway:8118 -e HTTPS_PROXY=http://gateway:8118 curlimages/curl -s ifconfig.me
- Для контроля запустите тот же контейнер без переменных прокси: docker run --rm --network isolated curlimages/curl -s -m 5 ifconfig.me. Запрос должен завершиться таймаутом: прямого выхода нет.
Совет: Комбинация внутренней сети и шлюза — лучшая страховка от утечек при мультиаккаунтной работе. Даже если разработчик забыл прописать прокси в новом сервисе, тот не сможет засветить IP сервера: он либо пойдет через шлюз, либо не пойдет никуда.
✅ Проверка: Контейнер в сети proxynet с переменной HTTP_PROXY=http://gateway:8118 показывает IP мобильного прокси. Контейнер во внутренней сети без прокси не может выйти в интернет вообще.
Возможные проблемы
- Could not resolve host: gateway. Рабочий контейнер не в той сети или запущен в сети по умолчанию, где имена не разрешаются. Проверьте флаг --network.
- Шлюз перезапускается. Ошибка в строке -F: опечатка в пароле или неверный порт. Смотрите docker logs gateway.
- Медленно. Мобильные прокси по природе медленнее дата-центровых, но если задержка исчисляется десятками секунд, проверьте, не идет ли DNS в обход: используйте socks5h вместо socks5 в строке -F, если провайдер дает SOCKS5.
Проверка результата: чек-лист работающего прокси в Docker
Пройдитесь по списку. Если каждый пункт отмечен, вы полностью освоили настройку прокси в Docker на практике.
Чек-лист
- curl с хоста через прокси возвращает мобильный IP.
- Контейнер с флагом --env-file proxy.env возвращает мобильный IP.
- Контейнер без флагов после настройки config.json возвращает мобильный IP (если вы делали шаг 3).
- docker info показывает адрес прокси, а docker pull работает (если вы делали шаг 4).
- docker compose up запускает сервисы, и в логах видны разные IP для разных прокси.
- Контейнер-шлюз работает, соседи выходят через него без логина и пароля.
- Контейнер во внутренней сети без прокси не может выйти в интернет.
Как протестировать целиком
- Запустите долгоживущий контейнер: docker run -d --name test --network proxynet -e HTTP_PROXY=http://gateway:8118 -e HTTPS_PROXY=http://gateway:8118 alpine sleep 3600
- Зайдите в него: docker exec -it test sh
- Установите curl: apk add --no-cache curl. Установка должна пройти через прокси.
- Сделайте пять запросов подряд: for i in 1 2 3 4 5; do curl -s ifconfig.me; echo; done. Все пять должны вернуть мобильный IP. Если у вашего прокси включена автоматическая ротация, IP могут отличаться между запросами, это нормально.
- Выйдите (exit) и удалите контейнер: docker rm -f test
Показатели успеха
Успешная настройка означает, что вы можете за секунду ответить на три вопроса: через какой IP выходит конкретный контейнер, где хранится пароль от прокси и что нужно поменять, чтобы переключить контейнер на другой прокси. Если ответ на каждый вопрос очевиден — цель достигнута.
Типичные ошибки при настройке прокси в Docker и их решения
Ошибка 1: IP не меняется, хотя переменные выставлены
Причина: приложение внутри контейнера не читает переменные окружения прокси. Это характерно для headless-браузеров, некоторых Go-программ и утилит, которые используют собственные сетевые стеки.
Решение: проверьте документацию приложения на предмет собственного флага прокси (у браузеров это обычно --proxy-server). Если флага нет, используйте шлюз и внутреннюю сеть из шага 6 или прозрачное проксирование из раздела для продвинутых.
Ошибка 2: 407 Proxy Authentication Required
Причина: неверный логин или пароль, либо спецсимволы в них не закодированы, либо у прокси включена авторизация по IP, а IP сервера не в белом списке.
Решение: проверьте данные с хоста через curl. Закодируйте спецсимволы. Добавьте IP сервера в белый список в личном кабинете или переключите прокси на авторизацию по логину и паролю.
Ошибка 3: Docker не запускается после правки daemon.json
Причина: синтаксическая ошибка в JSON: лишняя запятая, пропущенная кавычка, ключи в стиле config.json вместо стиля daemon.json.
Решение: посмотрите журнал: sudo journalctl -u docker -n 50. Там будет указана строка с ошибкой. Исправьте или восстановите резервную копию и перезапустите службу.
Ошибка 4: контейнеры перестали видеть друг друга
Причина: после глобальной настройки прокси в config.json запросы к соседним контейнерам тоже пошли через мобильный прокси, который не знает, что такое db или redis.
Решение: добавьте имена сервисов и внутренние подсети в NO_PROXY: localhost,127.0.0.1,db,redis,172.16.0.0/12. Учтите, что маски подсетей понимают не все программы, поэтому надежнее перечислять имена явно.
Ошибка 5: docker build падает на apt-get или pip
Причина: сборка идет без прокси, потому что переменные заданы для контейнеров, а не для сборки, или прокси демона настроен, но он не влияет на шаги RUN.
Решение: передайте --build-arg HTTP_PROXY и HTTPS_PROXY либо настройте секцию proxies в config.json клиента: она распространяется и на сборку.
Ошибка 6: пароль от прокси виден в docker inspect и логах
Причина: переменные окружения хранятся в метаданных контейнера в открытом виде, и любой, у кого есть доступ к Docker, увидит их через docker inspect.
Решение: используйте шлюз: рабочие контейнеры знают только адрес gateway:8118. Пароль остается в одном контейнере и в файле .env с ограниченными правами (chmod 600 .env).
Ошибка 7: после перезагрузки сервера прокси перестал работать
Причина: контейнер-шлюз не был запущен с политикой перезапуска или у мобильного прокси сменился IP-адрес хоста.
Решение: добавьте --restart unless-stopped к шлюзу. Используйте доменное имя прокси вместо IP, если провайдер его предоставляет. Проверьте docker ps -a: если шлюз в статусе Exited, посмотрите его логи.
Ошибка 8: HTTPS-сайты не открываются, а HTTP работает
Причина: задана только HTTP_PROXY, а HTTPS_PROXY пуста, либо в HTTPS_PROXY указана схема https:// вместо http://.
Решение: всегда задавайте обе переменные с одинаковым значением и схемой http://.
Дополнительные возможности для продвинутых: прозрачное проксирование, ротация IP и безопасность
Этот раздел для тех, кто прошел базовые шаги и хочет выжать из связки Docker и мобильных прокси максимум. Здесь меньше пошаговых списков и больше идей с ключевыми командами.
Прозрачное проксирование: когда приложение вообще не знает о прокси
Если у вас приложение, которое не умеет работать с прокси никак, можно завернуть весь его TCP-трафик на уровне сетевого стека. Идея такая: рабочий контейнер запускается с параметром network_mode: service:gateway (в Compose) или --network container:gateway (в docker run). Так он использует сетевой стек контейнера-шлюза целиком: тот же IP, те же интерфейсы, те же правила маршрутизации.
В шлюзе при этом работает программа вроде redsocks, которая слушает локальный порт и переправляет соединения в SOCKS5-прокси, а правила iptables перенаправляют на этот порт весь исходящий TCP-трафик. Шлюзу для этого нужны права: cap_add: NET_ADMIN. Приложение в рабочем контейнере делает обычный запрос к сайту, ядро перехватывает его и направляет в redsocks, а тот — в мобильный прокси. Никаких переменных окружения. Настройка requires аккуратности: неверное правило iptables может зациклить трафик, поэтому тестируйте на отдельной машине. Учтите также, что при network_mode: service рабочий контейнер теряет собственные порты и подключения к другим сетям, все это надо описывать на шлюзе.
Ротация IP из контейнера
У мобильных прокси есть особенность, ради которой их и берут: IP можно сменить по запросу. Провайдеры предоставляют специальную ссылку смены IP, которую достаточно открыть, чтобы модем переподключился. Из контейнера это делается тем же curl. Полезный паттерн: отдельный маленький сервис в Compose, который по расписанию дергает ссылку ротации. Он не должен ходить через прокси (иначе после смены IP он сам потеряет соединение), поэтому запускайте его без переменных прокси или явно с пустыми HTTP_PROXY. Учтите, что после смены IP активные соединения рабочих контейнеров разорвутся: закладывайте в парсеры повторные попытки.
Здоровье шлюза: healthcheck
Добавьте в Compose проверку, что шлюз действительно проксирует, а не просто запущен:
healthcheck: test: ["CMD", "gost", "-V"] interval: 30s timeout: 10s retries: 3Это минимальная проверка живости процесса. Для проверки реального выхода в интернет лучше отдельный контейнер-монитор, который раз в минуту делает запрос через шлюз и пишет результат в лог или отправляет уведомление. Если IP вдруг стал IP сервера, это тревога: шлюз упал, а контейнеры пошли напрямую. Внутренняя сеть из шага 6 как раз защищает от такого сценария.
Безопасное хранение паролей
Файл .env хорош для локальной работы, но на сервере с несколькими пользователями его стоит защитить: chmod 600 .env, владелец — тот пользователь, от которого запускается Compose. Compose также поддерживает секреты через директиву secrets, которые монтируются в контейнер файлом в /run/secrets/, а не переменной окружения. Gost не читает пароль из файла напрямую, но вы можете написать небольшой скрипт-обертку, который собирает строку -F из файла секрета при старте. Так пароль не попадет ни в docker inspect, ни в вывод docker compose config.
Несколько проектов и одна прокси-инфраструктура
Если у вас несколько Compose-проектов, а прокси общие, вынесите шлюзы в отдельный проект с внешней сетью: в нем объявите networks с параметром name: proxynet, а в остальных проектах подключайтесь к ней как к external: true. Тогда шлюзы живут независимо, а рабочие проекты можно перезапускать сколько угодно, не трогая прокси.
Ограничение трафика
Мобильный трафик обычно тарифицируется, и один сорвавшийся парсер может за ночь выкачать десятки гигабайт. На уровне Docker жестких квот на трафик нет, но есть косвенные меры: ограничение частоты запросов в самом приложении, лимит времени жизни контейнера через timeout в команде запуска и мониторинг через docker stats, который показывает NET I/O по каждому контейнеру в реальном времени. Регулярно сверяйте эти цифры со статистикой в личном кабинете провайдера.
Логи без секретов
Многие приложения при старте печатают переменные окружения в лог, включая HTTP_PROXY с паролем. Если логи уходят в централизованную систему, пароль утечет туда. Шлюз решает и эту проблему: в логах рабочих контейнеров будет только gateway:8118.
Совет: Раз в квартал перевыпускайте пароли прокси и обновляйте .env. Со шлюзом это занимает минуту: правите одну строку, делаете docker compose up -d gateway, и все воркеры продолжают работать без перезапуска.
FAQ: частые вопросы о настройке прокси в Docker
Нужно ли перезапускать контейнер, чтобы применить новые переменные прокси?
Да. Переменные окружения задаются в момент создания контейнера и не могут быть изменены у работающего. Остановите, удалите и создайте контейнер заново (в Compose это docker compose up -d --force-recreate имя_сервиса). Если перезапуски мешают, используйте шлюз: его настройки можно менять независимо.
Чем отличается настройка прокси для docker pull от прокси для приложения в контейнере?
Это два разных уровня. docker pull выполняет демон, и для него прокси задается в daemon.json или через systemd. Приложение в контейнере — отдельный процесс со своим окружением, для него прокси задается переменными, config.json клиента или сетью. Одно другого не заменяет.
Можно ли использовать SOCKS5 вместо HTTP-прокси в переменных окружения?
Можно, если приложение поддерживает SOCKS. curl, Python requests (с установленным пакетом PySocks), git поддерживают. apt и многие другие — нет. Универсальный выход: шлюз gost, который принимает HTTP на входе и отправляет в SOCKS5 на выходе: -L=http://:8118 -F=socks5://user:pass@host:port.
Как проверить, какой прокси использует уже запущенный контейнер?
Выполните docker inspect -f '{{.Config.Env}}' имя_контейнера. Вы увидите все переменные окружения. Для проверки фактического IP используйте docker exec имя_контейнера curl -s ifconfig.me, если в контейнере есть curl, или wget -qO- ifconfig.me.
Почему в Docker Desktop прокси работает, а на Linux-сервере те же настройки не работают?
Docker Desktop применяет настройки из окна Proxies и к демону, и к контейнерам одновременно. На Linux это два отдельных места: daemon.json для демона и ~/.docker/config.json для контейнеров. Проверьте, что вы настроили оба, если нужны оба.
Как задать прокси только для одного домена, а остальное пустить напрямую?
Переменные окружения так не умеют: они работают по принципу «все через прокси, кроме NO_PROXY». Если нужна обратная логика, используйте PAC-файл на стороне приложения (поддерживают браузеры) или правила маршрутизации в gost, который умеет направлять трафик на разные исходящие каналы по доменам.
Безопасно ли хранить пароль от прокси в compose.yaml?
Лучше не стоит. Храните его в .env с правами 600 и подставляйте через ${ИМЯ}. Не коммитьте .env в репозиторий. Для серверов используйте шлюз, чтобы пароль был в одном месте.
Что делать, если мобильный прокси сменил IP, и соединения в контейнерах оборвались?
Это нормальное поведение при ротации. Приложение должно уметь повторять запросы. Если ротация происходит по расписанию провайдера, узнайте интервал и синхронизируйте с ним тяжелые операции. Если ротация по вашей ссылке, вызывайте ее между пачками задач, а не посреди.
Работают ли эти настройки на Windows без WSL2?
Docker Desktop на Windows использует WSL2 или Hyper-V под капотом, и все команды docker run и docker compose работают одинаково из PowerShell. Отличаются только пути: файл config.json лежит в C:\Users\ИмяПользователя\.docker\config.json, а настройки демона делаются через окно Docker Desktop, а не через daemon.json вручную.
Сколько контейнеров можно пустить через один мобильный прокси?
Технически — сколько угодно, ограничение только в пропускной способности мобильного канала и лимитах тарифа. Практически для задач с аккаунтами разумно держать один прокси на одну логическую сущность (аккаунт, проект, регион), чтобы поведение выглядело естественно и ошибка в одном контейнере не влияла на остальные.
Заключение: что вы сделали и куда двигаться дальше
Давайте подведем итог. Вы проверили работоспособность прокси с хоста и разобрались с форматом строки подключения. Настроили прокси для отдельного контейнера через переменные окружения и файл env-file. Сделали передачу переменных автоматической через config.json клиента. Разобрались, как и зачем настраивать прокси для самого Docker-демона тремя способами. Описали несколько сервисов с разными мобильными прокси в Docker Compose, вынеся секреты в .env. И, наконец, построили контейнер-шлюз с изолированной сетью — самое надежное решение для продакшена, которое защищает от утечек реального IP, даже если приложение игнорирует переменные.
Теперь прокси в Docker для вас — не черный ящик, а три понятных уровня с четкими границами: демон, контейнер, сеть. Вы знаете, где искать проблему, если IP вдруг оказался не тем, и умеете это проверять за одну команду.
Что делать дальше
- Переведите свои рабочие проекты на схему со шлюзом и внутренней сетью. Начните с одного некритичного сервиса, убедитесь, что все работает, затем масштабируйте.
- Добавьте контейнер-монитор, который раз в минуту проверяет внешний IP через шлюз и сигнализирует, если он совпал с IP сервера.
- Настройте ротацию IP по расписанию под ваши задачи и научите приложения переживать разрыв соединения.
- Наведите порядок с секретами: .env с правами 600, никаких паролей в compose.yaml и Dockerfile.
Куда развиваться
Следующий логичный шаг — связать Docker с антидетект-браузерами и инструментами мультиаккаунтинга, где каждому профилю соответствует свой контейнер и свой мобильный прокси. Другое направление — автоматизация через API провайдера: получение списка прокси, проверка их статуса и ротация прямо из ваших сервисов. Обе темы выходят за рамки этого гайда, но фундамент, который вы сейчас заложили, делает их значительно проще. Удачных запусков и стабильных IP!