Как установить и настроить Portainer на VPS
Десяток контейнеров ещё держится в голове, тридцать — уже нет: docker ps уезжает за край терминала, а нужный лог ищется по памяти. Portainer даёт веб-панель ко всему, что крутится на сервере, но установка «в одну команду» оставляет открытый в интернет порт, самоподписанный сертификат и окно, в котором админа может создать кто угодно. Ниже — установка Portainer на VPS так, чтобы потом ничего не переделывать: compose-файл с закреплённой версией, админ без гонки с таймаутом, нормальный HTTPS и бэкап базы панели.
Содержание
- Что вы ставите: версии, теги и граница между CE и BE
- Подготовка VPS перед установкой Portainer
- Установка Portainer через compose-файл
- Первый вход без гонки с пятиминутным таймаутом
- HTTPS: Caddy перед панелью вместо самоподписанного сертификата
- Второй хост, обновления и бэкап панели
- Какой сервер взять под Portainer в MAATRIX
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Что вы ставите: версии, теги и граница между CE и BE
Portainer CE — веб-интерфейс к Docker: контейнеры, образы, тома, сети, логи и консоль внутрь контейнера в браузере, плюс стеки — те же compose-файлы из редактора. Магии нет: панель ходит в сокет /var/run/docker.sock и дёргает тот же API, что и docker.
Каналов релизов два: LTS — стабильный, для продакшена, и STS — быстрый, с новыми функциями. На конец августа 2026:
| Ветка | Вышла | Поддержка до | Теги образа |
|---|---|---|---|
| 2.45 LTS | август 2026 | май 2027 | 2.45.0, lts, latest |
| 2.44 STS | июль 2026 | до следующего STS | 2.44.0, sts |
| 2.39 LTS | февраль 2026 | ноябрь 2026 | 2.39.7 |
alpine и alpine-sts — те же сборки на Alpine, образ весит около 45 МБ в сжатом виде. Указывайте точную версию (portainer/portainer-ce:2.45.0), а не latest: иначе очередной docker compose pull подтянет новую ветку не вовремя, и вы займётесь миграцией базы вместо своей задачи.
Честно про границу редакций. В CE есть пользователи, команды и владение ресурсами, но нет ролевой модели: RBAC с семью ролями, шаблоны OAuth/OIDC (Google, GitHub, Entra ID, Okta) и журнал действий — это Business Edition. Нужно «выдать разработчику три контейнера и видеть, кто что перезапускал» — планируйте BE сразу: до трёх нод лицензия бесплатная, ключ продлевается раз в год, образ portainer/portainer-ee.
Подготовка VPS перед установкой Portainer
Берём чистый VPS с Ubuntu 24.04 LTS или Debian 13 и root-доступом, ставим Docker: curl -fsSL https://get.docker.com | sh, затем systemctl enable --now docker. Проверка docker --version && docker compose version в августе 2026 даёт Docker version 29.7.2 и Docker Compose version v2.x. Portainer заведётся и на старых ветках, но всё ниже 26.x уже без обновлений безопасности.
Дальше фаервол — здесь главная грабля установки:
ufw default deny incoming
ufw allow 22/tcp
ufw allow 80,443/tcp
ufw enable
Кажется, всё, кроме SSH и веба, закрыто. Это не так: Docker при публикации порта пишет правила прямо в iptables (цепочки DOCKER и DOCKER-USER), и они обрабатываются раньше правил ufw. Контейнер с -p 9443:9443 доступен из интернета, хотя ufw status показывает deny (incoming). Проверьте с другой машины nmap -Pn -p 9443 203.0.113.10: ответ 9443/tcp open значит, что панель видна сканерам. Поэтому её порт мы не публикуем — привязываем к 127.0.0.1, а наружу смотрит только реверс-прокси на 80 и 443.
Последнее — DNS: заведите A-запись portainer.example.com на IP сервера и проверьте dig +short portainer.example.com, иначе Let's Encrypt не даст сертификат.
Развернуть за пару минут
Готовый образ на VPS MAATRIX: NVMe, AMD EPYC, root-доступ. Локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Развернуть PortainerУстановка Portainer через compose-файл
docker run одной строкой хорош ровно один раз: через месяц никто не вспомнит, с какими флагами поднимался контейнер. Конфигурацию кладём в файл: mkdir -p /opt/portainer && cd /opt/portainer.
Сначала пароль администратора: минимум 12 символов, записать без завершающего перевода строки — иначе \n уедет в базу вместе с паролем.
printf '%s' "$(openssl rand -base64 18)" > /opt/portainer/admin_password
chmod 600 /opt/portainer/admin_password && cat /opt/portainer/admin_password
Сохраните его в менеджер паролей. Теперь /opt/portainer/compose.yaml:
services:
portainer:
image: portainer/portainer-ce:2.45.0
container_name: portainer
restart: unless-stopped
command: --http-disabled --admin-password-file /run/secrets/portainer_admin
ports:
- "127.0.0.1:9443:9443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- portainer_data:/data
secrets:
- portainer_admin
secrets:
portainer_admin:
file: ./admin_password
volumes:
portainer_data:
Что здесь важно:
--admin-password-fileсоздаётadminпри старте, минуя экран первичной настройки. Пароль идёт файловым секретом в/run/secrets/, а не светится вdocker inspect, как с--admin-password.--http-disabledвыключает HTTP-порт 9000, а привязка127.0.0.1:9443:9443оставляет панель видимой только с хоста — защита от граблей с ufw./var/run/docker.sockдаёт панели полный контроль над Docker: это суть её работы и главный риск, доступ к сокету равносилен root на хосте.- Том
portainer_dataхранит базу настроек: без него пересоздание контейнера обнулит учётки, окружения и стеки.
Поднимаем docker compose up -d и смотрим docker compose logs --tail 20 portainer: в логе должна быть строка вида starting Portainer | version=2.45.0 и ни одной с failed. Аппетиты скромные — docker stats --no-stream portainer на узле 2 vCPU / 4 ГБ показывает 71.9MiB / 3.84GiB и 0.28% CPU. Ресурсы съест не панель, а контейнеры.
Первый вход без гонки с пятиминутным таймаутом
Типичный сценарий: запустили контейнер, отвлеклись на звонок, вернулись через десять минут — и вместо формы регистрации:
Your Portainer instance timed out for security purposes.
To re-enable your Portainer instance, you will need to restart Portainer.
Это не баг. Свежая панель без администратора — открытая дверь: кто первым дошёл до формы, тот и хозяин сервера. На создание первого пользователя даётся пять минут, дальше форма блокируется — лечится командой docker restart portainer.
В конфигурации выше этой гонки нет: администратор создан из секрета при первом запуске, экран первичной настройки не появляется. Вы входите логином admin и паролем из /opt/portainer/admin_password. Пока прокси не настроен, до панели добираются SSH-туннелем ssh -L 9443:127.0.0.1:9443 root@203.0.113.10, но спешить некуда.
После первого входа включите двухфакторную аутентификацию (My account → Two-factor authentication) и уберите пароль с диска: удалите из compose.yaml блок secrets и флаг --admin-password-file, выполните docker compose up -d, затем shred -u /opt/portainer/admin_password. Флаг нужен только при первом запуске. Окружение local подключать не нужно, панель сама находит сокет.
HTTPS: Caddy перед панелью вместо самоподписанного сертификата
Portainer отдаёт интерфейс по HTTPS с самоподписанным сертификатом: браузер ругается каждый раз, а корпоративные политики его иногда не пропускают. Ставим перед панелью Caddy — он сам получит и продлит сертификат Let's Encrypt, без certbot и cron. Файл /opt/portainer/Caddyfile:
portainer.example.com {
reverse_proxy https://portainer:9443 {
transport http {
tls
tls_insecure_skip_verify
}
}
}
Сервис в compose.yaml:
caddy:
image: caddy:2-alpine
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data
- caddy_config:/config
В блок volumes допишите caddy_data: и caddy_config:. Первый обязателен: в нём лежат сертификаты и ACME-аккаунт, иначе каждое пересоздание контейнера запрашивает новый сертификат и упирается в лимит Let's Encrypt — пять выпусков на один набор доменов в неделю.
Строка tls_insecure_skip_verify выглядит подозрительно, но здесь обязательна: без неё Caddy не примет самоподписанный сертификат Portainer, отдаст 502 и напишет в лог:
tls: failed to verify certificate: x509: certificate signed by unknown authority
Проверять сертификат бэкенда, до которого трафик не покидает хост, смысла нет. Альтернатива — проксировать на http://portainer:9000 без --http-disabled: проще, но внутри docker-сети трафик пойдёт открытым, что допустимо на одной машине и не годится между серверами.
Поднимаем docker compose up -d и проверяем curl -sI https://portainer.example.com | head -1: ответ HTTP/2 200 означает, что сертификат выпущен, панель работает по домену, а 9443 закрыт. При постоянных IP добавьте в блок домена @blocked not remote_ip 203.0.113.7 198.51.100.0/24 и respond @blocked 403. Честный минус: с динамическим IP такой список — ловушка, однажды вы получите 403 из отпуска. Тогда лучше оставить вход открытым, но с 2FA и длинным паролем, либо пускать в панель через WireGuard.
Второй хост, обновления и бэкап панели
Одна панель управляет несколькими хостами — на дополнительном сервере поднимается агент:
docker run -d --name portainer_agent --restart=always \
-p 10.8.0.3:9001:9001 \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /var/lib/docker/volumes:/var/lib/docker/volumes \
portainer/agent:2.45.0
Порт опубликован на адрес 10.8.0.3 — приватная сеть или WireGuard-интерфейс. Агент не защищён паролем: отдадите 9001 на 0.0.0.0 — подарите первому сканеру root на этом сервере, а ufw deny, как мы помним, не спасает. Без приватной сети закрывайте порт правилом iptables -I DOCKER-USER -p tcp --dport 9001 ! -s 203.0.113.10 -j DROP. Хост добавляется в Environments → Add environment → Docker Standalone → Agent.
Обновление — смена тега в compose.yaml и docker compose pull && docker compose up -d. Важно: схема базы мигрирует вперёд, и откатить тег назад не выйдет — панель не стартует на «слишком новой» базе. Перед сменой ветки (2.39 → 2.45) снимайте архив тома:
docker run --rm -v portainer_data:/data:ro -v /root/backups:/backup alpine \
tar czf /backup/portainer-$(date +%F).tar.gz -C /data .
Архив небольшой — единицы мегабайт даже на панели с десятками контейнеров: база хранит только настройки панели, пользователей, окружения и стеки. Отсюда важное: бэкап Portainer не является бэкапом ваших сервисов, тома с базами и файлы приложений резервируются отдельно.
Встроенный механизм тоже есть: Settings → Backup Portainer — архив с шифрованием паролем вручную или по расписанию, с выгрузкой в S3 либо Azure Blob; локальные копии ложатся в /data/scheduled-backups/, восстановление — вкладка Restore from backup на экране входа.
Какой сервер взять под Portainer в MAATRIX
Сама панель почти ничего не стоит: образ около 45 МБ, в простое 70 МБ памяти и доли процента CPU. Сервер выбирают не под Portainer, а под то, что под ним крутится.
| Профиль | vCPU | RAM | NVMe | На что хватит |
|---|---|---|---|---|
| Минимум | 1 | 2 ГБ | 25 ГБ | Панель, Caddy и 3–5 лёгких контейнеров: статика, бот, API |
| Рабочий | 2 | 4 ГБ | 50 ГБ | Плюс PostgreSQL, Redis, очередь, staging рядом с продом |
| Комфортный | 4 | 8 ГБ | 100+ ГБ | Сборка образов, десяток сервисов, мониторинг, запас на пики |
Честно про нижнюю границу: на 1 ГБ Portainer запустится, но первая же сборка через docker build или тяжёлый запрос к контейнерной СУБД упрутся в память, и OOM-killer погасит не тот процесс. Один гигабайт — стенд, а не прод.
Диск заканчивается быстрее, чем ожидают: слои старых образов и брошенные тома копятся молча. Расход смотрят через docker system df, чистят docker image prune -a (снесёт все образы, не используемые ни одним контейнером). Ограничьте и логи: в /etc/docker/daemon.json задайте "log-driver": "json-file" и "log-opts": { "max-size": "10m", "max-file": "3" }, затем systemctl restart docker — иначе разговорчивый контейнер за месяц съест десятки гигабайт. Настройка касается новых контейнеров, старые нужно пересоздать.
Локация. Если под панелью европейские сервисы, берите UK, Лондон: 5–25 мс до европейских точек обмена, 45–60 мс до Москвы (для веб-интерфейса неощутимо), плюс GDPR-соседство для клиентов из ЕС. Российская аудитория и персональные данные по 152-ФЗ — RU-площадка. Контейнеры, которые ходят к зарубежным ИИ-API, — US, Нью-Йорк: чистые IP и прямой доступ.
Оплата у MAATRIX идёт картой российского банка, через СБП, криптовалютой или токеном MAAT — иностранная карта не нужна даже для лондонской площадки. Апгрейд делается без переезда: тома и контейнеры остаются на месте, а Portainer после ресайза поднимется сам благодаря restart: unless-stopped.
Развернуть за пару минут
Готовый образ на VPS MAATRIX: NVMe, AMD EPYC, root-доступ. Локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Развернуть PortainerОбсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Частые вопросы
Какой тег образа ставить — latest, lts или точный номер?
Для продакшена точный номер вроде portainer/portainer-ce:2.45.0: обновление тогда происходит в запланированный момент. lts годится для домашнего стенда, latest предсказуемости не даёт.
Можно ли обойтись без монтирования /var/run/docker.sock?
Для управления локальным Docker — нет, панель работает именно через сокет. Риск снижают агентом или socket-proxy с ограниченным набором вызовов API, но часть функций тогда отвалится.
Хватит ли 1 ГБ RAM под панель и пару сервисов?
Панель займёт около 70 МБ, но запас исчезнет на первой же сборке образа или всплеске нагрузки на базу. Рабочий минимум для прода — 2 ГБ, а если собираете образы на сервере — 4 ГБ.
Нужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.