Всем добра.
Меня зовут Нариман, я full-stack разработчик по совместительству и 1С-разработчик по основному роду деятельности, и сегодня хочу рассказать короткую историю про инструмент под названием Nginx Proxy Manager. Признаюсь был удивлен, не найдя на него обзора на хабре, а потому тема своей первой статьи на хабре была предрешена.
Цель статьи простая — познакомить читателя с удобным инструментом для быстрого развёртывания проектов через понятный и наглядный web-интерфейс.
Материал ориентирован в первую очередь на новичков, которые только начинают делать первые шаги в DevOps (примерно как я сам в своё время).
Немного личного опыта
На заре своей бесславной карьеры в разработке ПО, когда я написал свой первый более-менее серьёзный проект на популярном стеке FastAPI + Vue, встал вполне логичный вопрос:
А как все задеплоить?
С кодом проблем не было, Docker я уже знал, но вот дальше начиналось самое интересное — Nginx.
Я довольно долго ковырялся с конфигами, читал статьи, смотрел примеры, пытался понять, почему здесь proxy_pass работает, а там — нет.
В итоге, да, я его настроил. Всё заработало. Но:
было потрачено несколько вечеров,
было страшно от мысли, что все это придется повторить еще раз
и главное — появилось ощущение, что я занимаюсь чем угодно, но не разработкой
Разумеется, в этот момент я переосмыслил ситуацию и пошел гуглить, а какие еще есть варианты. В итоге я вышел на героя рассказа нашей повести - Nginx Proxy Manager.
Но прежде чем мы начнем обзор Nginx Proxy Manager, ответим на один вопрос..
Зачем вообще нужен reverse proxy?
Как правило в большинстве проектов, приложение разбито на несколько блоков. Отдельно Backend для api, отдельно frontend для визуала сайта, часто еще несколько сопутствующих сервисов - minio, celery, RabbitMq.
И все это хозяйство надо как то между собой связать, причем в идеальном мире у нас есть отдельно develop и отдельно production окружение.
Если в dev-окружении мы просто запускаем команды локального запуска проекта, например:
npm run dev
то в production на нужно сначала сделать build проекта, а потом все это пробросить во внешний мир через reverse_proxy:
Сначала билдим проект:
npm run build
После этого появится папка build/ со статическими файлами:
build/
├── index.html
├── static/
│ ├── css/
│ └── js/
└── ...
Эти файлы — готовы к раздаче через веб-сервер (например, Nginx).
Пример минимальной конфигурации Nginx
Ниже пример, просто для понимания того, как будет происходить процесс в случае чистой установки Nginx и правки конфигов руками.
Создайте файл конфигурации, например:
/etc/nginx/sites‑available/my‑app
server {
listen 80;
server_name your-domain.com; # Или IP-адрес, или localhost для теста
root /path/to/your/my-app/build; # ← УКАЖИТЕ ПОЛНЫЙ ПУТЬ!
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
# Опционально: кэширование статики
location /static {
expires 1y;
add_header Cache-Control "public, immutable";
}
}
Шаги для активации:
Убедитесь, что путь в
rootправильный (например:/home/user/my-app/build)Активируйте сайт (на Ubuntu/Debian):
sudo ln -s /etc/nginx/sites-available/my-app /etc/nginx/sites-enabled/Проверьте конфигурацию:
sudo nginx -tПерезапустите Nginx:
sudo systemctl reload nginx
Итак каждый раз при любом добавлении нового хоста, или внесении правок к текущему. А еще нам нужно будет сгенерировать SSL сертификаты от Let’s Encrypt, следить за их актуальностью, и также их прописать в конфигурацию Nignx.
Все это вызывало одновременно ужас и восторг. Восторг от того, что спустя n-ое количество часов все это работало, ужас же от того, каждый раз когда я это делал, то приходилось по новой собирать всю информацию и все шаги проходит по новой.
Что такое Nginx Proxy Manager
Nginx Proxy Manager (NPM) — это бесплатный open-source инструмент с веб-интерфейсом, который упрощает настройку обратного прокси на базе Nginx. Вместо ручного редактирования десятков конфигурационных файлов вы управляете прокси-правилами, доменами и SSL-сертификатами через удобную панель в браузере.
Под капотом — тот же надёжный Nginx, но без необходимости помнить синтаксис server, location и proxy_pass. NPM автоматически выпускает и обновляет бесплатные сертификаты от Let’s Encrypt, поддерживает пользовательские домены, базовую аутентификацию и отлично ложится в Docker-экосистему.
Именно поэтому он стал де-факто стандартом для домашних лабораторий, разработчиков и тех, кто хочет быстро и безопасно выставить локальный сервис в интернет — без единой строчки конфигурации.

