bolt Valebyte VPS від $4/міс — NVMe, запуск за 60 секунд.

Отримати VPS arrow_forward
eco Початковий Туторіал

Nginx Proxy Manager: SSL і домени для всіх контейнерів на одному VPS

calendar_month Sep 15, 2026 schedule 20 хв. читання visibility 79 переглядів
Nginx Proxy Manager: SSL и домены для всех контейнеров на одном VPS
info

Потрібен сервер для цього гайду? Ми пропонуємо виділені сервери та VPS у 50+ країнах з миттєвим налаштуванням.

Потрібен сервер для цього гайду?

Розгорніть VPS або виділений сервер за хвилини.

Nginx Proxy Manager: SSL і домени для всіх контейнерів на одному VPS

TL;DR

Nginx Proxy Manager дає змогу розмістити десятки Docker-контейнерів на одному VPS, надати кожному окремий домен або піддомен і автоматично випускати SSL-сертифікати Let’s Encrypt без ручного налаштування Nginx.

  • Одна публічна IP-адреса обслуговує кілька сайтів, API, панелей керування та self-hosted-сервісів.
  • Nginx Proxy Manager приймає HTTP/HTTPS-трафік на портах 80 і 443 та передає його потрібному контейнеру у внутрішній Docker-мережі.
  • SSL-сертифікати Let’s Encrypt випускаються та продовжуються автоматично через веб-інтерфейс.
  • Адмін-панель Nginx Proxy Manager не можна залишати відкритою для всього інтернету без додаткового захисту.
  • Для невеликого набору сервісів зазвичай достатньо VPS із 2 vCPU, 2–4 ГБ RAM і SSD-диском від 30 ГБ.
  • Критичні дані — Docker Compose-файли, томи Nginx Proxy Manager, база SQLite або MariaDB і резервні копії застосунків — потрібно регулярно вивантажувати за межі VPS.

Що ми налаштовуємо і навіщо

Схема: Що ми налаштовуємо і навіщо
Схема: Що ми налаштовуємо і навіщо

Типовий VPS швидко перетворюється на набір сервісів: GitLab або Gitea, Mattermost, Vaultwarden, Nextcloud, Grafana, домашня сторінка, API застосунку, тестові стенди та панелі моніторингу. Кожен контейнер зазвичай слухає свій внутрішній порт: 3000, 8080, 9000, 5000 або інший. Відкривати всі ці порти в інтернет незручно й небезпечно.

Nginx Proxy Manager, далі NPM, розв’язує це завдання як reverse proxy з веб-інтерфейсом. Він приймає запити на стандартних портах HTTP 80 і HTTPS 443, визначає домен із заголовка Host і перенаправляє трафік до потрібного контейнера. Наприклад, запит до git.example.com надсилається в Gitea, chat.example.com — у Mattermost, а status.example.com — в Uptime Kuma.

У результаті зовнішньому користувачеві неважливо, на якому порту насправді працює застосунок. Усі сервіси доступні за зрозумілими HTTPS-адресами, а на VPS достатньо відкрити лише SSH, HTTP і HTTPS. Внутрішні порти застосунків залишаються закритими Docker-мережею.

Підсумкова схема

У цьому посібнику використовуватиметься така архітектура:

  • Один VPS з Ubuntu Server 24.04 LTS.
  • Docker Engine і Docker Compose Plugin.
  • Nginx Proxy Manager в окремому Docker Compose-проєкті.
  • Спільна зовнішня Docker-мережа proxy.
  • Кілька застосунків, підключених до цієї мережі.
  • DNS-записи доменів типу app.example.com, що вказують на IP VPS.
  • Let’s Encrypt для безкоштовних TLS-сертифікатів.

Потік запиту матиме такий вигляд: браузер відкриває https://vault.example.com → DNS повертає IP VPS → NPM приймає запит на порту 443 → NPM завершує TLS → NPM передає HTTP до внутрішнього контейнера Vaultwarden через Docker-мережу.

Що ви отримаєте після налаштування

  • Єдину точку входу для всіх контейнерів на сервері.
  • HTTPS для кожного домену без ручного створення конфігурацій Nginx.
  • Автоматичне продовження сертифікатів Let’s Encrypt.
  • Можливість увімкнути WebSocket, access list, базову авторизацію та перенаправлення через UI.
  • Ізоляцію сервісів: застосунки не зобов’язані публікувати порти на IP VPS.
  • Простіше перенесення інфраструктури: конфігурація зберігається в Compose-файлах і Docker volumes.

