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

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

Розгортання Plane на VPS: self-hosted керування проєктами, SSL і резервні копії

calendar_month Oct 04, 2026 schedule 19 хв. читання visibility 52 переглядів
Развёртывание Plane на VPS: self-hosted управление проектами, SSL и резервные копии
info

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

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

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

Розгортання Plane на VPS: self-hosted керування проєктами, SSL і резервні копії

TL;DR

Plane — self-hosted платформа для керування проєктами, завданнями, спринтами, нотатками та командами. Нижче ми розгорнемо Plane у Docker на Ubuntu 24.04 LTS, закриємо його за Caddy з автоматичним SSL-сертифікатом, налаштуємо базовий захист сервера та резервне копіювання бази даних, конфігурації й файлів користувачів.

  • Використовуємо VPS щонайменше з 4 vCPU, 8 ГБ RAM і SSD від 80 ГБ.
  • Установимо Docker Engine і Docker Compose Plugin з офіційного репозиторію.
  • Розгорнемо Plane через офіційний self-hosted installer і зафіксуємо версію релізу.
  • Відкриємо лише SSH, HTTP і HTTPS, а адміністративний доступ обмежимо SSH-ключами.
  • Налаштуємо Caddy для автоматичного отримання та продовження TLS-сертифіката.
  • Створимо щоденний backup PostgreSQL, конфігурації та даних об'єктного сховища.

1. TL;DR

У цьому посібнику розглядається повний цикл розгортання Plane: від чистого VPS і базового захисту Ubuntu до публікації застосунку через HTTPS та відновлення з резервної копії. Команди розраховані на Ubuntu Server 24.04 LTS і Docker Engine 28.x або новішу стабільну версію, доступну в офіційному репозиторії Docker на момент установлення.

  • Plane працює як набір контейнерів: web-інтерфейс, API, фонові завдання, PostgreSQL, Redis і сховище файлів.
  • Доменне ім'я має вказувати на публічну IPv4-адресу сервера до запуску Caddy.
  • Секрети зберігаються у файлі .env з обмеженими правами доступу.
  • Один backup має включати не лише PostgreSQL, а й завантажені файли, конфігурацію та ключі.

2. Зміст

Стаття побудована як практичний сценарій для власника нового VPS. Спочатку визначаються ресурси та вимоги, потім виконуються підготовка сервера, установлення Plane, публікація через HTTPS і налаштування регулярних резервних копій.

  1. Підготувати DNS-запис для домену.
  2. Створити окремого адміністратора та заборонити вхід за паролем.
  3. Установити Docker і системні утиліти.
  4. Розгорнути Plane з офіційного джерела.
  5. Налаштувати зовнішній reverse proxy і TLS.
  6. Перевірити застосунок та автоматизувати backup.

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

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

Що таке Plane

Plane — система керування розробкою та проєктами з відкритим вихідним кодом. Вона надає робочі простори, проєкти, завдання, статуси, цикли, модулі, представлення, коментарі, сторінки та базові можливості командної роботи. Інтерфейс підходить як для невеликої продуктової команди, так і для кількох незалежних проєктів однієї організації.

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

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

Після виконання інструкції користувач зможе відкрити, наприклад, https://plane.example.com, створити робочий простір і запросити учасників команди. Plane працюватиме в Docker-контейнерах, а Caddy прийматиме зовнішній HTTPS-трафік і передаватиме його застосунку через локальний інтерфейс.

На сервері також з'являться:

  • PostgreSQL для постійних даних застосунку;
  • Redis для черг і кешування;
  • об'єктне сховище для вкладень і файлів користувачів;
  • Docker volumes для даних, які мають зберігатися після повторного створення контейнерів;
  • журнали контейнерів і системні журнали для діагностики.

Cloud-managed або self-hosted

