Контейнеры · :443

Nginx Proxy Manager на Synology: полная настройка

Единая точка входа для всех сервисов на NAS: сертификаты Let's Encrypt, DNS-челлендж без открытого 80-го порта и то, что конфликтует с самим DSM ещё до первого запуска.

Зачем реверс-прокси, если можно пробросить порты напрямую

Nginx Proxy Manager (NPM) даёт графический интерфейс для того, что иначе пришлось бы держать в голове и в десятке конфигов nginx вручную: маршрутизацию доменов на внутренние порты контейнеров и автоматическое продление сертификатов Let's Encrypt. Но главная причина держать его перед всеми сервисами — не удобство, а то, что наружу в интернет теперь смотрит один порт 443, а не десяток разных портов для каждого сервиса, каждый со своим сертификатом (или вовсе без него).

Главная ловушка на Synology: DSM уже занял 80 и 443

Если на NAS включены Web Station, стандартный DSM-портал по HTTPS или собственный реверс-прокси в Панели управления → Логин-портал → Дополнительно, порты 80 и 443 уже заняты системой ещё до того, как вы запустите первый контейнер NPM — и он просто не поднимется с ошибкой address already in use.

⚠ проверьте это в первую очередь
В Панели управления → Портал входа → Дополнительно отключите встроенный реверс-прокси DSM, либо смените порты самого DSM (Панель управления → Сеть → Настройка портов DSM) на нестандартные, например 5001/5002. Иначе конфликт портов будет выглядеть как "сломанный" NPM, хотя проблема на уровне DSM.

Что понадобится перед стартом

Шаг 1 — подготовка каталогов

ssh · admin@nas
mkdir -p /volume1/docker/nginx-proxy-manager/data
mkdir -p /volume1/docker/nginx-proxy-manager/letsencrypt

Папка data хранит встроенную базу SQLite с настройками всех Proxy Host'ов, а letsencrypt — сами сертификаты и учётные данные ACME. Актуальные версии образа NPM (2.11+) используют встроенный SQLite и не требуют отдельного контейнера с MariaDB — раньше это было обязательным шагом, сейчас лишняя сложность для домашнего использования.

Шаг 2 — docker-compose.yml

docker-compose.yml
services:
  app:
    image: jc21/nginx-proxy-manager:2.12
    container_name: nginx-proxy-manager
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
      - "127.0.0.1:81:81"
    environment:
      DISABLE_IPV6: "true"
    volumes:
      - /volume1/docker/nginx-proxy-manager/data:/data
      - /volume1/docker/nginx-proxy-manager/letsencrypt:/etc/letsencrypt
    mem_limit: 256m

Порт админ-панели 81 забинжен на 127.0.0.1, а не на все интерфейсы — панель управления сертификатами и правилами маршрутизации не должна быть доступна откуда угодно из локальной сети, не говоря уже об интернете. Доступ к ней — через SSH-туннель или отдельный Proxy Host с ограничением по IP (шаг 10).

Шаг 3 — первый вход и смена пароля

После docker compose up -d откройте http://IP_NAS:81 (или через туннель, если порт забинжен локально) и войдите с данными по умолчанию:

учётные данные по умолчанию
Email:    admin@example.com
Password: changeme
⚠ смените сразу, без исключений
Эти данные одинаковы для каждой установки NPM в мире и известны любому, кто хоть раз читал документацию проекта. Смените email и пароль администратора в первую же минуту после входа, до создания первого Proxy Host.

Шаг 4 — Proxy Host: домен, WebSocket, форс-HTTPS

При создании нового Proxy Host для каждого внутреннего сервиса — по аналогии с тем, как это делалось для Vaultwarden — важны три переключателя, которые часто оставляют по умолчанию:

nginx proxy manager → hosts → proxy host domain names vault.мойдомен.ру forward hostname / ip · port 192.168.1.10 : 8080 websockets support ✓ block common exploits ✓ force ssl ✓ http/2 support ✓