Які є альтернативи

Підхід Переваги Обмеження
Cloud-managed ingress або load balancer Висока доступність, керовані сертифікати, менше адміністрування Щомісячна вартість, залежність від хмари, часто надмірно для одного VPS
Звичайний Nginx вручну Максимальна гнучкість, звичні конфіги, висока продуктивність Потрібно самостійно писати virtual host-конфіги, налаштовувати Certbot і оновлення
Traefik Зручна автоматизація через Docker labels, добре підходить для великої кількості сервісів Конфігурація через labels і middleware може бути складнішою для новачка
Caddy Проста конфігурація, автоматичний HTTPS, компактний Caddyfile Менше візуального керування, частина завдань потребує ручної роботи з конфігом
Nginx Proxy Manager Зрозумілий UI, Let’s Encrypt, access lists, proxy hosts без ручного Nginx Додаткова панель керування, необхідно захищати адміністративний доступ

Для solo-розробника, маленької команди або власника одного VPS NPM зручний тим, що не вимагає тримати в голові синтаксис Nginx під час додавання чергового сервісу. Він не скасовує потреби розуміти мережі, DNS і безпеку, але значно зменшує кількість ручних операцій.

Nginx Proxy Manager не замінює firewall. Навіть якщо сервіс доступний лише через проксі, відкриті Docker-порти можуть обійти правила UFW. Публікуйте порти застосунків лише на 127.0.0.1 або не публікуйте взагалі.

Яка VPS-конфігурація потрібна для цього завдання

Схема: Яка VPS-конфігурація потрібна для цього завдання
Схема: Яка VPS-конфігурація потрібна для цього завдання

Сам Nginx Proxy Manager споживає небагато ресурсів. На чистому сервері його контейнер зазвичай вкладається в сотні мегабайт RAM, а TLS-операції помітно навантажують CPU лише за великої кількості нових з’єднань. Ресурси потрібно обирати насамперед для застосунків за проксі: GitLab, Nextcloud, бази даних, ігрові сервери та CI значно важчі за сам NPM.

Сценарій CPU RAM Диск Мережа
NPM + 2–5 легких сервісів 2 vCPU 2 ГБ 30 ГБ SSD 100 Мбіт/с
NPM + Nextcloud, Gitea, Mattermost, моніторинг 2–4 vCPU 4–8 ГБ 80–160 ГБ NVMe 100 Мбіт/с або 1 Гбіт/с
Багато користувачів, файли, CI, бази даних 4–8 vCPU 8–16 ГБ 160 ГБ+ NVMe 1 Гбіт/с

Практичний стартовий варіант для NPM, Vaultwarden, Uptime Kuma, Gitea та невеликого API — 2 vCPU, 4 ГБ RAM, 60–80 ГБ NVMe і 1 Гбіт/с. За потреби можна взяти VPS із зазначеними характеристиками або аналогічний тариф в іншого провайдера. Важливіше за назву тарифу — наявність виділеного публічного IPv4, стабільної мережі, доступу через SSH і можливості створювати snapshots.

Чому потрібен публічний IP

Для стандартної HTTP-01 перевірки Let’s Encrypt сервер має бути доступним ззовні на порту 80. Якщо VPS перебуває за CGNAT або має лише приватний IP, автоматичний випуск сертифіката через звичайну HTTP-перевірку не спрацює. У такому разі потрібен публічний IPv4, публічний IPv6 із коректним DNS або DNS-01 challenge через DNS-провайдера.

Коли потрібен dedicated, а не VPS

Для одного reverse proxy dedicated-сервер не потрібен. Він стає виправданим, коли за проксі працюють важкі сервіси: великий GitLab із CI-runner, файлове хмарне сховище з терабайтами даних, транскодування відео, високонавантажена база даних, десятки тисяч запитів за секунду або вимоги до передбачуваної продуктивності диска.

Також dedicated варто розглядати за високого мережевого трафіку, великої кількості одночасних TLS-з’єднань, вимог до кількох фізичних дисків у RAID і коли віртуалізація сусідів на VPS є неприпустимою за політикою безпеки. Для 5–30 внутрішніх сервісів невеликої команди зазвичай достатньо якісного VPS.

Як вибрати локацію