Критерій Хмарна версія Self-hosted на VPS
Установлення Практично не потрібне Потрібно обслуговувати сервер і контейнери
Контроль даних Залежить від постачальника Дані перебувають під контролем власника
Вартість Зазвичай залежить від кількості користувачів Основні витрати — сервер, диски та backup
Оновлення Виконуються автоматично або постачальником Потрібно планувати самостійно
Інтеграція Обмежена можливостями сервісу Можна налаштувати VPN, SSO, SMTP і внутрішні webhook

Cloud-managed варіант раціональніший, якщо немає часу на експлуатацію Linux-сервера. Self-hosted Plane на VPS обирають, коли важливі контроль, передбачувана інфраструктура, незалежність від лімітів SaaS або розміщення поруч з іншими внутрішніми сервісами.

Попередні умови

Потрібен домен або піддомен, наприклад plane.example.com. Створіть DNS-запис типу A, що вказує на IPv4 сервера. Якщо використовується IPv6, додайте AAAA-запис лише після перевірки, що сервер і firewall коректно обслуговують IPv6.

# Перевіряємо, що DNS уже вказує на потрібну адресу
dig +short plane.example.com A

До отримання сертифіката домен має бути доступний з інтернету через порти 80 і 443. Якщо перед сервером розташований зовнішній firewall, його правила також мають дозволяти ці порти.

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

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

Plane — не статична HTML-сторінка. Self-hosted установлення запускає кілька контейнерів, базу даних, чергу завдань і файлове сховище. Тому орієнтуватися лише на розмір web-інтерфейсу неправильно: водночас важливі RAM, швидкий диск і запас CPU для фонових операцій.

Мінімальні вимоги

Ресурс Мінімум для тестової команди Практичний старт для production
CPU 2 vCPU 4 vCPU
RAM 4 ГБ 8 ГБ
Диск 40 ГБ SSD 80–160 ГБ NVMe SSD
Мережа 100 Мбіт/с 1 Гбіт/с або вище
Адреса Публічний IPv4 Публічний IPv4 та за потреби IPv6
ОС Ubuntu 24.04 LTS Ubuntu 24.04 LTS

Конфігурація з 4 vCPU і 8 ГБ RAM підходить для невеликої команди, кількох проєктів і помірної кількості вкладень. Диск слід обирати з урахуванням зростання файлів: база даних Plane зазвичай займає менше місця, ніж зображення, документи та інші вкладення.

Як один із варіантів можна взяти VPS з 4 vCPU, 8 ГБ RAM, NVMe-диском від 80 ГБ і публічним IPv4. Аналогічні параметри можна отримати в будь-якого провайдера, якщо він надає повний root-доступ, віртуалізацію з гарантованими ресурсами та можливість робити зовнішні backup.

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

Dedicated-сервер виправданий не самим фактом запуску Plane, а навантаженням і вимогами до ізоляції. Він потрібен, якщо на одному сервері одночасно працюють Plane, GitLab, CI runners, моніторинг, бази даних та інші ресурсомісткі сервіси, або якщо потрібна гарантована продуктивність без конкуренції за CPU й диск.

Для команди з кількох десятків людей dedicated зазвичай не є обов'язковим. Спочатку варто виміряти споживання CPU, RAM, I/O і розмір даних. Перехід на виділений сервер має сенс після появи постійного навантаження, частого swap або потреби розміщувати кілька production-систем.

Вибір локації

Локація впливає на затримку доступу, законодавчі вимоги та вартість передавання даних. Для команди, що перебуває в одному регіоні, обирайте дата-центр з мінімальним RTT до користувачів. Для міжнародної команди важливіші стабільний маршрут і наявність IPv4, ніж різниця в кілька мілісекунд.

Резервні копії бажано зберігати в іншій географічній зоні або хоча б на іншому фізичному сервері. Backup на тому самому VPS не захищає від видалення диска, блокування акаунта, апаратної аварії чи помилки адміністратора.

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

Підключення та створення адміністратора

Передбачається, що провайдер надав чистий сервер Ubuntu 24.04 LTS і початковий доступ через SSH. Підставте IP-адресу та ім’я користувача, створеного під час встановлення.

# Підключаємося до сервера через SSH
ssh root@SERVER_IP

