Ошибки сети в Plex: настройка доступа извне без VPN
Разбираем типичные проблемы с удалённым доступом к Plex: проброс портов, Docker-сети, обратный прокси и безопасность. Практические решения от системного инженера.
Почему Plex не видит внешний доступ: базовая диагностика
Проверка статуса удалённого доступа в веб-интерфейсе
Первое, что делаю, когда клиент жалуется «Plex не работает извне» — открываю Settings → Remote Access. Там всего два состояния, но люди почему-то игнорируют второе.
Fully accessible — идеальный случай. Порт проброшен, UPnP сработал (или вы настроили вручную), Plex подтвердил доступность через свои релейные серверы. Если видите зелёную галочку — проблема не в пробросе, ищите в другом месте: DNS, реверс-прокси, TLS-терминацию.
Not available outside your network — классика. Plex не смог дотянуться до себя извне. Нажмите Retry пару раз — иногда помогает, если UPnP на роутере «завис». Не помогло — идём в ручную.
В веб-интерфейсе показывается внешний IP, который Plex видит. Сравните его с тем, что выдаёт curl ifconfig.me с самого сервера. Если отличаетесь — у вас CGNAT, двойной NAT или провайдер подменяет IP. В таком случае «прямой» удалённый доступ не заработает без VPN или Tailscale. Об этом ниже.
Практический совет: не доверяйте только веб-интерфейсу. Откройте в браузере
http://<ваш-внешний-ip>:32400/web— если открывается, но Plex пишет «Not available», значит, его релейная проверка провалилась по таймауту или блокируется фаерволом на выходе.
Анализ логов Plex Media Server на предмет сетевых ошибок
Логи — единственное место, где Plex честно пишет, что происходит. В Docker они лежат в контейнере, на bare metal — в /var/lib/plexmediaserver/Library/Application Support/Plex Media Server/Logs/.
Ищем файл Plex Media Server.log (без даты в имени — это текущий). Два паттерна, которые покрывают 90 % случаев:
bash# В контейнере
docker exec -it plex grep -i "remote\|nat\|upnp\|public\|wan" /config/Library/Application\ Support/Plex\ Media\ Server/Logs/Plex\ Media\ Server.log | tail -30
# На хосте
grep -i "remote\|nat\|upnp\|public\|wan" "/var/lib/plexmediaserver/Library/Application Support/Plex Media Server/Logs/Plex Media Server.log" | tail -30
Типичные записи и что они означают:
| Запись в логе | Диагноз |
|---|---|
NAT-PMP/UPnP: Failed to map port | UPnP отключен на роутере или не работает. Настраивайте проброс вручную. |
PublishedServer: Failed to publish | Порт 32400 недоступен извне. Проверяйте фаервол, iptables -L -n, cloud-файрвол провайдера. |
Error checking for remote access: Timeout | Исходящие соединения к plex.tv блокируются. Проверьте egress-правила. |
MyPlex: Unable to connect to pubsub | Проблема с WebSocket к пуш-серверу Plex. Часто бывает за корпоративными прокси или при MTU < 1500. |
External IP changed from X to Y | Провайдер сменил IP. Если у вас динамический IP без DDNS — удалённый доступ сломается при каждой смене. |
Если в логах чисто, а веб-интерфейс показывает «Not available» — запустите ручную проверку доступности порта с внешнего хоста:
bash# С VPS или домашнего сервера друга
nc -zv <ваш-внешний-ip> 32400
# или
curl -I http://<ваш-внешний-ip>:32400/web
Ответ Connection refused — порт закрыт на уровне хоста/фаервола. Connection timed out — пакеты отбрасываются где-то по пути (роутер, провайдер, cloud-файрвол). HTTP/1.1 200 OK или 401 Unauthorized — порт открыт, Plex отвечает, проблема в самом сервисе Remote Access.
Из практики: на MikroTik часто забывают добавить
dst-natправило для входящего интерфейса, а не только дляdst-port. Проверяйте/ip firewall nat print where chain=dstnat.
Настройка проброса портов и Docker-сети
Правильный маппинг порта 32400 в docker-compose и host-режиме
Plex Media Server слушает порт 32400/TCP — это единственный порт, который должен быть доступен извне для работы Remote Access. Всё остальное (DLNA, mDNS, GDM) работает только внутри локальной сети и пробрасывать его наружу не нужно.
Вариант А: bridge-сеть с явным пробросом (рекомендую для большинства)
yamlservices:
plex:
image: lscr.io/linuxserver/plex:latest
container_name: plex
network_mode: bridge
ports:
- "32400:32400/tcp"
environment:
- PUID=1000
- PGID=1000
- TZ=Europe/Moscow
- VERSION=docker
- PLEX_CLAIM=claim-xxxxxxxxxxxxxxxx # получите на https://plex.tv/claim
volumes:
- /opt/plex/config:/config
- /mnt/media:/data
restart: unless-stopped
Ключевой момент: ports: - "32400:32400/tcp". Docker создаёт DNAT-правило в iptables — трафик, приходящий на порт 32400 хоста, попадает в контейнер. Никаких дополнительных манипуляций с iptables не требуется.
Частая ошибка: мапят UDP. Plex использует UDP только для SSDP (порт 1900) и GDM (порт 32410/32412/32413/32414) — всё это локальное обнаружение. Внутрь контейнера UDP 32400 не нужен.
Вариант Б: host-режим (когда bridge не подходит)
yamlservices:
plex:
image: lscr.io/linuxserver/plex:latest
container_name: plex
network_mode: host
environment:
- PUID=1000
- PGID=1000
- TZ=Europe/Moscow
- VERSION=docker
- PLEX_CLAIM=claim-xxxxxxxxxxxxxxxx
volumes:
- /opt/plex/config:/config
- /mnt/media:/data
restart: unless-stopped
С network_mode: host контейнер разделяет сетевой стек с хостом. Порт 32400 слушается напрямую на всех интерфейсах хоста. Проброс портов в ports не указывается — он игнорируется.
Когда оправдан host-режим:
- Нужно, чтобы Plex видел реальные IP клиентов без
X-Forwarded-For(важно для логов и геолокации) - Используете macvlan для других сервисов и хотите единый L2-сегмент
- Есть проблемы с hairpin NAT на роутере (клиенты внутри LAN не могут зайти на внешний IP)
Минусы host-режима: нет изоляции портов. Если на хосте уже висит что-то на 32400 — конфликт. Плюс контейнер получает доступ ко всем интерфейсам хоста, включая docker0, lo, VPN-туннели. С точки зрения безопасности — большая поверхность атаки.
Особенности работы с bridge- и macvlan-сетями для контейнера Plex
Bridge (default) — просто работает, но есть нюанс с hairpin NAT
В bridge-режиме контейнер получает внутренний IP (обычно 172.17.0.x или 172.18.0.x в пользовательских сетях). Docker настраивает DNAT на хосте. Из интернета — работает. Из локальной сети по внешнему IP — работает только если роутер поддерживает hairpin NAT (NAT loopback).
Проверка на роутере (пример для Keenetic):
ip nat loopback
На MikroTik:
/ip firewall nat add chain=srcnat action=masquerade src-address=192.168.1.0/24 dst-address=192.168.1.10 protocol=tcp dst-port=32400
где 192.168.1.10 — IP хоста с Plex.
Если hairpin NAT не настроен или роутер его не поддерживает — клиенты внутри LAN увидят таймаут при обращении к внешнему IP. Лечится либо настройкой роутера, либо split-DNS (локальный домен резолвится во внутренний IP хоста).
Macvlan — контейнер как полноценный хост в L2
yamlnetworks:
macvlan_net:
driver: macvlan
driver_opts:
parent: eth0
ipam:
config:
- subnet: 192.168.1.0/24
gateway: 192.168.1.1
ip_range: 192.168.1.200/29 # резервируем 192.168.1.200–206 для контейнеров
services:
plex:
image: lscr.io/linuxserver/plex:latest
container_name: plex
networks:
macvlan_net:
ipv4_address: 192.168.1.200
environment:
- PUID=1000
- PGID=1000
- TZ=Europe/Moscow
- VERSION=docker
- PLEX_CLAIM=claim-xxxxxxxxxxxxxxxx
volumes:
- /opt/plex/config:/config
- /mnt/media:/data
restart: unless-stopped
Контейнер получает свой MAC-адрес и IP 192.168.1.200 в той же подсети, что и хост. Для роутера и клиентов это отдельное устройство. Порт 32400 слушается на этом IP — никакого DNAT не нужно, проброс на роутере делается прямо на 192.168.1.200.
Важное ограничение macvlan: хост не может обратиться к контейнеру по его macvlan-IP (192.168.1.200). Это ограничение драйвера — трафик от хоста к macvlan-интерфейсу не проходит через parent-интерфейс.
Если на хосте крутится Nginx/Caddy как reverse proxy для Plex — в bridge-режиме прокси ходит на http://plex:32400 (Docker DNS резолвит внутренний IP). В macvlan — так не получится. Варианты:
- Добавить контейнер во вторую сеть (bridge) для общения с хостом
- Использовать
ipvlanвместоmacvlan(поддерживает L3-коммуникацию с хостом, но требует поддержки ядром и не работает на некоторых VPS) - Оставить Plex в bridge, а macvlan использовать для сервисов, которым нужен свой IP (Home Assistant, AdGuard Home, Pi-hole)
Что я использую у себя
На кластере Proxmox (три ноды: Винни-Пух, Пятачок, Сова) Plex крутится в LXC-контейнере на отдельной ноде с пробросом порта 32400 на роутере (MikroTik, hairpin NAT включён). Docker не использую для Plex — LXC даёт лучшую производительность (нет оверхеда overlayfs, прямой доступ к железу для транскодинга через Intel Quick Sync). Но если бы разворачивал в Docker — выбрал бы bridge с правильным hairpin NAT на роутере. Предсказуемость конфигурации важнее модных сетевых драйверов.
Обратный прокси через Nginx или Caddy: безопасная альтернатива
Конфигурация TLS-терминации и заголовков X-Forwarded-For
Прямой проброс 32400 во внешний мир — это работающий, но ленивый вариант. Вы отдаёте управление терминацией TLS самому Plex, теряете возможность централизованно управлять сертификатами и, что хуже всего, не видите реальные IP клиентов в логах. Обратный прокси решает всё это заодно.
С практической точки зрения, схема выглядит так: клиент → 443 (прокси) → 32400 (Plex в контейнере). Прокси снимает TLS, подставляет правильные заголовки и отдаёт трафик внутрь по HTTP. Plex при этом думает, что он работает за доверенным прокси — и это важно включить в его настройках.
Nginx. Конфиг для виртуального хоста plex.example.com:
nginxserver { listen 443 ssl http2; server_name plex.example.com; ssl_certificate /etc/letsencrypt/live/plex.example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/plex.example.com/privkey.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; # Plex требует большие тела для загрузки медиа client_max_body_size 100M; location / { proxy_pass http://plex:32400; proxy_http_version 1.1; # Обязательные заголовки — без них Plex не увидит реальные IP proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Port $server_port; # WebSocket для Plex Web и синхронизации proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; # Таймауты — Plex может долго думать при сканировании библиотек proxy_read_timeout 300s; proxy_send_timeout 300s; # Буферизация отключаем для стриминга proxy_buffering off; proxy_request_buffering off; } # Специфичный эндпоинт для DLNA — без него некоторые телевизоры не видят сервер location /dlna/ { proxy_pass http://plex:32400/dlna/; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } # Редирект HTTP → HTTPS server { listen 80; server_name plex.example.com; return 301 https://$host$request_uri; }
Caddy делает то же самое в 15 строк — за счёт автоматического ACME и разумных дефолтов:
caddyplex.example.com { reverse_proxy plex:32400 { header_up Host {host} header_up X-Real-IP {remote_host} header_up X-Forwarded-For {remote_host} header_up X-Forwarded-Proto {scheme} header_up X-Forwarded-Host {host} header_up X-Forwarded-Port {server_port} } }
Caddy сам выдаст и обновит сертификат Let's Encrypt. Никаких крон-задач, никаких certbot renew. Это тот случай, когда «просто работает» не маркетинг, а реальность.
Теперь главное — сказать Plex'у доверять этому прокси. В веб-интерфейсе: Settings → Network → Custom server access URLs — добавьте https://plex.example.com. И ниже, в List of IP addresses that are allowed to connect without auth (или в Preferences.xml вручную), укажите подсеть докер-хоста или IP самого прокси-контейнера:
xml<Preferences
...
trustedProxy="172.18.0.0/16,10.0.0.0/8"
...
/>
Маска /16 для docker-сети даёт запас — при пересоздании контейнера IP может смениться, но подсеть останется. Если используете network_mode: host — пропишите конкретный IP хоста.
Проверка: зайдите в Settings → Status → Remote Access. Должно гореть зелёное «Fully accessible outside your network» и виден ваш внешний хостнейм. В логах Plex (/config/Library/Application Support/Plex Media Server/Logs/Plex Media Server.log) теперь будут реальные IP клиентов, а не IP прокси.
Ограничение доступа по подсетям и базовая аутентификация
Прокси — это уже хорошо. Но порт 443 открыт для всего интернета, и боты начнут проверять, не Plex ли это, уже через час после появления А-записи. Два слоя защиты: сетевой (allow/deny) и приложенный (basic auth). Первый отсекает 99 % шума, второй — на случай, если IP утечёт или вы заходите из новой сети.
Nginx: allow/deny по подсетям. Допустим, у вас статический белый IP дома — 203.0.113.42. И вы хотите заходить с телефона через мобильный оператор — подсеть 100.64.0.0/10 (CGNAT диапазон РФ). Остальным — 403.
nginxlocation / { # Белый список allow 203.0.113.42; # домашний статический allow 100.64.0.0/10; # мобильные операторы РФ (CGNAT) allow 172.18.0.0/16; # внутренняя docker-сеть (для healthchecks) deny all; # остальным — 403 proxy_pass http://plex:32400; # ... остальные proxy_set_header из прошлого конфига }
Если статического IP нет — можно использовать GeoIP модуль и разрешать только страну, но это уже избыточно для домашнего сервера. Проще повесить basic auth.
Basic auth в Nginx. Генерируем файл паролей один раз:
bash# Установите apache2-utils (Debian/Ubuntu) или httpd-tools (RHEL/Fedora)
htpasswd -c /etc/nginx/.htpasswd plexuser
# Введите пароль дважды
Добавляем в location /:
nginxlocation / { allow 203.0.113.42; allow 100.64.0.0/10; allow 172.18.0.0/16; deny all; auth_basic "Plex Media Server"; auth_basic_user_file /etc/nginx/.htpasswd; proxy_pass http://plex:32400; # ... }
Теперь: с домашнего IP и мобильной сети — сразу в Plex. Из кафе, отеля, работы — браузер спросит логин/пароль. Боты получают 401/403 и уходят.
Важный нюанс: Plex Web App и мобильные клиенты умеют.basic auth. Но DLNA-устройства (телевизоры, приставки) — нет. Поэтому /dlna/ лучше оставить без аутентификации, но строго по подсетям:
nginxlocation /dlna/ { allow 172.18.0.0/16; # только внутренняя сеть allow 192.168.1.0/24; # ваша домашняя LAN deny all; proxy_pass http://plex:32400/dlna/; # заголовки... }
Caddy: то же самое, короче. Базовая аутентификация через basicauth (пароль в хеше bcrypt):
caddyplex.example.com { # Хэш пароля: caddy hash-password --plaintext 'ваш_пароль' basicauth { plexuser $2a$14$xxxxxxxxxxxxxxxxxxxxxx } @allowed { remote_ip 203.0.113.42 remote_ip 100.64.0.0/10 remote_ip 172.18.0.0/16 } @dlna path /dlna/* handle @dlna { @lan remote_ip 172.18.0.0/16 192.168.1.0/24 respond @lan 403 reverse_proxy plex:32400 { header_up Host {host} header_up X-Real-IP {remote_host} header_up X-Forwarded-For {remote_host} header_up X-Forwarded-Proto {scheme} } } handle @allowed { reverse_proxy plex:32400 { header_up Host {host} header_up X-Real-IP {remote_host} header_up X-Forwarded-For {remote_host} header_up X-Forwarded-Proto {scheme} header_up X-Forwarded-Host {host} header_up X-Forwarded-Port {server_port} } } respond "Access denied" 403 }
Синтаксис Caddy v2 с matchers (@allowed, @dlna) выглядит необычно, но даёт гибкость без копипасты location-блоков.
Что не забыть проверить после настройки:
curl -I https://plex.example.com— должен вернуть 200 или 401 (если не с разрешенного IP), но не 502/504.curl -u plexuser:password -I https://plex.example.com— 200 OK.- В логах Nginx/Caddy — реальные IP в
X-Forwarded-For, а не IP докер-хоста. - В логах Plex — те же IP, и статус «Fully accessible».
- Телевизор в домашней LAN видит Plex через DLNA без пароля.
Если всё сходится — вы сделали правильно. Порт 32400 на роутере можно закрыть, plex.example.com работает только через 443, сертификаты обновляются сами, а боты получают 403 на входе. Предсказуемость — вот она.
Тонкая настройка Plex для работы за прокси и NAT
Параметры customAccessUrl и publishedServerURL в Preferences.xml
Plex хранит свою конфигурацию в XML-файле. В контейнере он лежит по пути /config/Library/Application Support/Plex Media Server/Preferences.xml — на хосте маппится через volume. Редактировать его нужно когда сервер остановлен, иначе Plex перезапишет изменения при выходе.
Два параметра решают 90 % проблем с удалённым доступом за прокси:
xml<Preferences
...
customAccessUrl="https://plex.example.com"
publishedServerURL="https://plex.example.com:443"
...
/>
customAccessUrl — это адрес, который Plex отдаёт клиентам для подключения. Если вы сидите за Nginx/Caddy/Traefik, укажите сюда публичный URL с HTTPS. Порт не указывайте, если он стандартный (443).
publishedServerURL — адрес, по которому сам Plex считает, что он доступен извне. Используется для генерации ссылок в веб-интерфейсе, для DLNA-объявлений и для Plex Relay. Здесь порт нужен явно, даже если это 443.
Пример для типичной схемы: домашний сервер за CGNAT, доступ через VPS с Caddy:
xml<Preferences
MachineIdentifier="a1b2c3d4-e5f6-7890-abcd-ef1234567890"
ProcessedMachineIdentifier="a1b2c3d4e5f67890abcd"
customAccessUrl="https://plex.mydomain.ru"
publishedServerURL="https://plex.mydomain.ru:443"
...
/>
Если у вас несколько доменов (например, локальный plex.lan и внешний plex.mydomain.ru), customAccessUrl принимает список через запятую:
xmlcustomAccessUrl="https://plex.mydomain.ru,http://plex.lan:32400"
Plex попробует их по порядку. Первый доступный — и будет использован.
Важно: после правки XML обязательно перезапустите контейнер.
docker restart plex— и только потом проверяйте в веб-интерфейсе: Settings → Remote Access. Статус должен стать «Fully accessible».
Настройка доверенных сетей и отключение автоматического определения IP
По умолчанию Plex считает доверенными все сети, из которых видит входящие соединения. За обратным прокси это ломает авторизацию: Plex видит IP прокси (172.17.0.1 или 10.0.0.5) и считает его «локальным», не требуя аутентификацию. Или наоборот — помечает легитимные запросы как подозрительные.
Решается двумя параметрами в том же Preferences.xml:
xml<Preferences
...
trustedNetworks="192.168.1.0/24,10.8.0.0/24,172.20.0.0/16"
autoDetectNetworks="0"
...
/>
trustedNetworks — список CIDR, которые Plex считает безопасными. Сюда вписываете:
- вашу домашнюю подсеть (например, 192.168.1.0/24)
- подсеть WireGuard/Tailscale (10.8.0.0/24)
- Docker-сеть, в которой сидит прокси (172.20.0.0/16 — пример для
docker network create -d bridge --subnet=172.20.0.0/16 plex_net)
autoDetectNetworks="0" — отключает автоматическое расширение списка. Без этого Plex каждые несколько минут сканирует интерфейсы и добавляет всё, что видит. В контейнере это приводит к тому, что в доверенные попадает 172.17.0.0/16 (дефолтный bridge) и доступ без пароля открывается для любого контейнера на хосте.
Проверка: в веб-интерфейсе Settings → Network → «List of networks that are allowed without auth». Должен отображаться именно ваш список.
Типичная схема с Docker Compose
yamlservices:
plex:
image: lscr.io/linuxserver/plex:latest
container_name: plex
network_mode: "service:gluetun" # через VPN-контейнер, если нужно
# или: networks: [plex_net] # если без VPN
environment:
- PUID=1000
- PGID=1000
- TZ=Europe/Moscow
- VERSION=docker
volumes:
- /srv/plex/config:/config
- /srv/media:/media
restart: unless-stopped
caddy:
image: caddy:2-alpine
container_name: caddy
networks: [plex_net]
ports:
- "443:443"
- "80:80"
volumes:
- /srv/caddy/Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/data
- caddy_config:/config
restart: unless-stopped
networks:
plex_net:
driver: bridge
ipam:
config:
- subnet: 172.20.0.0/16
volumes:
caddy_data:
caddy_config:
Caddyfile:
plex.mydomain.ru {
reverse_proxy plex:32400
header_up X-Forwarded-Proto https
header_up X-Real-IP {remote_host}
}
В этом случае в trustedNetworks прописываете 172.20.0.0/16 — сеть, где живут оба контейнера. Plex будет видеть реальный IP клиента через заголовок X-Real-IP (Caddy передаёт его автоматически), а сеть прокси будет в доверенных.
Как проверить, что всё работает
- Остановите Plex:
docker stop plex - Отредактируйте Preferences.xml (см. выше)
- Запустите:
docker start plex - В логах ищите строку:
Published server URL: https://plex.mydomain.ru:443 - В веб-интерфейсе: Settings → Remote Access → «Fully accessible»
- Откройте
https://plex.mydomain.ru/webв браузере — должен войти без «Sign in with Plex» если вы в доверенной сети, и с авторизацией — если снаружи.
Если Remote Access показывает «Not available» — проверьте, что publishedServerURL указывает на порт 443, а не на 32400. Частая ошибка: пишут https://plex.mydomain.ru:32400 — так не заработает, наружу торчит только 443.
Часто задаваемые вопросы
Почему Plex показывает «Fully accessible», но извне всё равно не открывается?
Зелёная галочка в веб-интерфейсе означает только то, что релейные серверы Plex смогли дотянуться до вашего порта 32400 извне. Если при этом браузер по адресу http://<ваш-внешний-ip>:32400/web выдаёт таймаут или ошибку соединения, проблема чаще всего в фаерволе на самом сервере — ufw, firewalld или iptables блокируют входящие пакеты на этом порту. Проверьте ss -ltnp | grep 32400 и убедитесь, что процесс слушает на 0.0.0.0, а не только на 127.0.0.1. Ещё один частый случай — Docker-контейнер запущен с --network host, а вы пробрасываете порт на хосте, но внутри контейнера Plex привязан к другому интерфейсу.
Как настроить удалённый доступ, если провайдер выдаёт CGNAT или серый IP?
При CGNAT «прямой» проброс портов не сработает — пакеты просто не дойдут до вашего роутера. Есть три рабочих пути: заказать у провайдера белый статический IP (обычно платно), поднять VPS с публичным IP и пробросить трафик через WireGuard или Tailscale, либо использовать Tailscale Funnel / Cloudflare Tunnel для терминации TLS на их стороне. Последний вариант самый простой для домашней лаборатории: ставите cloudflared на сервер, настраиваете туннель на поддомен, и Plex становится доступен по HTTPS без открытых портов на роутере. Главное — в настройках Plex указать Custom server access URLs с вашим публичным хостом, иначе клиенты будут пытаться стучаться по локальному IP.
Зачем нужен обратный прокси перед Plex, если можно просто пробросить порт 32400?
Прямой проброс порта 32400 работает, но даёт три проблемы: трафик идёт в открытом виде (пароли и токены уходят в plaintext), нет возможности ограничить доступ по географии или IP, и вы не можете терминировать TLS вашим сертификатом. Nginx или Caddy перед Plex решают всё это: терминируют HTTPS, добавляют rate limiting, fail2ban банит брутфорс по логам прокси, а вы получаете единую точку входа для всех сервисов на одном домене. Конфиг Caddy для Plex занимает 10 строк и автоматически выдаёт/продлевает Let's Encrypt сертификаты — проще нет. Только не забудьте в настройках Plex отключить «Require HTTPS for connections» и указать прокси в X-Forwarded-For, иначе Plex будет видеть IP прокси вместо реальных клиентов.
Почему в логах Plex вижу «Error mapping NAT-PMP/UPnP port» и что с этим делать?
Эта запись означает, что Plex попытался автоматически открыть порт на роутере через UPnP или NAT-PMP и не смог — либо роутер не поддерживает эти протоколы, либо они отключены в настройках, либо сработало ограничение по количеству правил. Не тратьте время на борьбу с UPnP — он ненадёжен, не даёт обратной связи и часто ломается после перезагрузки роутера. Настройте статический проброс порта 32400 в веб-интерфейсе роутера вручную: внешний порт 32400 → внутренний IP сервера → порт 32400, протокол TCP. После этого в настройках Plex отключите «Manually specify public port» и нажмите «Retry» — Plex подхватит ручной проброс и покажет «Fully accessible».
Можно ли запускать Plex в Docker за обратным прокси без --network host?
Можно и нужно — --network host лишает вас изоляции сети и усложняет файрвол. Используйте обычную bridge-сеть Docker, пробросьте порт 32400 только на localhost (127.0.0.1:32400:32400), а Nginx/Caddy на хосте будет проксировать трафик на http://127.0.0.1:32400. В docker-compose.yml добавьте network_mode: bridge (по умолчанию) и переменную окружения PLEX_ADVERTISE_URL=http://<ваш-домен>:443/ — она заставит Plex отдавать клиентам правильные внешние URL для стриминга. Ещё один нюанс: для DLNA/устройств в локальной сети добавьте extra_hosts: - "plex.local:127.0.0.1" или настройте локальный DNS, иначе телевизоры не найдут сервер по хосту.