Локація VPS впливає на затримку, вимоги законодавства та швидкість початкового завантаження. Якщо основна аудиторія перебуває в Європі, обирайте європейський дата-центр; якщо користувачі в Казахстані, Росії, Туреччині або на Близькому Сході, попередньо виміряйте ping до кількох локацій. Для адмін-панелей різниця між 20 і 60 мс майже непомітна, але для ігор, голосових сервісів, API та файлового сховища вона важливіша.

Не розміщуйте сервер лише з огляду на близькість до себе, якщо сервісом користується команда з іншої країни. Також перевірте, чи дозволені потрібні порти, чи є reverse DNS за потреби поштових сервісів і чи доступні резервні сховища в іншій локації.

Підготовка сервера

Нижче передбачається свіжий сервер з Ubuntu Server 24.04 LTS і входом під користувачем root. Якщо у вас Debian 12 або Debian 13, логіка залишається тією самою, але окремі команди встановлення пакетів можуть відрізнятися. Перед налаштуванням доменів створіть A-записи: наприклад, npm.example.com, vault.example.com і status.example.com повинні вказувати на публічний IPv4 сервера.

Оновіть систему та створіть адміністратора

Виконуйте початкове налаштування через SSH. Замість admin вкажіть власне ім’я користувача, а замість прикладу публічного ключа вставте ключ із файлу ~/.ssh/id_ed25519.pub на локальному комп’ютері.

apt update && apt upgrade -y
apt install -y sudo curl ca-certificates gnupg fail2ban ufw vim git
adduser admin
usermod -aG sudo admin

Команда оновлює систему, встановлює базові утиліти, Fail2ban і UFW, а потім створює користувача з правами sudo.

install -d -m 700 -o admin -g admin /home/admin/.ssh
nano /home/admin/.ssh/authorized_keys
chmod 600 /home/admin/.ssh/authorized_keys
chown admin:admin /home/admin/.ssh/authorized_keys

Цей блок створює каталог SSH і додає публічний ключ. Вставте ключ одним рядком, збережіть файл і не закривайте поточну root-сесію до перевірки нового входу.

ssh -i ~/.ssh/id_ed25519 admin@SERVER_IP

Команда перевіряє, що новий користувач справді може підключитися за ключем. Відкрийте окреме вікно термінала та переконайтеся, що вхід виконується без пароля.

Вимкніть парольний вхід SSH

Після успішної перевірки відредагуйте окремий файл конфігурації SSH. Це безпечніше, ніж змінювати основний файл /etc/ssh/sshd_config, який може оновлюватися менеджером пакетів.

sudo nano /etc/ssh/sshd_config.d/99-hardening.conf

Додайте такі параметри:

PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
X11Forwarding no
MaxAuthTries 3
sudo sshd -t && sudo systemctl restart ssh

Команда перевіряє синтаксис конфігурації і лише потім перезапускає SSH. Якщо перевірка повернула помилку, не перезапускайте сервіс, доки не виправите файл.

Налаштуйте firewall і Fail2ban

NPM повинен отримувати зовнішні підключення на 80 і 443. SSH бажано обмежити IP-адресою офісу або домашнього VPN, але для першого запуску можна тимчасово залишити доступ з будь-якого IP. Docker має особливості взаємодії з UFW, тому головний захист контейнерів — не публікувати їхні порти назовні.

sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status verbose

Команди забороняють вхідний трафік за замовчуванням і дозволяють лише SSH, HTTP і HTTPS. Пізніше можна додати обмеження SSH за вихідним IP або перенести доступ до панелі NPM за VPN.

sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd

Цей блок запускає Fail2ban і показує стан jail для SSH. Fail2ban зменшує ефект перебору паролів, але не замінює ключі SSH, оновлення та обмеження доступу.

Перевірте DNS до випуску сертифіката

Сертифікат Let’s Encrypt не буде видано, доки DNS-запис не вказує на поточний сервер. Перевіряйте запис із VPS і, бажано, через зовнішні DNS-резолвери.

getent hosts npm.example.com
curl -4 ifconfig.me
dig +short npm.example.com A @1.1.1.1

IP, який повертає DNS, повинен збігатися з публічним IPv4 VPS. Якщо DNS ще поширюється, зачекайте TTL запису. Не створюйте десятки невдалих запитів сертифіката: Let’s Encrypt застосовує rate limits.

Встановлення ПЗ — покроково

Схема: Встановлення ПЗ — покроково
Схема: Встановлення ПЗ — покроково