Створимо користувача deploy, додамо його до групи sudo та встановимо публічний ключ. Виконуйте блок від root.

# Створюємо окремого адміністратора
adduser deploy

# Дозволяємо користувачеві виконувати адміністративні команди
usermod -aG sudo deploy

# Створюємо каталог для SSH-ключів
install -d -m 700 -o deploy -g deploy /home/deploy/.ssh

# Відкриваємо редактор для додавання публічного ключа
nano /home/deploy/.ssh/authorized_keys

# Виправляємо власника та права файлу ключів
chown deploy:deploy /home/deploy/.ssh/authorized_keys
chmod 600 /home/deploy/.ssh/authorized_keys

Вставте в authorized_keys вміст файлу id_ed25519.pub зі свого комп’ютера. Після цього перевірте новий вхід в окремому терміналі, не закриваючи поточну root-сесію.

# Перевіряємо вхід новим користувачем
ssh deploy@SERVER_IP

# Перевіряємо права sudo
sudo -v

Оновлення системи та базові утиліти

# Оновлюємо індекси пакетів і встановлюємо виправлення
sudo apt update && sudo apt full-upgrade -y

# Встановлюємо інструменти адміністрування та діагностики
sudo apt install -y ca-certificates curl gnupg lsb-release \
  unzip jq git vim nano htop tree dnsutils \
  ufw fail2ban unattended-upgrades

Перезавантажте сервер, якщо оновлювалося ядро або системні бібліотеки.

# Перевіряємо необхідність перезавантаження
if [ -f /var/run/reboot-required ]; then sudo reboot; fi

SSH-ключі та вимкнення паролів

Після перевірки входу за ключем заборонимо автентифікацію за паролем. Перед зміною конфігурації збережіть копію файлу та перевірте синтаксис SSH.

# Зберігаємо резервну копію конфігурації SSH
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak

# Відкриваємо конфігурацію SSH
sudo nano /etc/ssh/sshd_config

Переконайтеся, що присутні такі параметри:

PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
# Перевіряємо конфігурацію перед перезапуском
sudo sshd -t

# Застосовуємо налаштування SSH
sudo systemctl restart ssh

Firewall

Відкриємо SSH, HTTP і HTTPS. Якщо SSH працює на нестандартному порту, замініть 22/tcp відповідним значенням. Спочатку дозвольте SSH і лише потім вмикайте UFW.

# Дозволяємо адміністративний доступ і веб-трафік
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

# Вмикаємо firewall із політикою заборони вхідних з’єднань
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw --force enable

# Перевіряємо активні правила
sudo ufw status verbose

Fail2ban

Fail2ban тимчасово блокує адреси, з яких виконуються повторні невдалі спроби входу в SSH. Це не замінює ключі та firewall, але зменшує шум від автоматичних сканерів.

# Створюємо локальну конфігурацію jail для SSH
sudo tee /etc/fail2ban/jail.d/sshd.local > /dev/null <<'EOF'
[sshd]
enabled = true
backend = systemd
port = 22
maxretry = 5
findtime = 10m
bantime = 1h
EOF

# Перезапускаємо fail2ban і вмикаємо автозапуск
sudo systemctl enable --now fail2ban

# Перевіряємо стан захисту SSH
sudo fail2ban-client status sshd

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

Схема: 6. Установка ПО — пошагово
Схема: 6. Встановлення ПЗ — покроково

Встановлення Docker Engine

В Ubuntu краще використовувати офіційний apt-репозиторій Docker, а не старі пакети зі стандартного репозиторію. У 2026 році орієнтуйтеся на актуальну стабільну гілку Docker Engine 28.x або новішу, якщо її вже опубліковано для Ubuntu 24.04.

# Видаляємо конфліктні неофіційні пакети
sudo apt remove -y docker.io docker-doc docker-compose podman-docker containerd runc || true

# Створюємо каталог для ключів apt
sudo install -m 0755 -d /etc/apt/keyrings

# Завантажуємо офіційний ключ Docker
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
  sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