Быстрый старт: поднимаем NPM через Docker Compose
В отдельной папке нашего сервера, создадим папку для запуска NPM через docker-compose. В отдельной папке, потому что у нас, могут быть несколько docker compose проектов, а обслуживать его будет один NPM.
Я создал каталог nginx-pr-manager в каталоге /home и уже в нем создал файл docker-compose.yml. А также два каталога nginx-pr-manager/data и nginx-pr-manager/letsencrypt, для хранения конфигов и сертификатов.
services:
app:
image: 'jc21/nginx-proxy-manager:latest'
container_name: nginx-proxy-manager
restart: unless-stopped
ports:
- '80:80' # HTTP
- '81:81' # Админ-панель NPM
- '443:443' # HTTPS
volumes:
- ./data:/data
- ./letsencrypt:/etc/letsencrypt
Запускаем контейнер простой командой:
docker-compose up -d
Первичная настройка
После успешного запуска переходим в браузер по адресу вашего сервера с указанием порта 81 (например, http://localhost:81 или http://<ip-вашего-сервера>:81).
Вас встретит окно авторизации. Используйте стандартные учетные данные, которые заданы разработчиком по умолчанию:
Email:
admin@example.comPassword:
changeme
Сразу после входа система попросит вас сменить почту и пароль на свои. Не пропускайте этот шаг ради безопасности.

Связываем NPM с нашими сервисами
Тут есть важный нюанс. Так как мы запустили Nginx Proxy Manager отдельным изолированным контейнером, он ничего не знает о ваших других проектах. Если вы попытаетесь указать ему http://my-super-app:3000, он просто не найдет этот хост.
Чтобы решить эту проблему и «подружить» контейнеры из разных docker-compose файлов, есть самый правильный и элегантный способ — создать внешнюю Docker-сеть.
Каюсь, я часто опускаю этот шаг, и вместо создания отдельной сети для контейнеров, использую просто IP адрес сервера и порт на котором работает docker контейнер.
Решение: Создаем общую сеть
Создаем сеть вручную в терминале:
docker network create public_net-
Добавляем эту сеть в
docker-compose.ymlнашего Nginx Proxy Manager:
Открываем конфиг NPM и добавляем секцию networks внизу и указываем её для сервиса:services:
app:
image: 'jc21/nginx-proxy-manager:latest'
# остальные настройки (ports, volumes, environment) ...
networks:
- public_netnetworks:
public_net:
external: trueНе забудьте перезапустить контейнер NPM:
docker-compose down && docker-compose up -d Добавляем эту же сеть в
docker-compose.ymlвашего приложения:
Допустим, у вас есть ваш проект. Делаем то же самое:
version: "3.9"
services:
db:
image: postgres:15-alpine
container_name: postgres_db
restart: always
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: password
POSTGRES_DB: my_database
volumes:
- db_data:/var/lib/postgresql/data
networks:
- internal_net
pgadmin:
image: dpage/pgadmin4
container_name: pgadmin_panel
restart: unless-stopped
environment:
PGADMIN_DEFAULT_EMAIL: admin@admin.com
PGADMIN_DEFAULT_PASSWORD: admin
depends_on:
- db
networks:
- internal_net
- public_net
backend:
build:
context: ./backend
container_name: fastapi_app
restart: unless-stopped
environment:
DATABASE_URL: postgresql://user:password@db:5432/my_database
depends_on:
- db
networks:
- internal_net
- public_net
frontend:
build:
context: ./frontend
container_name: vue_app
restart: unless-stopped
networks:
- public_net
networks:
internal_net:
driver: bridge
public_net:
external: true
volumes:
db_data:
Теперь, когда оба контейнера находятся в одной сети public_net, NPM сможет обращаться к вашему приложению просто по имени контейнера: http://backend:8000.
Настройка проксирования в интерфейсе
Теперь самое приятное. Никаких конфигов и консоли.
Заходим в админку NPM.
Идем во вкладку Hosts -> Proxy Hosts.
-
Жмем кнопку Add Proxy Host. открывшемся окне заполняем основные поля:

Форма добавления нового хоста в Nginx Proxy Manager
Domain Names: Ваш домен (например,
api.mysite.com). > Важно: У регистратора домена A-запись уже должна указывать на IP вашего сервера.Scheme:
http(обычно связь между контейнерами идет по http).Forward Hostname / IP: Имя контейнера вашего приложения (в нашем примере
my-backend-app) или IP адрес сервера, если не настраивали сеть.Forward Port: Порт, на котором работает ваше приложение внутри контейнера (например,
8000).

Рекомендую также сразу проставить галочки:
Block Common Exploits — базовая защита от простых атак.
Websockets Support — если ваше приложение использует сокеты.

Магия SSL в два клика
Вспомните, как нужно было ставить certbot, запускать скрипты, прописывать пути к ключам в конфиге Nginx... Забудьте.
В этом же окне настройки хоста переходим на вкладку SSL:
В выпадающем списке SSL Certificate выбираем:
Request a new SSL Certificate.Включаем переключатель Force SSL (чтобы был автоматический редирект с http на https).
Вводим email для Let's Encrypt и соглашаемся с условиями.
Жмем Save.
NPM сам сходит к Let's Encrypt, подтвердит владение доменом (через 80 порт), скачает сертификаты, положит их в нужное место и сам перепишет конфиг Nginx. Через 10-15 секунд у вас будет рабочий сайт с зеленым замочком HTTPS.
Более того, он сам будет следить за сроком действия сертификатов и автоматически их продлевать.
Важный нюанс, вы должны для всех доменов для которых хотите получить SSL- сертификат, настроить А-запись указав имя вашего сервера, на котором развернут Nginx Proxy Manager.


Итоги
Что мы получили в итоге?
Экономия времени. Развертывание нового поддомена занимает ровно 1 минуту.
Наглядность. Весь список ваших ресурсов перед глазами, вы видите, куда и что проксируется.
Безопасность. SSL-сертификаты ставятся и обновляются автоматически, исключая человеческий фактор («ой, забыл продлить»).
Никакой боли с конфигами. Вы больше не боитесь пропустить точку с запятой в
/etc/nginx/sites-available/default.
Конечно, для масштабных Enterprise-проектов с тысячами RPS (requests per second) и сложной балансировкой, возможно, потребуется чистый и оптимизированный вручную Nginx или ingress-ко��троллеры в Kubernetes. Но для стартапов, пет-проектов, домашнего сервера или фриланс-заказов Nginx Proxy Manager — это тот самый «швейцарский нож», который должен быть в арсенале каждого разработчика.
Пробуйте, экспериментируйте и не пишите конфиги руками, если это можно не делать.
Всем удачного деплоя
OFrol
Вместо конфигов, написание и деплой которых отлично автоматизируется, вы предлагаете кликать мышкой в интерфейсе для каждого нового сервиса. Удобство тут так себе, на мой взгляд.
По существу вопроса: если у вас уже и так есть docker, то логично его использовать в качестве service discovery. Например, можно поставить Traefik или Caddy, и конфигурировать эндпоинты и https для сервисов в самих сервисах.
Всё что вам нужно, это поднять один контейнер с Traefik или Caddy и настроить их на получение конфигурации из соседних docker-контейнеров.
Например, вот docker-compose.yml для какого-то сервиса MY_SUPER_SERVICE, обратите внимание на labels:
Это единственная конфигурация, которую вам нужно будет сделать для каждого нового сервиса. Traefik сам обнаружит появление нового контейнера, сам получит для него LE-сертификат для домена
SERVICE.example.comи сам будет этот сертификат обновлять когда требуется. И так же сам всё подчистит, когда вы этот контейнер удалите.Никаких веб-интерфейсов и ручного труда - вы просто делаете
docker compose up -dдля своего сервиса и через несколько десятков секунд получаете работающий эндпоинт с httpsbaldr
Кроме того, конфигурация, накликанная мышкой на страничке довольно сложно бэкапится, копируется и переносится.
Это ок если вы один - можно всё запомнить. А вот как только появяется в команде хотя бы ещё один человек - то сразу возникают вопросы - кто, что, когда и как поменял?
Он, конечно, все настройки сохраняет в стандартный конфиг nginx, и можно его оттуда в git закачивать. Но где вы это будете делать - на продакшен-сервере? (на всех?).
Вызывает некоторое уважение список из 851 открытых issue на Github, а также 88 висящих pull-requests. Первая страница багов - только в течение последнего месяца. Встречаются совсем глупые, которые бы должны тестироваться вовремя. Есть серьёзные уязвимости безопасности, которые не чинятся годами. В общем, я бы не спешил это ставить себе.