Для Nginx Proxy Manager використовуйте Docker Engine з офіційного репозиторію Docker, а не застарілий пакет docker.io зі стандартного репозиторію Ubuntu. Станом на 2026 рік актуальна гілка Docker Engine 29 підтримує Compose Plugin; конкретний номер мінорної версії перевіряйте перед встановленням в офіційній документації Docker.

Встановіть Docker Engine і Compose Plugin

sudo apt remove -y docker.io docker-compose docker-compose-v2 podman-docker containerd runc || true
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg

Команди видаляють конфліктні старі пакети та додають GPG-ключ офіційного Docker-репозиторію.

echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Цей блок додає репозиторій і встановлює Docker Engine, containerd, Buildx і сучасний Compose Plugin.

sudo usermod -aG docker admin
newgrp docker
docker version
docker compose version

Команда додає користувача до групи Docker і виводить версії Docker та Compose. Врахуйте, що членство в групі docker фактично надає привілеї рівня root. Не додавайте до неї звичайних користувачів застосунків.

Створіть спільну Docker-мережу

Контейнери, до яких NPM повинен звертатися через внутрішній DNS Docker, підключатимуться до однієї зовнішньої мережі. Це краще, ніж прокидати порти кожного застосунку на публічний інтерфейс сервера.

docker network create proxy
docker network inspect proxy

Команди створюють bridge-мережу proxy і показують її параметри. У майбутньому NPM зможе звертатися до контейнера за іменем сервісу, наприклад vaultwarden або uptime-kuma.

Створіть каталог Nginx Proxy Manager

mkdir -p ~/stacks/nginx-proxy-manager
cd ~/stacks/nginx-proxy-manager
mkdir -p data letsencrypt
chmod 700 data letsencrypt

Цей блок створює робочий каталог і постійні директорії. У data NPM зберігає конфігурацію та SQLite-базу, а в letsencrypt — сертифікати й дані ACME.

Підготуйте Compose-файл

Для невеликого VPS можна використовувати вбудовану SQLite-базу. Це мінімізує кількість контейнерів і достатньо для одного екземпляра NPM. У великих установках і за вимог до резервування зазвичай використовують MariaDB, але для одного reverse proxy SQLite простіше в обслуговуванні.

nano compose.yml

Вставте конфігурацію із закріпленим образом NPM гілки 2.12.3. Перед новим розгортанням перевіряйте GitHub Releases проєкту та changelog: не замінюйте стабільний тег на latest без тестування.

services:
  npm:
    image: jc21/nginx-proxy-manager:2.12.3
    container_name: nginx-proxy-manager
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
      - "127.0.0.1:81:81"
    environment:
      TZ: "Europe/Berlin"
    volumes:
      - ./data:/data
      - ./letsencrypt:/etc/letsencrypt
    networks:
      - proxy

networks:
  proxy:
    external: true

Порти 80 і 443 опубліковані для всього інтернету, а адміністративний порт 81 прив’язаний лише до 127.0.0.1. Це важливий безпечний варіант: панель не буде доступною безпосередньо за http://SERVER_IP:81.

docker compose pull
docker compose up -d
docker compose ps
docker logs --tail=100 nginx-proxy-manager

Команди завантажують образ, запускають стек у фоновому режимі, показують стан контейнера та останні логи. Статус повинен бути Up. Якщо контейнер перезапускається, перевірте логи повністю.

Відкрийте адміністративну панель через SSH-тунель

Оскільки порт 81 доступний лише локально на VPS, створіть тунель із робочого комп’ютера. Команда виконується на вашому локальному комп’ютері, а не на сервері.

ssh -L 8181:127.0.0.1:81 admin@SERVER_IP

Поки SSH-сесія відкрита, перейдіть у браузері за адресою http://127.0.0.1:8181. Для першого входу використовуйте стандартні дані NPM: email [email protected], пароль changeme. Відразу після входу інтерфейс запропонує змінити email і пароль.

Не публікуйте порт 81 через 81:81, якщо немає суворої необхідності. Навіть із надійним паролем адмін-панель не повинна бути зайвою публічною поверхнею атаки.

Конфігурація

Схема: Конфігурація
Схема: Конфігурація

Тепер налаштуємо приклад із двома застосунками: Vaultwarden і Uptime Kuma. Вони працюватимуть без зовнішніх опублікованих портів. NPM побачить їх через спільну мережу proxy, а користувачі звертатимуться до них через домени vault.example.com і status.example.com.