# Робимо ключ доступним для apt
sudo chmod a+r /etc/apt/keyrings/docker.gpg

# Додаємо репозиторій Docker для поточного релізу Ubuntu
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

# Оновлюємо список пакетів і встановлюємо Docker Compose Plugin
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io \
  docker-buildx-plugin docker-compose-plugin

# Дозволяємо запуск Docker без sudo для користувача deploy
sudo usermod -aG docker "$USER"

# Перевіряємо версії
docker --version
docker compose version

Після додавання користувача до групи Docker потрібно відкрити нову SSH-сесію. Група docker фактично надає root-права, тому додавайте до неї лише довірених адміністраторів.

# Перевіряємо роботу Docker після нового входу
docker run --rm hello-world

Завантаження офіційного встановлювача Plane

Self-hosted-дистрибутив Plane публікується проєктом Plane у GitHub. Встановлювач створює каталог розгортання, Docker Compose-файли та шаблон змінних середовища. Перед застосуванням у production перевірте release notes і сумісність вибраної версії.

# Переходимо до домашнього каталогу адміністратора
cd ~

# Створюємо окремий каталог для Plane
mkdir -p ~/plane
cd ~/plane

# Завантажуємо офіційний встановлювач із репозиторію Plane
curl -fsSL -o setup.sh \
  https://raw.githubusercontent.com/makeplane/plane/master/deploy/selfhost/install.sh

# Робимо встановлювач виконуваним
chmod 700 setup.sh

# Переглядаємо встановлювач перед запуском
less setup.sh

Перевірка скрипту перед виконанням обов’язкова: вона показує, які образи, каталоги та команди буде використано. Якщо проєкт опублікував встановлювач для конкретного релізу, бажано брати його зі сторінки релізу, а не використовувати плаваючу гілку master.

# Запускаємо інтерактивне встановлення Plane
./setup.sh install

Залежно від версії встановлювача команда може називатися ./setup.sh install, ./setup.sh start або мати меню дій. Використовуйте назву, яку показує сам скрипт під час запуску з параметром довідки.

# Показуємо доступні дії конкретної версії встановлювача
./setup.sh --help

Отримання початкової конфігурації

Зазвичай у каталозі Plane з’являються файл .env і один або кілька Compose-файлів. Якщо installer створив лише шаблон, скопіюйте його до робочого файлу та заповніть значення.

# Показуємо вміст каталогу розгортання
find ~/plane -maxdepth 2 -type f -printf '%p\n' | sort

# Якщо присутній шаблон, створюємо робочий файл середовища
[ -f ~/plane/.env.example ] && cp ~/plane/.env.example ~/plane/.env

# Обмежуємо доступ до секретів
chmod 600 ~/plane/.env

Запуск контейнерів

Перед першим запуском вивчіть підсумкову конфігурацію. Це дає змогу побачити імена сервісів, проброшені порти та volume, який потрібно включити до резервного копіювання.

# Переходимо до каталогу Plane
cd ~/plane

# Перевіряємо та розгортаємо підсумкову Compose-конфігурацію
docker compose config > /tmp/plane-compose-resolved.yml

# Запускаємо сервіси у фоновому режимі
docker compose up -d

Перший запуск може тривати кілька хвилин: Docker завантажує образи, створює мережу та volumes, а застосунок виконує міграції бази даних.

# Перевіряємо список контейнерів і їхній стан
docker compose ps

# Переглядаємо останні 200 рядків загального журналу
docker compose logs --tail=200

# За потреби стежимо за журналом конкретного сервісу
docker compose logs -f --tail=100 web

Ім’я сервісу web залежить від версії Compose-файлу. Якщо такого сервісу немає, спочатку виконайте docker compose config --services і виберіть фактичне ім’я frontend або proxy-сервісу.

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

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

Змінні середовища

Усі секрети Plane мають зберігатися у .env або в захищеному менеджері секретів. Не вставляйте паролі PostgreSQL, ключі JWT і SMTP-паролі безпосередньо у Compose-файл, Git-репозиторій або shell-скрипт, доступний усім користувачам.