Шаг 5 — сертификаты без открытого порта 80 (DNS-01)

Стандартный способ подтверждения домена для Let's Encrypt (HTTP-01) требует, чтобы порт 80 был доступен из интернета. Это не работает в двух частых ситуациях: провайдер использует CGNAT (нет реального внешнего IP) или нужен wildcard-сертификат вида *.мойдомен.ру, который HTTP-01 в принципе не поддерживает.

Решение — DNS-01 challenge через API вашего DNS-провайдера. Для Cloudflare это выглядит так: в NPM при выпуске сертификата выбираете DNS Challenge, провайдера Cloudflare и API-токен с правами на редактирование DNS-зоны:

cloudflare credentials (в интерфейсе npm)
dns_cloudflare_api_token = ваш_api_токен_с_правами_dns_edit
✓ совет
Создайте отдельный API-токен именно с правом Zone.DNS: Edit только для нужной зоны — а не полный Global API Key от всего аккаунта Cloudflare. Компрометация NPM в этом случае не даст доступа ко всему остальному аккаунту.

Advanced-конфигурация: заголовки безопасности

Вкладка Advanced в настройках Proxy Host позволяет добавить произвольные директивы nginx поверх сгенерированного конфига. Базовый набор заголовков безопасности, который стоит добавить почти везде:

advanced · custom nginx configuration
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Strict-Transport-Security "max-age=63072000" always;

Strict-Transport-Security добавляйте с осторожностью: браузер запомнит требование HTTPS для домена на указанный срок, и откатиться на обычный HTTP для тестов будет неудобно, пока не истечёт max-age.

Ограничение доступа к панели администратора

Создайте в NPM отдельный Access List с разрешённым диапазоном локальной подсети и привяжите его к Proxy Host, через который вы всё же решите открыть админ-панель наружу (например, для доступа из другого города):

ПараметрЗначение
Satisfyany / all — обычно all с Basic Auth поверх IP-фильтра
Allow192.168.1.0/24 (локальная подсеть)
Denyall (всё остальное)

Если удалённый доступ к самой панели вам не нужен в принципе — проще оставить порт 81 забинженным на 127.0.0.1, как в шаге 2, и заходить только через SSH-туннель.

Бэкапы

Как и в остальных сервисах на NAS, бэкапить нужно ровно то, что определяет состояние сервиса — здесь это оба тома целиком:

npm-backup.sh
#!/bin/bash
STAMP=$(date +%Y%m%d-%H%M)
DEST=/volume1/docker/nginx-proxy-manager/backups
mkdir -p "$DEST"
tar -czf "$DEST/npm-$STAMP.tar.gz" \
    -C /volume1/docker/nginx-proxy-manager data letsencrypt
find "$DEST" -name "npm-*.tar.gz" -mtime +14 -delete

Восстановление из такого архива на новый NAS занимает пару минут: разворачиваете тома, поднимаете тот же compose-файл — все Proxy Host'ы и сертификаты возвращаются как есть, без повторной ручной настройки каждого домена.

Частые проблемы

СимптомВероятная причина
Контейнер не стартует, «address already in use»порты 80/443 заняты встроенным Web Station или логин-порталом DSM
502 Bad Gatewayневерный внутренний IP/порт в Forward Hostname, либо сам сервис ещё не поднялся
Сертификат не выпускается по HTTP-01провайдер использует CGNAT — порт 80 недоступен снаружи, нужен DNS-01
Зависает синхронизация / реалтайм-обновленияне включён Websockets Support для этого Proxy Host
Бесконечный редирект «too many redirects»Force SSL включён одновременно с похожей настройкой на самом внутреннем сервисе
Не получается зайти в панель :81 снаружипорт намеренно забинжен на 127.0.0.1 — используйте SSH-туннель или Access List

После того как встроенный реверс-прокси DSM отключён, домены выпускают сертификаты по DNS-01, а панель администратора закрыта от внешнего доступа — NPM можно спокойно считать единственной точкой входа для всего остального стека на NAS.