Розгорніть тестові контейнери

Створіть окремий Compose-проєкт. Не зберігайте секрети у вихідному коді та не публікуйте їх у Git. Для Vaultwarden використовуйте файл .env з правами лише для власника.

mkdir -p ~/stacks/apps
cd ~/stacks/apps
nano .env
chmod 600 .env

До файлу .env додайте довгий випадковий пароль. Його можна згенерувати командою openssl rand -base64 48.

VAULTWARDEN_ADMIN_TOKEN=replace_with_a_long_random_secret
TZ=Europe/Berlin
nano compose.yml
services:
  vaultwarden:
    image: vaultwarden/server:1.34.3
    container_name: vaultwarden
    restart: unless-stopped
    environment:
      DOMAIN: "https://vault.example.com"
      WEBSOCKET_ENABLED: "true"
      ADMIN_TOKEN: "${VAULTWARDEN_ADMIN_TOKEN}"
      TZ: "${TZ}"
      SIGNUPS_ALLOWED: "false"
    volumes:
      - ./vaultwarden-data:/data
    networks:
      - proxy

  uptime-kuma:
    image: louislam/uptime-kuma:1.23.16
    container_name: uptime-kuma
    restart: unless-stopped
    volumes:
      - ./uptime-kuma-data:/app/data
    networks:
      - proxy

networks:
  proxy:
    external: true

У цьому прикладі немає секції ports. Контейнери доступні лише сусідам у мережі proxy. Якщо застосунку потрібен доступ до бази даних, базу також підключайте до окремої внутрішньої мережі та не публікуйте її порт 3306, 5432 або 6379 назовні.

docker compose up -d
docker compose ps
docker network inspect proxy

Команди запускають застосунки та перевіряють, що контейнери підключені до мережі. У виводі docker network inspect proxy мають з’явитися nginx-proxy-manager, vaultwarden і uptime-kuma.

Перевірте внутрішню зв’язність

Перед створенням proxy host переконайтеся, що NPM бачить цільові контейнери. Усередині контейнера NPM можна виконати HTTP-запит за Docker DNS-іменем. Vaultwarden за замовчуванням використовує порт 80, Uptime Kuma — 3001.

docker exec nginx-proxy-manager curl -I http://vaultwarden:80
docker exec nginx-proxy-manager curl -I http://uptime-kuma:3001

Для Vaultwarden очікується HTTP-відповідь на кшталт 200, 301 або 302. Для Uptime Kuma також допустима відповідь перенаправлення. Помилка Could not resolve host означає, що контейнер не підключений до мережі proxy.

Створіть Proxy Host для Vaultwarden

Відкрийте SSH-тунель до панелі, перейдіть до Hosts → Proxy Hosts → Add Proxy Host і заповніть поля:

  • Domain Names: vault.example.com
  • Scheme: http
  • Forward Hostname / IP: vaultwarden
  • Forward Port: 80
  • Cache Assets: вимкнено для першого запуску
  • Block Common Exploits: увімкнено
  • Websockets Support: увімкнено

На вкладці SSL виберіть Request a new SSL Certificate, вкажіть email для Let’s Encrypt, увімкніть Force SSL, HTTP/2 Support і погодьтеся з умовами Let’s Encrypt. Потім збережіть запис.

Для HTTP-01 challenge домен має вести на VPS, а вхідний порт 80 має бути доступний. NPM сам використовує вбудовану ACME-логіку, аналогічну Certbot: вручну встановлювати Certbot або Caddy поверх NPM не потрібно й не можна, оскільки вони конкуруватимуть за порти 80 і 443.

Створіть Proxy Host для Uptime Kuma

Додайте другий host аналогічно, але з іншими значеннями:

  • Domain Names: status.example.com
  • Scheme: http
  • Forward Hostname / IP: uptime-kuma
  • Forward Port: 3001
  • Websockets Support: увімкнено
  • Block Common Exploits: увімкнено

На вкладці SSL знову запросіть окремий сертифікат. Можна випустити один сертифікат на кілька доменів, але окремі сертифікати простіше обслуговувати та вони безпечніші з погляду ізоляції. Wildcard-сертифікат потребуватиме DNS-01 challenge і API DNS-провайдера.

Налаштуйте access list для внутрішніх панелей