Назви змінних залежать від конкретного релізу Plane. Не видаляйте обов’язкові значення з файлу, який створив installer. Заповніть домен і згенеруйте випадкові секрети там, де це передбачено шаблоном.

# Генерируем криптографически случайные значения для собственных секретов
openssl rand -hex 32
openssl rand -base64 48

# Открываем файл переменных окружения
nano ~/plane/.env

# Проверяем права на файл секретов
stat -c '%A %U:%G %n' ~/plane/.env

У конфігурації мають бути коректно задані публічний URL застосунку, домен, параметри PostgreSQL, Redis, SMTP та об’єктного сховища. Публічний URL має використовувати остаточну HTTPS-адресу, наприклад:

WEB_URL=https://plane.example.com
CORS_ALLOWED_ORIGINS=https://plane.example.com

Точні назви змінних потрібно звіряти з документацією та шаблоном вибраного релізу. Не слід механічно додавати неіснуючі змінні: застосунок може проігнорувати їх і продовжити роботу з небезпечними значеннями за замовчуванням.

Публікація через Caddy

Caddy автоматично отримує сертифікат Let’s Encrypt і продовжує його. Спочатку Plane можна запустити на локальному порту, недоступному з інтернету, а назовні виставити лише Caddy.

Перевірте, який сервіс Plane публікує HTTP-порт:

# Показываем сервисы и опубликованные порты
cd ~/plane
docker compose config --services
docker compose ps

Якщо Compose-файл публікує порт контейнера 80 на хостовий порт 80, змініть прив’язку на локальну адресу та вільний порт, наприклад 127.0.0.1:8080:80. Робіть це в підтримуваному override-файлі або способом, передбаченим installer. Наведений нижче приклад override застосовний лише якщо сервіс справді називається proxy і всередині прослуховує порт 80.

services:
  proxy:
    ports:
      - "127.0.0.1:8080:80"

Якщо внутрішній сервіс має іншу назву, замініть proxy. Не публікуйте безпосередньо назовні PostgreSQL, Redis, MinIO або адміністративні порти.

# Применяем изменение и пересоздаём контейнеры
cd ~/plane
docker compose up -d

# Проверяем локальный HTTP-ответ
curl -I http://127.0.0.1:8080

Встановимо Caddy з офіційного репозиторію.

# Добавляем официальный ключ репозитория Caddy
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | \
  sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg

# Добавляем репозиторий Caddy
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | \
  sudo tee /etc/apt/sources.list.d/caddy-stable.list

# Устанавливаем Caddy 2.x
sudo apt update
sudo apt install -y caddy

Створіть конфігурацію /etc/caddy/Caddyfile. Замініть домен на свій.

plane.example.com {
    reverse_proxy 127.0.0.1:8080

    encode zstd gzip

    header {
        X-Content-Type-Options nosniff
        X-Frame-Options SAMEORIGIN
        Referrer-Policy strict-origin-when-cross-origin
    }

    log {
        output file /var/log/caddy/plane-access.log
        format json
    }
}
# Проверяем синтаксис Caddyfile
sudo caddy validate --config /etc/caddy/Caddyfile

# Включаем запуск Caddy вместе с системой
sudo systemctl enable --now caddy

# Перезапускаем после изменения конфигурации
sudo systemctl reload caddy

# Проверяем состояние reverse proxy
sudo systemctl status caddy --no-pager

Якщо DNS уже налаштовано, Caddy автоматично надішле запит на отримання сертифіката. Перевірка має виконуватися із зовнішнього комп’ютера або через публічний домен:

# Проверяем HTTPS и заголовки ответа
curl -I https://plane.example.com

# Проверяем TLS-сертификат
curl -vI https://plane.example.com 2>&1 | grep -E 'SSL connection|subject:|issuer:'

Перевірка стану Plane

Відкрийте домен у браузері, створіть початковий обліковий запис і перевірте створення проєкту, завдання та вкладень. Потім перегляньте контейнери й останні помилки.

