Gluetun: проброс порту для torrent-клієнта
Завантаження працюють, але вхідних підключень немає? Налаштуйте проброс порту в Gluetun, передавайте новий порт клієнту після reconnect і перевірте його.
Чому без проброшеного порту немає вхідних підключень
Проброс портів у Gluetun просить вашого VPN-провайдера зіставити один публічний порт на його вихідній адресі з вашим контейнером. Це єдиний спосіб, у який інший peer може ініціювати підключення до вашого torrent-клієнта. Без такого зіставлення тунель працює, завантаження виконуються, але вхідні підключення самостійно не надходять. Кожне робоче підключення ініціює ваш клієнт.
Цей механізм називається NAT (перетворення мережевих адрес). Ваш контейнер використовує вихідну адресу провайдера спільно з багатьма іншими клієнтами. Коли ваш клієнт відкриває вихідне підключення, провайдер записує цей потік і передає відповіді назад через ваш тунель. Вхідне підключення від peer, який вам невідомий, не відповідає жодному записаному потоку. Тому пакет доходить до вихідної адреси й відкидається там. Ваш клієнт і далі підключається до кожного peer, який сам може приймати підключення, тому завантаження завершуються, а проблема залишається непомітною. Вона проявляється під час роздачі, оскільки seeder — це машина, до якої підключаються інші користувачі.
Відкритий вхідний порт змінює дві речі. Ви швидше підключаєтеся до swarm, оскільки peer, які самі не можуть приймати підключення, тепер можуть підключатися до вас. Крім того, ви взагалі можете передавати дані цим peer.
Чому більшість VPN-провайдерів не пропонує переадресацію порту
Переадресований порт є обмеженим ресурсом на спільній адресі. Провайдер резервує один номер порту на одній вихідній IP-адресі для одного клієнта, а потім відповідає за все, що цей клієнт робить через нього. Кілька великих провайдерів вилучили цю функцію та назвали причиною обробку зловживань. Розглядайте підтримку цієї функції як окреме питання, а не як прапорець у списку можливостей: запитайте, чи пропонує провайдер переадресацію портів зараз, у вашому тарифі та на серверах, які ви справді можете вибрати.
Якщо переадресація доступна, порт є динамічним. Він належить сеансу VPN, а не вашому обліковому запису, тому після кожного повторного підключення номер може бути іншим. Private Internet Access видає підписаний порт, який gluetun оновлює. В документації upstream зазначено, що той самий порт зберігається протягом 60 днів, якщо змонтувати каталог /gluetun через bind mount, щоб стан зберігався після перезапуску. ProtonVPN призначає випадковий порт через NAT-PMP (протокол зіставлення портів NAT) на короткий строк оренди, який потрібно постійно поновлювати. Тому одноразове встановлення порту в клієнті не забезпечує його постійну роботу.
Які провайдери можуть запитувати порт через gluetun
Станом на gluetun v3.41.3, випущену 30 July 2026, нативна інтеграція перевіряє чотири назви провайдерів: Private Internet Access, ProtonVPN, Perfect Privacy і PrivateVPN. Увімкніть її за допомогою VPN_PORT_FORWARDING=on. За замовчуванням це off. У старіших інструкціях використовуються PORT_FORWARDING або PRIVATE_INTERNET_ACCESS_VPN_PORT_FORWARDING. В обох випадках у цій версії вони ще працюють як сумісні зі старими конфігураціями назви, але їх поступово вилучають.
Дві особливості провайдерів визначають, чи може запит узагалі виконатися. Для ProtonVPN потрібен платний план, а NAT-PMP має бути ввімкнено: увімкніть NAT-PMP (Port Forwarding) у параметрах VPN під час створення конфігурації WireGuard або додайте +pmp до імені користувача, якщо використовуєте OpenVPN. Для Private Internet Access в OpenVPN доступний параметр PORT_FORWARD_ONLY. Він обмежує вибір серверів серверами з підтримкою port forwarding, щоб підключення не потрапило на сервер, який ніколи його не підтримував. WireGuard і OpenVPN по-різному запитують порт, тому перед вибором ознайомтеся зі сторінкою свого провайдера.
Коли gluetun використовує власну конфігурацію замість вбудованого провайдера, VPN_PORT_FORWARDING_PROVIDER визначає API, до якого gluetun має звертатися. На сторінці Private Internet Access у upstream-репозиторії цю змінну використовують разом із VPN_PORT_FORWARDING_USERNAME і VPN_PORT_FORWARDING_PASSWORD. Вони передають облікові дані, потрібні для запиту порту.
Увімкнення перенаправлення портів gluetun у docker compose
Це передбачає, що тунель уже працює. Якщо ні, спочатку виконайте маршрутизацію трафіку Docker-контейнерів через gluetun, а потім поверніться до цього розділу, коли завантаження запрацюють.
services:
gluetun:
image: qmcgaw/gluetun:v3.41.3
container_name: gluetun
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
ports:
- 8080:8080/tcp
- 8000:8000/tcp
volumes:
- ./gluetun:/gluetun
environment:
- VPN_SERVICE_PROVIDER=protonvpn
- VPN_TYPE=wireguard
- WIREGUARD_PRIVATE_KEY=${WIREGUARD_PRIVATE_KEY}
- VPN_PORT_FORWARDING=on
- TZ=Etc/UTC
restart: unless-stopped
qbittorrent:
image: lscr.io/linuxserver/qbittorrent:5.2.3
container_name: qbittorrent
network_mode: "service:gluetun"
environment:
- PUID=1000
- PGID=1000
- TZ=Etc/UTC
- WEBUI_PORT=8080
volumes:
- ./qbittorrent:/config
- ./downloads:/downloads
depends_on:
- gluetun
restart: unless-stoppedЗафіксуйте тег. qmcgaw/gluetun:latest стежить за гілкою master, де внутрішні механізми перенаправлення портів змінюються для v4, тому образ без зафіксованого тегу може змінити поведінку під час наступного docker compose pull. Зберігайте приватний ключ поза файлом compose за допомогою env-файлу для секретів compose.
Де gluetun записує перенаправлений порт
Gluetun надає порт у трьох місцях, і всюди вказано однакове значення.
Під час кожного отримання порту він один раз записує його в журнал. Рядок має вигляд port forwarded is 45678, а якщо запит не повернув значення — no port forwarded.
docker logs gluetun 2>&1 | grep -i "port forwarded"Він записує номер у файл, заданий параметром VPN_PORT_FORWARDING_STATUS_FILE; значення за замовчуванням — /tmp/gluetun/forwarded_port. Файл містить один порт у кожному рядку, має права доступу 0644, а його власником і групою є відповідно PUID та PGID контейнера. Коли перенаправлення припиняється, gluetun очищає файл, а не видаляє його. Тому споживач отримує порожній файл, а не помилку через відсутній файл.
docker exec gluetun cat /tmp/gluetun/forwarded_portВін надає це значення через control server, який за замовчуванням прослуховує :8000 і налаштовується параметром HTTP_CONTROL_SERVER_ADDRESS.
curl -s http://127.0.0.1:8000/v1/portforward{"port":45678,"ports":[45678]}Gluetun також відкриває цей порт у власному firewall на VPN-інтерфейсі. Тому FIREWALL_VPN_INPUT_PORTS не потрібна, якщо працює нативна інтеграція. Ця змінна потрібна в іншому випадку: коли провайдер не підтримується gluetun, а ви отримали статичний порт іншим каналом і маєте дозволити його вручну.
Одне з цих трьох джерел є довговічним, а два інші — ні. Документація upstream позначає status file як deprecated у v4.0.0. Крім того, GET /v1/openvpn/portforwarded уже повертає 301 Moved Permanently із посиланням на /v1/portforward. Новий код має читати дані з control server.
Чому клієнту потрібно повідомляти порт після кожного повторного підключення
Torrent-клієнт зберігає порт для прослуховування у власній конфігурації та використовує цей номер після перезапуску. Перенаправлений порт є властивістю сеансу VPN. Після повторного підключення ці два номери не збігаються: провайдер перенаправляє порт, який ніхто не прослуховує, а клієнт прослуховує порт, на який нічого не перенаправляється. Повторні підключення не є рідкістю: це може бути перезапуск контейнера, зміна сервера, розірваний тунель, який health check gluetun перезапускає, або lease, який не вдалося поновити. У результаті конфігурація, яка вчора була доступною, сьогодні непомітно стає недоступною, хоча в жодному журналі немає помилки.
Тому порт потрібно застосовувати саме в момент, коли gluetun отримує його. Є два способи це налаштувати. Вони відрізняються тим, який процес виконує цю роботу.
Варіант 1: gluetun передає порт за допомогою команди up
VPN_PORT_FORWARDING_UP_COMMAND виконується після встановлення переадресації порту, а VPN_PORT_FORWARDING_DOWN_COMMAND — після її вимкнення. Перед виконанням команди Gluetun підставляє {{PORT}} (перший порт), {{PORTS}} (усі порти через кому) і {{VPN_INTERFACE}} (назву інтерфейсу тунелю; за замовчуванням — tun0). Для синтаксису оболонки потрібна явна оболонка /bin/sh -c. Це приклад для qBittorrent із upstream, записаний як два записи середовища в compose:
- VPN_PORT_FORWARDING_UP_COMMAND=/bin/sh -c 'wget -O- -nv --retry-connrefused --post-data "json={\"listen_port\":{{PORT}},\"current_network_interface\":\"{{VPN_INTERFACE}}\",\"random_port\":false,\"upnp\":false}" http://127.0.0.1:8080/api/v2/app/setPreferences'
- VPN_PORT_FORWARDING_DOWN_COMMAND=/bin/sh -c 'wget -O- -nv --retry-connrefused --post-data "json={\"listen_port\":0,\"current_network_interface\":\"lo\"}" http://127.0.0.1:8080/api/v2/app/setPreferences'Кожне поле цього виклику має окреме призначення. listen_port — це новий порт. current_network_interface прив’язує qBittorrent до тунелю. Якщо random_port має значення false, qBittorrent не вибиратиме власний порт під час наступного запуску. Якщо upnp має значення false, qBittorrent не намагатиметься зіставити порт через маршрутизатор, якого немає.
Цей підхід має дві вимоги. Вебінтерфейс qBittorrent має відповідати на 127.0.0.1:8080 з контейнера gluetun. Це відбувається автоматично, коли клієнт використовує простір імен мережі gluetun. Також має бути ввімкнено Bypass authentication for clients on localhost (bypass_local_auth), оскільки команда не передає облікових даних. Команда down потрібна, оскільки qBittorrent не завжди повторно встановлює порт після розриву з’єднання.
Команда виконується всередині контейнера gluetun, створеного на базі Alpine, і містить wget. У цьому образі немає curl. Команда, яка вказує бінарний файл, відсутній в образі, щоразу завершується помилкою під час встановлення переадресації порту.
Варіант 2: процес поза gluetun читає порт
За другим підходом поруч із gluetun працює невеликий процес. Він отримує порт і передає його клієнту через власний API клієнта. Отримайте його з control server:
port=$(curl -s http://127.0.0.1:8000/v1/portforward | jq -r .port)Або прочитайте файл, якщо процес може його бачити. /tmp/gluetun/forwarded_port розташований усередині контейнера gluetun, тому sidecar потребує спільного тому, змонтованого за шляхом /tmp/gluetun в обох контейнерах. Також можна вказати для VPN_PORT_FORWARDING_STATUS_FILE шлях у томі, який уже змонтовано.
Автентифікація має значення. У v3.41.3 маршрут GET /v1/portforward належить стандартній ролі з назвою public і має auth = "none". Тому він відповідає без облікових даних, а gluetun записує попередження, що починається з route GET /v1/portforward is unprotected by default, please set up authentication. У наступнішій версії upstream закриє цей доступ. Заздалегідь визначте роль у файлі, змонтованому через bind mount за шляхом /gluetun/auth/config.toml:
roles = [
{ name = "qbittorrent", routes = ["GET /v1/portforward"], auth = "apikey", apikey = "myapikey" }
]Згенеруйте ключ за допомогою docker run --rm qmcgaw/gluetun:v3.41.3 genkey і передавайте його в заголовку X-API-Key. HTTP_CONTROL_SERVER_AUTH_DEFAULT_ROLE виконує ту саму функцію, що й одна змінна середовища у форматі JSON, якщо ви не хочете монтувати файл. Опублікований порт 8000 без ролі дає будь-кому, хто може до нього підключитися, змогу керувати станом VPN. Тому свідомо визначте, наскільки далеко він буде доступний, коли налаштовуєте доступ до gluetun із хоста та інших контейнерів.
Використовуйте команду up, якщо клієнт має API, яким можна керувати одним викликом wget. Вона виконується рівно один раз для кожної події й не потребує постійного процесу. Використовуйте зовнішній процес, якщо клієнту потрібен процес входу, перезапис файлу конфігурації або перезапуск. У стеку застосунків arr за одним контейнером gluetun зазвичай достатньо одного невеликого процесу опитування, оскільки порт потрібен лише torrent-клієнту.
Пастка: спільний network namespace не встановлює порт прослуховування
Ця помилка забирає найбільше часу. network_mode: "service:gluetun" розміщує клієнт у network namespace gluetun, тому клієнт отримує VPN-адресу, маршрути тунелю та правила firewall gluetun. Жоден із цих параметрів не встановлює порт прослуховування клієнта. Gluetun відкриває перенаправлений порт на VPN-інтерфейсі. Пакети для цього порту надходять у namespace. Якщо клієнт прослуховує інший порт, kernel не має процесу, якому можна передати ці пакети. З’єднання відхиляється або завершується тайм-аутом, хоча всі перевірки вихідного трафіку проходять успішно. Перенаправлений порт і порт прослуховування клієнта — це два окремі номери. Увімкнути однакове значення для них — основне завдання.
Порівняйте їх, а не вгадуйте. Обидві команди виконуються в тому самому namespace:
docker exec gluetun cat /tmp/gluetun/forwarded_port
docker exec gluetun wget -qO- http://127.0.0.1:8080/api/v2/app/preferences | grep -o '"listen_port":[0-9]*'Ще один параметр може спрямувати діагностику в неправильний бік. VPN_PORT_FORWARDING_LISTENING_PORT перенаправляє вхідний трафік із перенаправленого порту на фіксований локальний порт за допомогою iptables. Upstream не рекомендує використовувати його з torrent-клієнтами, оскільки клієнт повідомляє tracker-ам і пірам власний порт прослуховування. Через це swarm отримує неправильний номер порту.
Як довести, що порт із перенаправленням доступний
Власний індикатор підключення клієнта відображає вихідні підключення до tracker, тому він може показувати зелений стан, навіть якщо до вас ніхто не може підключитися. Виконайте перевірку за допомогою listener, яким ви керуєте, з мережі поза tunnel. Upstream публікує для цього невеликий інструмент. Спочатку зупиніть torrent client, оскільки два процеси не можуть прив’язати один і той самий порт.
docker stop qbittorrent
docker exec -it gluetun /bin/shУсередині контейнера замініть amd64 на значення для вашої архітектури CPU, а 4567 — на перенаправлений порт:
wget -qO port-checker https://github.com/qdm12/port-checker/releases/download/v0.4.0/port-checker_0.4.0_linux_amd64
chmod +x port-checker
./port-checker --listening-address=":4567"Тепер визначте exit address, яку використовує gluetun. Відповідь має формат JSON, а адреса міститься в полі public_ip.
curl -s http://127.0.0.1:8000/v1/publicip/ipВідкрийте http://<that address>:4567 на пристрої, який не підключений до тієї самої VPN. Підійде телефон із мобільним передаванням даних. Сторінка з IP-адресою та user agent вашого браузера разом із відповідним записом запиту в журналі port-checker означає, що вхідний TCP-трафік досягає namespace. Timeout означає, що цього не відбувається, а причина виникла на рівні вище клієнта. Зупиніть інструмент за допомогою CTRL+C, вийдіть із shell командою exit і знову запустіть клієнт. Ця перевірка охоплює лише TCP. Трафік DHT (distributed hash table) і uTP використовує UDP із тим самим номером порту, але ця перевірка його не охоплює.
Типові помилки та повідомлення, які ви побачите
У журналі взагалі немає рядка про порт. Запит на порт не надходив. За допомогою docker exec gluetun printenv | grep PORT_FORWARDING перевірте, чи змінна справді потрапила в контейнер, оскільки змінна, задана для неправильного сервісу Compose, є поширеною причиною.
Gluetun не запускається та повідомляє про помилку провайдера. Значення VPN_PORT_FORWARDING_PROVIDER перевіряється за чотирма підтримуваними назвами, тому помилка в написанні зупиняє контейнер, а не дає йому непомітно працювати без перенаправлення.
У журналі зазначено no port forwarded. Gluetun надіслав запит, але провайдер не повернув результат. У ProtonVPN це зазвичай означає, що NAT-PMP не було ввімкнено в згенерованій конфігурації або що тарифний план не підтримує port forwarding. У Private Internet Access це зазвичай означає, що вибраний сервер не підтримує цю функцію.
Порт отримано, але вхідні підключення не встановлюються. За допомогою двох наведених вище команд порівняйте порт, призначений для перенаправлення, з портом, на якому слухає клієнт. Якщо вони збігаються, перевірте, чи клієнт прив’язаний до tunnel interface і чи вимкнено параметр випадкового порту, оскільки цей параметр змінює порт прослуховування під час кожного запуску.
Команда up, схоже, нічого не робить. Виконайте точну команду всередині контейнера, щоб побачити помилку: docker exec gluetun /bin/sh -c '<your command>'. Зазвичай результатом є curl: not found, оскільки image містить лише wget.
401 Unauthorized від control server. Ви визначили auth config, але роль не містить маршруту, до якого ви звертаєтеся. Маршрути зіставляються як метод і шлях, тому роль, у якій зазначено лише /v1/portforward, не охоплює GET /v1/portforward.
Після кожного перезапуску в Private Internet Access використовується інший порт. Створіть bind mount для /gluetun, щоб збережений стан порту зберігався після перезапуску. Без цього тому gluetun запитує новий порт щоразу.
FAQ
Чому мої торенти завантажуються, але вхідні з’єднання не надходять?
Без проброшеного порту VPN-провайдер не має правила NAT, яке надсилає вхідні пакети з будь-якого порту до вашого тунелю. Тому з’єднання, ініційовані не вами, відкидаються на вихідній адресі. Завантаження все одно працює, оскільки ваш клієнт сам відкриває ці з’єднання й може підключатися до будь-якого доступного піра. Роздавання та приєднання до роїв погіршуються, оскільки залежать від можливості інших учасників підключитися до вас. Рішення — VPN-провайдер із підтримкою port forwarding, VPN_PORT_FORWARDING=on у gluetun і застосування отриманого порту як порту прослуховування клієнта.
Чи працює gluetun із port forwarding будь-якого VPN-провайдера?
Ні. Gluetun v3.41.3 має вбудовану інтеграцію з чотирма провайдерами: Private Internet Access, ProtonVPN, Perfect Privacy і PrivateVPN. Будь-який провайдер поза цим списком не проходить перевірку для VPN_PORT_FORWARDING_PROVIDER, і контейнер зупиняється під час запуску. Якщо провайдер видає статичний порт через власну панель керування, gluetun не може запросити його замість вас, але FIREWALL_VPN_INPUT_PORTS пропустить цей фіксований порт через firewall gluetun. Політики провайдерів змінюються, тому перед придбанням плану перевірте актуальну сторінку провайдера.
Чи потрібно оновлювати порт після кожного повторного підключення?
Так, і це оновлення має виконуватися автоматично. Проброшений порт належить сеансу VPN, тому перезапуск контейнера, зміна сервера або невдале поновлення оренди можуть призвести до отримання нового номера, тоді як клієнт продовжить використовувати порт, збережений у його власній конфігурації. Дозвольте gluetun передавати його через VPN_PORT_FORWARDING_UP_COMMAND, який запускається одразу після активації port forwarding, або запустіть невеликий процес, що зчитує GET /v1/portforward із control server і записує це значення в клієнт через його API.
Як перевірити, що проброшений порт справді відкритий?
Запустіть listener на цьому самому порту в мережевому просторі імен gluetun і підключіться до нього ззовні VPN. Спочатку зупиніть torrent-клієнт, щоб порт був вільний, а потім запустіть upstream binary port-checker усередині контейнера gluetun за допомогою --listening-address=":<port>". Отримайте вихідну адресу з curl -s http://127.0.0.1:8000/v1/publicip/ip і відкрийте http://<address>:<port> на телефоні, підключеному через мобільну мережу. Запит у журналі port-checker підтверджує, що вхідний TCP-трафік надходить. Тайм-аут означає, що він не надходить, незалежно від того, що показує власний індикатор стану клієнта.