Не всі сервіси мають бути доступні всім користувачам. Наприклад, адмін-панель, Grafana, Portainer або тестове API краще закрити Basic Auth і, якщо можливо, списком дозволених IP. У NPM перейдіть до Access Lists → Add Access List, створіть список admins-only, додайте користувача з довгим паролем і на вкладці Access вкажіть дозволені CIDR-мережі.

Після цього виберіть створений список у налаштуваннях потрібного Proxy Host. Basic Auth — додатковий рівень, а не заміна автентифікації самого застосунку. Для критично важливих панелей краще використовувати WireGuard, Tailscale або SSH-тунель.

Додаткові параметри proxy host

Деякі застосунки потребують передавання реального IP клієнта, збільшеного ліміту завантаження або тривалих таймаутів. NPM уже додає стандартні proxy headers, але в поле Advanced можна додати безпечні директиви для конкретного host:

client_max_body_size 2g;
proxy_connect_timeout 60s;
proxy_send_timeout 3600s;
proxy_read_timeout 3600s;
send_timeout 3600s;

Такий приклад потрібен для завантаження великих файлів у Nextcloud або аналогічний сервіс. Не вставляйте випадкові директиви з форумів у глобальну конфігурацію: помилка синтаксису може зламати генерацію конфігурацій Nginx для всіх доменів.

Перевірте HTTPS і сертифікат

curl -I https://vault.example.com
curl -I https://status.example.com
curl -Iv https://vault.example.com 2>&1 | grep -E "SSL certificate verify|subject:|issuer:"

Відповідь має містити успішний HTTP-код і не повинна видавати помилку перевірки TLS. Якщо використовується Cloudflare у режимі проксування, для початкової діагностики тимчасово вимкніть proxy-режим запису або переконайтеся, що його SSL-режим не конфліктує з origin-сертифікатом.

docker logs --tail=100 nginx-proxy-manager
docker exec nginx-proxy-manager nginx -t

Ці команди показують логи NPM і перевіряють синтаксис згенерованої конфігурації Nginx. Виконуйте їх після зміни складних advanced-налаштувань або за помилок 502/503.

Резервні копії та обслуговування

Схема: Резервні копії та обслуговування
Схема: Резервні копії та обслуговування

Nginx Proxy Manager можна швидко відтворити, але без резервної копії ви втратите proxy hosts, access lists, користувачів, сертифікати та налаштування. Окрім NPM необхідно окремо резервувати дані застосунків: каталоги Nextcloud, Vaultwarden, Git-репозиторії, бази PostgreSQL і MariaDB, файли Mattermost і конфігурації Compose.

Що потрібно включити до резервної копії

Об’єкт Де розташований Навіщо потрібен
NPM data ~/stacks/nginx-proxy-manager/data SQLite-база, proxy hosts, користувачі, налаштування
Let’s Encrypt ~/stacks/nginx-proxy-manager/letsencrypt Сертифікати, акаунт ACME, ключі
Compose-файли та .env ~/stacks Відтворюване розгортання та секрети
Дані застосунків bind mounts або named volumes Користувацькі файли, бази, конфігурація
Дампи БД окремий каталог backup Консистентне відновлення PostgreSQL/MariaDB

Не вважайте snapshot VPS повноцінним бекапом. Snapshot корисний перед оновленням, але якщо він зберігається в тому самому акаунті або дата-центрі, він не захищає від видалення акаунта, компрометації облікового запису або аварії у провайдера. Використовуйте правило 3-2-1: щонайменше три копії, на двох типах сховища, одна поза основним сервером.

Простий бекап із Restic у S3

Restic підтримує шифрування на боці клієнта та S3-сумісні сховища. Створіть окремий bucket, окремого користувача з доступом лише до цього bucket і збережіть ключі у закритому файлі.

sudo apt install -y restic
sudo install -d -m 700 /root/.config/restic
sudo nano /root/.config/restic/env
sudo chmod 600 /root/.config/restic/env

Додайте до файлу змінні доступу. Значення замініть даними вашого S3-сховища.

export RESTIC_REPOSITORY="s3:https://s3.example-storage.net/server-backups/npm-vps"
export RESTIC_PASSWORD="use_a_long_unique_backup_password"
export AWS_ACCESS_KEY_ID="YOUR_ACCESS_KEY"
export AWS_SECRET_ACCESS_KEY="YOUR_SECRET_KEY"
sudo bash -c 'source /root/.config/restic/env && restic init'