# Проверяем, что контейнеры не находятся в состоянии restarting
cd ~/plane
docker compose ps

# Ищем ошибки в журналах за последний запуск
docker compose logs --since=10m 2>&1 | grep -iE 'error|fatal|panic' || true

# Проверяем место на диске
df -h
docker system df

Команда ping перевіряє лише ICMP-зв’язність і не підтверджує роботу HTTPS. Для застосунку корисніше використовувати curl, перевірку статусу контейнерів і перегляд журналів.

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

Що необхідно зберігати

Мінімальний backup Plane складається з чотирьох частин: дампу PostgreSQL, користувацьких файлів, файлу .env і Compose-конфігурації. Якщо використовується MinIO або інше S3-сумісне сховище, його bucket із вкладеннями не можна замінювати лише дампом бази даних.

  • PostgreSQL: робочі простори, проєкти, завдання, користувачі та налаштування.
  • Object storage: зображення, документи, аватари та вкладення.
  • Конфігурація: .env, Compose-файли та Caddyfile.
  • Ключі: лише якщо вони потрібні для розшифрування або доступу до backup.

Не покладайтеся на snapshot VPS як на єдиний backup. Snapshot зручний для швидкого відкату, але в разі проблеми із самим обліковим записом або сховищем він може стати недоступним разом із сервером.

Встановлення restic

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

# Устанавливаем restic из репозитория Ubuntu
sudo apt update
sudo apt install -y restic

# Создаём каталоги для временных дампов и скриптов
sudo install -d -m 700 /var/backups/plane
sudo install -d -m 700 /usr/local/sbin

Скрипт резервного копіювання

Назви сервісів бази даних і об’єктного сховища потрібно визначити за виводом docker compose config --services. У прикладі база називається plane-db. Якщо у вашій версії назва інша, змініть змінну DB_SERVICE.

sudo nano /usr/local/sbin/plane-backup.sh
#!/usr/bin/env bash
set -Eeuo pipefail

PLANE_DIR="/home/deploy/plane"
BACKUP_DIR="/var/backups/plane"
STAMP="$(date -u +%Y-%m-%dT%H-%M-%SZ)"
DB_SERVICE="plane-db"

# Эти переменные лучше загрузить из отдельного root-only файла
source /root/.config/plane-backup/restic.env

mkdir -p "$BACKUP_DIR/$STAMP"

# Создаём логический дамп PostgreSQL внутри контейнера
cd "$PLANE_DIR"
docker compose exec -T "$DB_SERVICE" \
  pg_dumpall -U postgres | gzip -9 > "$BACKUP_DIR/$STAMP/postgres.sql.gz"

# Сохраняем конфигурацию и Compose-файлы
tar --exclude='.log' -czf "$BACKUP_DIR/$STAMP/config.tar.gz" \
  -C "$PLANE_DIR" .env docker-compose.yml docker-compose.yaml 2>/dev/null || true

# Сохраняем Caddyfile
tar -czf "$BACKUP_DIR/$STAMP/caddy.tar.gz" \
  -C /etc caddy/Caddyfile

# Отправляем зашифрованные данные во внешнее S3-хранилище
restic backup "$BACKUP_DIR/$STAMP" \
  --tag plane \
  --host "$(hostname -f)"

# Удаляем локальные временные файлы старше двух дней
find "$BACKUP_DIR" -mindepth 1 -maxdepth 1 -type d -mtime +2 -exec rm -rf {} +

# Удаляем старые удалённые backup по политике хранения
restic forget --tag plane --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune

Створіть файл із параметрами restic. Доступ до нього має мати лише root.

# Создаём каталог для параметров резервного копирования
sudo install -d -m 700 /root/.config/plane-backup

# Создаём файл с URL S3 и паролем restic
sudo nano /root/.config/plane-backup/restic.env