Команда створює новий зашифрований репозиторій. Пароль RESTIC_PASSWORD зберігайте окремо від VPS: у password manager або офлайн-сховищі. Втрата цього пароля робить резервні копії невідновлюваними.

sudo nano /usr/local/sbin/backup-stacks.sh
sudo chmod 700 /usr/local/sbin/backup-stacks.sh

Створіть скрипт:

#!/usr/bin/env bash
set -euo pipefail

source /root/.config/restic/env

STAMP=$(date +%F)
BACKUP_DIR="/root/backup-work/$STAMP"

mkdir -p "$BACKUP_DIR"

docker exec vaultwarden /bin/sh -c 'sqlite3 /data/db.sqlite3 ".backup /data/db-backup.sqlite3"' || true

restic backup /home/admin/stacks \
  --exclude='/node_modules' \
  --exclude='/cache' \
  --tag docker-stacks

restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune
restic check

Скрипт зберігає каталоги стеків, видаляє старі знімки згідно з політикою зберігання та перевіряє репозиторій. Для застосунків із PostgreSQL або MariaDB перед бекапом додайте pg_dump або mariadb-dump; копіювання файлів активної бази без дампа може дати пошкоджену або логічно неконсистентну копію.

sudo crontab -e

Додайте щоденний запуск уночі:

15 3   * /usr/local/sbin/backup-stacks.sh >> /var/log/backup-stacks.log 2>&1

Після налаштування обов’язково виконайте відновлення до тестового каталогу. Бекап вважається робочим лише після успішної перевірки відновлення.

sudo bash -c 'source /root/.config/restic/env && restic snapshots'
sudo mkdir -p /root/restore-test
sudo bash -c 'source /root/.config/restic/env && restic restore latest --target /root/restore-test'

Оновлення NPM і контейнерів

Для одного VPS оптимальна модель maintenance window: виберіть період, наприклад раз на два тижні, зробіть бекап, прочитайте release notes і оновлюйте по одному стеку за раз. Rolling update корисний у кластері з кількома репліками, але на одиночному сервері зазвичай не забезпечує високої доступності: перезапуск NPM на 10–30 секунд усе одно короткочасно розірве з’єднання.

cd ~/stacks/nginx-proxy-manager
docker compose pull
docker compose up -d
docker image prune -f
docker compose ps

Команди завантажують образ, відтворюють контейнер у разі зміни версії, видаляють невикористовувані dangling-образи та показують підсумковий статус. Спочатку фіксуйте версію образу в compose.yml, потім оновлюйте її свідомо. Не запускайте бездумно docker system prune -a --volumes: команда здатна видалити дані, які Docker вважає невикористовуваними.

Раз на місяць перевіряйте оновлення ОС, строк дії сертифікатів, розмір логів і вільне місце:

sudo apt update && sudo apt upgrade -y
df -h
docker system df
openssl s_client -connect vault.example.com:443 -servername vault.example.com < /dev/null 2>/dev/null | openssl x509 -noout -dates

Усунення несправностей + FAQ

Чому під час випуску сертифіката Let’s Encrypt з’являється Internal Error або timeout?

Спочатку перевірте DNS: домен має повертати IP саме цього VPS. Потім переконайтеся, що порт 80 відкритий в UFW, у панелі провайдера та не зайнятий іншим контейнером або Nginx на хості. Виконайте sudo ss -lntp | grep -E ":80|:443" і перевірте, що порти прослуховує Docker. Якщо використовується CDN-проксі, тимчасово вимкніть його для діагностики. Також перевірте docker logs nginx-proxy-manager і не перевищуйте ліміти Let’s Encrypt повторними спробами.

Чому Nginx Proxy Manager повертає 502 Bad Gateway?

Помилка 502 майже завжди означає, що NPM не може підключитися до upstream-контейнера. Перевірте ім’я контейнера, внутрішній порт і Docker-мережу. Виконайте docker exec nginx-proxy-manager curl -I http://SERVICE:PORT. Якщо ім’я не резолвиться, обидва контейнери не перебувають у мережі proxy. Якщо з’єднання відхилено, застосунок прослуховує інший порт або не запустився. Не вказуйте в полі Forward Hostname публічний домен самого VPS: це може створити петлю проксі.

Чому домен відкривається через HTTP, але не перенаправляється на HTTPS?

Відкрийте налаштування відповідного Proxy Host і переконайтеся, що сертифікат вибрано, а перемикач Force SSL увімкнено. Якщо сертифікат не було випущено, NPM не зможе безпечно перенаправити на HTTPS. Перевірте, чи не використовується окремий DNS-запис IPv6 AAAA, що веде на інший сервер: браузер може підключатися через IPv6, а ви перевіряєте IPv4. Команди dig A domain і dig AAAA domain допомагають швидко побачити розбіжності.

Яка конфігурація VPS мінімально підійде?

Для одного Nginx Proxy Manager і кількох легких контейнерів мінімально розумний варіант — 2 vCPU, 2 ГБ RAM, 30 ГБ SSD і публічний IPv4. Один vCPU та 1 ГБ RAM можуть працювати для тесту, але оновлення, TLS-операції та сусідні сервіси швидко впруться в пам’ять. Для Vaultwarden, Uptime Kuma, невеликої Gitea і reverse proxy краще одразу вибрати 2 vCPU, 4 ГБ RAM і 60 ГБ NVMe.

Що вибрати — VPS чи dedicated для цього завдання?

Для Nginx Proxy Manager, особистих сервісів і невеликої команди обирайте VPS: він дешевший, швидше розгортається та зазвичай легко масштабується за CPU, RAM і диском. Dedicated виправданий не через проксі, а через навантаження застосунків за ним: великого GitLab, важкої бази даних, терабайтового файлового сховища, CI, відеообробки або дуже високого трафіку. Якщо сервер обслуговує менше кількох десятків активних користувачів, VPS найчастіше достатньо.

Чому застосунок працює через IP і порт, але не працює через домен?

Перевірте налаштування Proxy Host: правильний scheme, ім’я контейнера та порт. Багато застосунків генерують посилання, cookies і redirect URL на основі змінних на кшталт DOMAIN, URL, ROOT_URL або PUBLIC_URL. Укажіть там зовнішній HTTPS-домен, а не http://localhost:PORT. Для сервісів із WebSocket увімкніть Websockets Support. Після зміни змінних середовища перезберіть контейнер через docker compose up -d.

Чи потрібно відкривати порти застосунків, наприклад 3000, 8080 або 3001, в UFW?

Ні, якщо NPM і застосунок підключені до однієї Docker-мережі. Не додавайте правила UFW для внутрішніх портів і не публікуйте їх через ports. NPM звертається до сервісу за ім’ям контейнера всередині мережі Docker. Виняток — налагодження, але навіть тоді безпечніше тимчасово прив’язати порт до 127.0.0.1, наприклад 127.0.0.1:3001:3001, і підключатися через SSH-тунель.

Як безпечно відкрити адмін-панель NPM?

Найкращий простий варіант — залишити порт 81 прив’язаним до 127.0.0.1 і використовувати SSH-тунель. Для постійного доступу можна створити окремий proxy host із HTTPS, access list і додатковою автентифікацією, але це збільшує зовнішню поверхню атаки. Надійніший підхід — доступ до панелі лише через WireGuard або Tailscale. Завжди змінюйте стандартні облікові дані, використовуйте унікальний пароль і регулярно оновлюйте контейнер.

Висновки та наступні кроки

Схема: Висновки та наступні кроки
Схема: Висновки та наступні кроки

Тепер один VPS може обслуговувати кілька Docker-застосунків через окремі домени з автоматичним HTTPS. Nginx Proxy Manager приховує внутрішні порти контейнерів, централізує TLS-сертифікати та спрощує додавання нових сервісів.

  1. Додайте моніторинг доступності доменів через Uptime Kuma та налаштуйте сповіщення в Telegram, email або Mattermost.
  2. Перенесіть адміністративні інтерфейси за WireGuard або Tailscale, а публічними залиште лише сервіси, призначені для користувачів.
  3. Налаштуйте регулярну перевірку відновлення резервних копій і документуйте домени, контейнери, порти та секрети в закритому репозиторії або password manager.

Коли кількість сервісів зросте, розділіть застосунки за Compose-проєктами, обмежте ресурси контейнерів і розгляньте окрему базу даних або другий VPS для резервних копій і моніторингу.

Чи був цей гайд корисним?

Ваш відгук допомагає нам покращувати гайди.

Share this post:

Надішліть гайд тому, кому він може стати в пригоді.

Telegram VKVK WhatsApp Facebook LinkedIn XX

nginx proxy manager: ssl і домени для всіх контейнерів на одному vps
support_agent
Valebyte Support
Usually replies within minutes
Hi there!
Send us a message and we'll reply as soon as possible.