# Пример содержимого; замените значения на свои
RESTIC_REPOSITORY="s3:https://s3.example.net/plane-backups"
RESTIC_PASSWORD="GENERATE_AND_STORE_A_LONG_RANDOM_PASSWORD"
AWS_ACCESS_KEY_ID="BACKUP_ACCESS_KEY"
AWS_SECRET_ACCESS_KEY="BACKUP_SECRET_KEY"

# Ограничиваем права
sudo chmod 600 /root/.config/plane-backup/restic.env

# Делаем скрипт исполняемым
sudo chmod 700 /usr/local/sbin/plane-backup.sh

# Инициализируем репозиторий один раз
sudo bash -c 'source /root/.config/plane-backup/restic.env && restic init'

Перевірте backup вручну до додавання cron.

# Запускаем полный backup и проверяем код возврата
sudo /usr/local/sbin/plane-backup.sh

# Показываем список снимков restic
sudo bash -c 'source /root/.config/plane-backup/restic.env && restic snapshots --tag plane'

Планувальник cron

Для невеликої інсталяції достатньо щоденного запуску вночі. Якщо протягом робочого дня створюється багато даних, зменште інтервал і окремо увімкніть backup бази. Найважливіше — періодично перевіряти відновлення, а не лише наявність файлів.

# Открываем root crontab
sudo crontab -e
# Ежедневно в 02:30 по времени сервера
30 2    /usr/local/sbin/plane-backup.sh >> /var/log/plane-backup.log 2>&1

Перевірка відновлення

Не тестуйте відновлення поверх єдиної production-бази. Створіть тимчасовий сервер або окремий Compose-проєкт, відновіть останній snapshot, імпортуйте PostgreSQL і перевірте вхід, проєкти та вкладення.

# Проверяем целостность данных restic
sudo bash -c 'source /root/.config/plane-backup/restic.env && restic check'

# Показываем содержимое последнего снимка
sudo bash -c 'source /root/.config/plane-backup/restic.env && restic ls latest --tag plane'

Оновлення Plane

Перед оновленням прочитайте release notes конкретної версії та зробіть backup. Для невеликої команди безпечніше maintenance window: зупинити запис, оновити образи, дочекатися міграцій і перевірити основні сценарії.

# Создаём backup перед обновлением
sudo /usr/local/sbin/plane-backup.sh

# Загружаем новые образы и пересоздаём контейнеры
cd /home/deploy/plane
docker compose pull
docker compose up -d

# Проверяем миграции и состояние сервисов
docker compose ps
docker compose logs --tail=200

Не використовуйте бездумно docker system prune -a: команда може видалити образи, необхідні для швидкого відкату. Не видаляйте volumes, доки не підтверджено наявність зовнішнього backup і не зрозумілий процес відновлення.

9. Усунення несправностей і FAQ

Чому домен відкривається з помилкою 502 Bad Gateway?

Спочатку перевірте, що Caddy працює: systemctl status caddy. Потім переконайтеся, що Plane дійсно слухає локальний порт командою curl -I http://127.0.0.1:8080. Якщо відповіді немає, виконайте docker compose ps і docker compose logs --tail=200 у каталозі Plane. Частою причиною є неправильна назва сервісу в override-файлі, контейнер, що зупинився, або вказівка Caddy на порт, який не опублікований на хості.

Сертифікат Caddy не випускається. Що перевірити?

Перевірте A-запис командою dig +short plane.example.com і порівняйте адресу з публічним IP сервера. Порти 80 і 443 мають бути дозволені в UFW, зовнішньому firewall і security group провайдера. Якщо увімкнено проксі CDN, переконайтеся, що він не блокує HTTP-перевірку, або тимчасово використовуйте DNS-налаштування без проксіювання. Детальна причина міститься в journalctl -u caddy -e.

Контейнери Plane постійно перезапускаються. Що робити?

Перегляньте статус і код завершення: docker compose ps, потім журнали конкретного контейнера: docker compose logs --tail=300 SERVICE. Перевірте вільну RAM і диск через free -h і df -h. Типові причини — нестача пам’яті, неправильні секрети, недоступна база, незаповнені обов’язкові змінні або пошкоджений volume. Не видаляйте volumes до аналізу логів і перевірки backup.

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

Для ознайомчої установки можна почати з 2 vCPU, 4 ГБ RAM і 40 ГБ SSD, але це залишає невеликий запас для Docker, бази та оновлень. Практичний мінімальний production-варіант — 4 vCPU, 8 ГБ RAM і SSD від 80 ГБ. Якщо плануються великі вкладення, розмір диска обирайте за прогнозом зростання даних і окремо зберігайте backup. Для стабільної роботи важливіші швидкий SSD і гарантовані ресурси, ніж велика кількість віртуальних ядер.

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

Для одного Plane і невеликої команди зазвичай достатньо VPS. Dedicated потрібен, коли сервер одночасно обслуговує важкі CI-завдання, GitLab, бази даних, моніторинг та інші застосунки, або потрібна повна ізоляція ресурсів. Рішення краще ухвалювати за вимірюваннями: якщо RAM постійно закінчується, з’являється swap, а диск зазнає високого I/O-навантаження, спочатку можна збільшити VPS, а потім розглянути dedicated.

Чи можна не використовувати Caddy і залишити вбудований reverse proxy?

Можна, якщо офіційний deployment Plane вже надає підтримуваний proxy-контейнер і коректну конфігурацію TLS. Зовнішній Caddy зручний тим, що відокремлює керування сертифікатом від застосунку та дозволяє не публікувати внутрішні сервіси. Не можна одночасно займати порт 80 кількома proxy: оберіть один зовнішній вхідний шар. У будь-якому варіанті мають бути відкриті лише 80 і 443, а бази та черги повинні залишатися у внутрішній Docker-мережі.

Де подивитися причину помилки входу або непрацюючого завдання?

Перевірте журнали frontend, API і фонових workers, а не лише Caddy. Список точних назв сервісів виводиться командою docker compose config --services. Потім використовуйте docker compose logs --since=15m SERVICE. Якщо помилка пов’язана з листами, перевірте SMTP-змінні та доступність сервера надсилання. Якщо не завантажуються вкладення, перевірте налаштування об’єктного сховища та наявність вільного місця.

Що робити, якщо закінчився диск?

Спочатку визначте джерело: df -h, du -xhd1 /var/lib/docker і docker system df. Перевірте розмір uploads, PostgreSQL і журналів. Старі локальні backup можна видалити лише після підтвердження, що зовнішня копія доступна. Логи Docker слід обмежити через підтримувані параметри Compose або daemon configuration. Не виконуйте видалення volumes і не використовуйте aggressive prune без розуміння того, які дані зберігаються в кожному томі.

Як безпечно оновлювати Plane без простою?

Повністю безперебійне оновлення залежить від конкретної версії Plane та схеми бази, тому для одного VPS краще використовувати коротке вікно обслуговування. Зробіть зовнішній backup, перевірте release notes, завантажте нові образи, застосуйте docker compose up -d і перевірте міграції. Для мінімізації простою можна заздалегідь завантажити образи командою docker compose pull. Перед оновленням збережіть поточний tag образів і Compose-файли для відкату.

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

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

У результаті Plane працює на власному VPS у Docker, доступний через HTTPS за допомогою Caddy, а сервер захищений SSH-ключами, UFW і fail2ban. Конфігурація, PostgreSQL і користувацькі файли включені до зашифрованого зовнішнього backup з регулярною перевіркою відновлення.

Далі корисно увімкнути моніторинг CPU, RAM, диска та строку дії backup, потім винести об’єктне сховище на окремий S3-сумісний сервіс зі зростанням кількості вкладень. У разі збільшення команди можна додати SMTP, SSO, окремий сервер бази даних або масштабувати VPS після аналізу реального споживання ресурсів.

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

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

Share this post:

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

Telegram VKVK WhatsApp Facebook LinkedIn XX

розгортання Plane на VPS: self-hosted керування проєктами, SSL і резервні копії
support_agent
Valebyte Support
Usually replies within minutes
Hi there!
Send us a message and we'll reply as soon as possible.