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

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

Встановлення Chatwoot на VPS: Docker, PostgreSQL, Redis, SSL і налаштування email

calendar_month Oct 08, 2026 schedule 18 хв. читання visibility 99 переглядів
Установка Chatwoot на VPS: Docker, PostgreSQL, Redis, SSL и настройка email
info

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

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

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

Встановлення Chatwoot на VPS: Docker, PostgreSQL, Redis, SSL і налаштування email

TL;DR

Chatwoot — self-hosted платформа для підтримки клієнтів через віджет сайту, email, Telegram, WhatsApp та інші канали. У цьому посібнику ви розгорнете Chatwoot на Ubuntu VPS у Docker, підключите PostgreSQL і Redis, налаштуєте HTTPS через Caddy, SMTP для вихідної пошти, резервне копіювання та безпечне обслуговування.

  • Для невеликої команди достатньо VPS із 2 vCPU, 4 ГБ RAM і 50–80 ГБ NVMe.
  • Chatwoot запускається в контейнерах: вебзастосунок, фоновий worker, PostgreSQL, Redis і Caddy.
  • HTTPS-сертифікат Let’s Encrypt випускається та продовжується автоматично через Caddy.
  • Вихідна пошта налаштовується через SMTP-змінні у файлі .env.
  • Перед запуском потрібно створити базу даних командою db:chatwoot_prepare.
  • Критичні дані для бекапу: PostgreSQL, .env, Caddy data і користувацькі завантаження.

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

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

Chatwoot — це open-source система customer support і omnichannel inbox. Вона збирає звернення клієнтів в одному інтерфейсі: повідомлення з вебчату, email, Telegram, Facebook Messenger, Instagram, WhatsApp Business API та інших інтеграцій. Оператори можуть призначати діалоги один одному, використовувати мітки, шаблони відповідей, автоматизацію, SLA та базу знань.

У цій інструкції буде встановлено self-hosted екземпляр Chatwoot на власному VPS. Він буде доступний за вашим доменним ім’ям, наприклад chat.example.com, через захищене HTTPS-підключення. Дані листування, контакти, вкладення та налаштування зберігатимуться на вашому сервері, а не в чужому SaaS-акаунті.

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

  • вебінтерфейс Chatwoot для адміністраторів і операторів;
  • віджет онлайн-чату, який можна додати на сайт;
  • PostgreSQL 16 як основна база даних;
  • Redis 7 для черг, кешу та фонових завдань;
  • Sidekiq worker для надсилання email, обробки webhook і фонових операцій;
  • Caddy 2 як reverse proxy і менеджер TLS-сертифікатів;
  • SMTP-надсилання сповіщень, запрошень користувачів і відповідей із email-каналу;
  • автоматичні бекапи PostgreSQL у S3-сумісне сховище.

Cloud-managed або self-hosted

Критерій Хмарний сервіс Self-hosted Chatwoot на VPS
Швидкість старту Кілька хвилин, інфраструктура вже готова Потрібно налаштувати сервер, DNS, SSL і бекапи
Контроль даних Дані перебувають у постачальника послуги Дані, логи та резервні копії контролюєте ви
Кастомізація Обмежена тарифом та інтерфейсом Можна змінювати конфіги, інтеграції та версію застосунку
Експлуатація Оновлення та бекапи зазвичай виконує сервіс Оновлення, безпека та відновлення — ваша зона відповідальності
Вартість під час зростання команди Часто залежить від кількості агентів і каналів Залежить переважно від ресурсів сервера та сховища

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

Перед початком підготуйте домен або піддомен, наприклад chat.example.com. Його A-запис має вказувати на публічну IPv4-адресу VPS. Для автоматичного випуску сертифіката порти 80 і 443 мають бути доступні з інтернету.

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

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

Навантаження Chatwoot залежить не лише від кількості операторів, а й від кількості одночасних відвідувачів у вебчаті, розміру вкладень, кількості підключених каналів та активності автоматизації. PostgreSQL і Sidekiq чутливі до нестачі пам’яті: сервер із 1 ГБ RAM для production-розгортання використовувати не варто.

Сценарій vCPU RAM NVMe-диск Кому підходить
Тестовий стенд 2 2 ГБ 30 ГБ Тестування, один адміністратор, без великої кількості вкладень
Мінімальний production 2 4 ГБ 50–80 ГБ До 5–10 агентів і помірний потік звернень
Робоча команда 4 8 ГБ 100–160 ГБ 10–30 агентів, активні канали та вкладення
Високе навантаження 8+ 16+ ГБ 250+ ГБ Багато діалогів, інтеграцій, API та тривале зберігання медіа

Практичний стартовий конфіг — 2 vCPU, 4 ГБ RAM, 80 ГБ NVMe і канал від 100 Мбіт/с. Цього достатньо, щоб одночасно працювали PostgreSQL, Redis, Caddy, вебконтейнер і worker. Під час вибору можна взяти VPS із зазначеними характеристиками або аналогічний сервер в іншого провайдера.

Чому важливий запас на диску

Диск витрачають не лише Docker-образи. Простір займають база PostgreSQL, тимчасові файли, логи контейнерів, вкладення з діалогів, резервні копії до надсилання у зовнішнє сховище та дані Caddy. Не плануйте диск «впритул»: залишайте щонайменше 25–30% вільного місця. У разі заповнення розділу PostgreSQL може аварійно зупинитися або пошкодити робочий процес транзакцій.

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

Виділений сервер має сенс за стабільного високого навантаження, вимог до ізоляції ресурсів, зберігання великої кількості файлів або якщо Chatwoot працює разом з іншими важкими сервісами. Наприклад, dedicated варто розглянути за наявності 50+ активних агентів, десятків тисяч розмов на місяць, локального зберігання великих медіафайлів та інтенсивної аналітики.

Для звичайної підтримки малого бізнесу VPS зазвичай кращий: його простіше збільшити за CPU, RAM і диском, він дешевший на старті та не потребує резервування надлишкових ресурсів. Не розміщуйте production Chatwoot на одному сервері з публічною базою даних, тестовими CI-завданнями або неперевіреними контейнерами.

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

Локація впливає на затримку вебчату, маршрутизацію email і вимоги до обробки персональних даних. Обирайте регіон ближче до операторів та основної аудиторії. Якщо ви зберігаєте листування клієнтів з ЄС, заздалегідь перевірте внутрішні юридичні вимоги до регіону розміщення та угод про обробку даних.

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

Схема: Підготовка сервера
Схема: Підготовка сервера

Нижче використовується Ubuntu Server 24.04 LTS. Станом на 2026 рік це відповідна LTS-база для Docker-розгортання: вона має актуальне ядро, тривалу підтримку та стабільний набір пакетів. Підключіться до сервера під користувачем root, якого надав провайдер.

Оновіть операційну систему

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

apt update && apt upgrade -y
apt autoremove -y
reboot

Після перезавантаження знову підключіться через SSH і створіть окремого користувача для адміністрування. Не працюйте постійно під root: це підвищує ризик випадково видалити дані або виконати небезпечну команду без обмежень.

adduser deploy
usermod -aG sudo deploy
mkdir -p /home/deploy/.ssh
chmod 700 /home/deploy/.ssh
chown -R deploy:deploy /home/deploy/.ssh

Скопіюйте свій публічний SSH-ключ у файл авторизації. Виконуйте команду на локальному комп’ютері, замінивши IP-адресу сервера.

ssh-copy-id deploy@SERVER_IP

Перевірте вхід у другому терміналі. Не закривайте поточну root-сесію, доки не переконаєтеся, що ключ працює.

ssh deploy@SERVER_IP
sudo whoami

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

sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
sudo sed -i 's/^#\?PermitRootLogin./PermitRootLogin no/' /etc/ssh/sshd_config
sudo sed -i 's/^#\?PasswordAuthentication./PasswordAuthentication no/' /etc/ssh/sshd_config
sudo sshd -t && sudo systemctl reload ssh

Встановіть базові утиліти та захист від перебору паролів

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

sudo apt install -y ca-certificates curl gnupg git jq \
  ufw fail2ban unattended-upgrades apt-transport-https \
  software-properties-common

Налаштуйте firewall. Відкриваються лише SSH, HTTP та HTTPS. PostgreSQL на порту 5432 і Redis на порту 6379 не можна відкривати назовні: контейнери взаємодіятимуть лише у внутрішній Docker-мережі.

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

Створіть мінімальну локальну конфігурацію Fail2ban для SSH. Значення означають: блокувати IP на одну годину, якщо він здійснив п’ять невдалих спроб за десять хвилин.

sudo tee /etc/fail2ban/jail.d/sshd.local <<'EOF'
[sshd]
enabled = true
maxretry = 5
findtime = 10m
bantime = 1h
EOF

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

Створіть робочий каталог

Усі файли стека перебуватимуть у /opt/chatwoot. Такий шлях зручно резервувати, переносити та перевіряти. Не зберігайте секрети в домашньому каталозі, якщо на сервері кілька адміністраторів.

sudo mkdir -p /opt/chatwoot
sudo chown -R deploy:deploy /opt/chatwoot
cd /opt/chatwoot

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

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

Для встановлення використовується Docker Engine 27+ і Docker Compose Plugin v2. У production не встановлюйте PostgreSQL і Redis безпосередньо через apt, якщо плануєте запускати їх у Docker: змішування двох способів ускладнює мережеву діагностику, оновлення та резервне копіювання.

Встановіть Docker Engine з офіційного репозиторію

Спочатку додайте ключ і репозиторій Docker для Ubuntu.

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

Наступна команда додає репозиторій, що відповідає архітектурі та версії 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

sudo apt update

Встановіть Docker Engine, Compose Plugin і необхідні компоненти мережі контейнерів.

sudo apt install -y docker-ce docker-ce-cli containerd.io \
  docker-buildx-plugin docker-compose-plugin

sudo systemctl enable --now docker
sudo usermod -aG docker deploy

Вийдіть із SSH-сесії та підключіться знову, щоб група docker застосувалася. Потім перевірте версії.

exit
ssh deploy@SERVER_IP
docker --version
docker compose version
docker run --rm hello-world

Станом на 2026 рік орієнтуйтеся на Docker Engine 27 або новішу версію та Docker Compose v2. Якщо команда docker run повертає привітальне повідомлення, демон працює коректно.

Створіть структуру постійних даних

Docker named volumes переживають повторне створення контейнерів, але для Caddy і локальних вкладень зручніше явно створити каталоги. Каталог storage використовуватиметься Chatwoot для локального зберігання файлів.

cd /opt/chatwoot
mkdir -p caddy/data caddy/config storage backups
chmod 700 backups
find /opt/chatwoot -maxdepth 2 -type d -print

Згенеруйте секрети

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

openssl rand -hex 64
openssl rand -hex 32

Перше значення використовуватиметься як SECRET_KEY_BASE, друге — як пароль PostgreSQL. У наступному розділі вони потраплять у файл .env, доступ до якого буде обмежено.

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

До запуску Caddy домен уже має розпізнаватися в IP-адресу сервера. Замініть ім’я на власне. Якщо виведення показує іншу адресу або порожній результат, виправте A-запис у DNS-провайдера та дочекайтеся оновлення зони.

getent ahostsv4 chat.example.com
curl -4 ifconfig.me
echo

Конфігурація Chatwoot, SSL та email

Схема: Конфигурация Chatwoot, SSL и email
Схема: Конфігурація Chatwoot, SSL та email

У цьому варіанті всі сервіси описані в одному файлі compose.yaml. PostgreSQL і Redis не публікують порти на хост, тому до них не можна підключитися безпосередньо з інтернету. Caddy — єдиний контейнер, який приймає зовнішні запити на порти 80 і 443.

Створіть файл зі змінними середовища

Створіть /opt/chatwoot/.env. Замініть домен, email адміністратора, паролі та SMTP-параметри. Значення FRONTEND_URL обов’язково має починатися з https:// і не повинно мати слеша в кінці.

cd /opt/chatwoot
nano .env
POSTGRES_DB=chatwoot_production
POSTGRES_USER=chatwoot
POSTGRES_PASSWORD=CHANGE_TO_A_LONG_RANDOM_DATABASE_PASSWORD
POSTGRES_HOST=postgres
POSTGRES_PORT=5432

REDIS_URL=redis://redis:6379
RAILS_ENV=production
NODE_ENV=production
INSTALLATION_ENV=docker
SECRET_KEY_BASE=CHANGE_TO_128_HEX_CHARACTERS_FROM_OPENSSL

FRONTEND_URL=https://chat.example.com
DEFAULT_LOCALE=ru
RAILS_LOG_TO_STDOUT=true
RAILS_SERVE_STATIC_FILES=true
ENABLE_ACCOUNT_SIGNUP=false

ACTIVE_STORAGE_SERVICE=local
LOCAL_STORAGE_PATH=/app/storage

[email protected]
SMTP_ADDRESS=smtp.example.com
SMTP_PORT=587
SMTP_USERNAME=smtp-login
SMTP_PASSWORD=CHANGE_TO_SMTP_PASSWORD
SMTP_DOMAIN=example.com
SMTP_AUTHENTICATION=plain
SMTP_ENABLE_STARTTLS_AUTO=true
SMTP_OPENSSL_VERIFY_MODE=peer

[email protected]

Для SMTP використовуйте окрему поштову скриньку або SMTP-обліковий запис. Поштові сервіси часто вимагають пароль застосунку, а не основний пароль від скриньки. Порт 587 використовується зі STARTTLS, порт 465 — із TLS одразу після підключення; для 465 зазвичай потрібне додаткове налаштування адаптера, тому для першого запуску обирайте 587.

Обмежте доступ до файлу: читати його мають лише root і користувач deploy.

chmod 600 /opt/chatwoot/.env
ls -l /opt/chatwoot/.env

Створіть конфігурацію Docker Compose

Нижче використовується стабільний образ Chatwoot гілки 4.x. Перед великим оновленням фіксуйте конкретний тег, наприклад v4.x.y, після перевірки release notes. Тег latest зручний для тестів, але для production погіршує передбачуваність оновлень.

nano compose.yaml
services:
  postgres:
    image: postgres:16-alpine
    restart: unless-stopped
    env_file: .env
    environment:
      POSTGRES_DB: ${POSTGRES_DB}
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]
      interval: 10s
      timeout: 5s
      retries: 10
    networks:
      - chatwoot_internal

  redis:
    image: redis:7.4-alpine
    restart: unless-stopped
    command: ["redis-server", "--appendonly", "yes"]
    volumes:
      - redis_data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 10
    networks:
      - chatwoot_internal

  rails:
    image: chatwoot/chatwoot:v4.0.2
    restart: unless-stopped
    env_file: .env
    command: bundle exec rails server -p 3000 -b 0.0.0.0
    entrypoint: docker/entrypoints/docker-entrypoint.sh
    volumes:
      - ./storage:/app/storage
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy
    networks:
      - chatwoot_internal

  worker:
    image: chatwoot/chatwoot:v4.0.2
    restart: unless-stopped
    env_file: .env
    command: bundle exec sidekiq -C config/sidekiq.yml
    entrypoint: docker/entrypoints/docker-entrypoint.sh
    volumes:
      - ./storage:/app/storage
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy
    networks:
      - chatwoot_internal

  caddy:
    image: caddy:2.10-alpine
    restart: unless-stopped
    env_file: .env
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - ./caddy/data:/data
      - ./caddy/config:/config
    depends_on:
      - rails
    networks:
      - chatwoot_internal

volumes:
  postgres_data:
  redis_data:

networks:
  chatwoot_internal:
    driver: bridge

Якщо на момент встановлення актуальний стабільний реліз Chatwoot новіший за v4.0.2, замініть тег у контейнерах rails і worker на однаковий перевірений тег актуальної стабільної гілки. Ніколи не оновлюйте лише один із цих двох контейнерів: веб-процес і Sidekiq мають працювати на одній версії застосунку.

Налаштуйте Caddy і TLS

Caddy самостійно запросить сертифікат Let’s Encrypt, налаштує перенаправлення HTTP-to-HTTPS і продовжуватиме сертифікат. Сертифікати й обліковий запис ACME зберігаються в ./caddy/data, тому вони не зникнуть після повторного створення контейнера.

nano Caddyfile
CADDY_EMAIL {
  email {$CADDY_EMAIL}
}

chat.example.com {
  encode zstd gzip

  reverse_proxy rails:3000

  header {
    -Server
    Strict-Transport-Security "max-age=31536000; includeSubDomains"
    X-Content-Type-Options "nosniff"
    X-Frame-Options "SAMEORIGIN"
    Referrer-Policy "strict-origin-when-cross-origin"
  }

  log {
    output stdout
    format json
  }
}

Замініть chat.example.com у Caddyfile на той самий домен, який указано у FRONTEND_URL. Змінна CADDY_EMAIL із файлу .env застосовується всередині Caddy через синтаксис {$CADDY_EMAIL}.

Запустіть інфраструктурні контейнери та підготуйте базу

Спочатку завантажте образи та запустіть PostgreSQL із Redis. Потім виконайте міграції й початкову підготовку бази. Команда db:chatwoot_prepare створює структуру таблиць і застосовує міграції.

cd /opt/chatwoot
docker compose pull
docker compose up -d postgres redis
docker compose ps

Дочекайтеся статусу healthy у PostgreSQL і Redis. Після цього запустіть одноразовий контейнер із завданням підготовки бази.

docker compose run --rm rails \
  bundle exec rails db:chatwoot_prepare

Якщо команда завершилася без помилки, запустіть застосунок, worker і reverse proxy. Параметр -d запускає сервіси у фоновому режимі.

docker compose up -d rails worker caddy
docker compose ps
docker compose logs --tail=100 caddy

Перевірте працездатність

Перевірте відповідь Caddy із самого VPS. Код 200, 301 або 302 означає, що маршрут відповідає. Під час першого запиту Caddy може кілька секунд отримувати сертифікат.

curl -I http://chat.example.com
curl -I https://chat.example.com
docker compose logs --tail=100 rails
docker compose logs --tail=100 worker

Відкрийте https://chat.example.com у браузері. Під час першого запуску Chatwoot запропонує створити обліковий запис адміністратора та організацію. Оскільки ENABLE_ACCOUNT_SIGNUP=false, публічну реєстрацію буде вимкнено після створення початкового облікового запису; нових агентів додавайте з інтерфейсу адміністратора через запрошення.

Перевірте SMTP і налаштуйте email-канал

Після створення облікового запису адміністратора перейдіть в інтерфейсі до розділу налаштувань організації та перевірте запрошення нового агента: це простий тест вихідної пошти. Якщо лист не надходить, спочатку перегляньте логи worker, оскільки надсилання email виконується фоновим завданням.

docker compose logs -f worker

Щоб приймати звернення електронною поштою, створіть inbox типу Email Channel у панелі Chatwoot. Сервіс покаже адресу для пересилання або параметри інтеграції. На стороні вашого поштового провайдера налаштуйте forwarding з адреси підтримки на цю адресу або використовуйте підтримуваний поштовий канал згідно з інструкцією в інтерфейсі.

Для хорошої доставлюваності вихідної пошти налаштуйте DNS-записи SPF, DKIM і DMARC у домені відправника. SMTP може технічно працювати і без них, але листи із запрошеннями та відповідями частіше потраплятимуть у спам. Адреса MAILER_SENDER_EMAIL має належати домену, для якого налаштовано ці записи.

Додайте вебвіджет на сайт

Після створення Website Inbox Chatwoot покаже готовий JavaScript-сніпет. Вставте його перед закривальним тегом </body> сайту. Не копіюйте приклад із чужим ідентифікатором сайту: використовуйте код, сформований саме вашим екземпляром Chatwoot, інакше діалоги буде прив’язано не до потрібного inbox.

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

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

Робочий сервер без перевіреного відновлення не можна вважати захищеним. Для Chatwoot потрібно резервувати не лише PostgreSQL: частина критичних даних міститься в конфігурації та локальному сховищі вкладень. Redis зазвичай не є основним джерелом даних, але його volume можна включити до повної аварійної резервної копії.

Що обов’язково зберігати

  • PostgreSQL: облікові записи, контакти, діалоги, повідомлення, налаштування inbox та інтеграцій.
  • Файл .env: секрети застосунку, параметри SMTP, пароль бази даних, публічний URL.
  • Каталог storage: вкладення, якщо використовується ACTIVE_STORAGE_SERVICE=local.
  • Каталог caddy/data: сертифікати та дані ACME; їх можна відновити заново, але зберігати корисно.
  • compose.yaml і Caddyfile: інфраструктурна конфігурація.

Не покладайтеся лише на Docker volume як на резервну копію. Volume розташований на тому самому диску й не врятує у разі видалення VPS, помилки адміністратора, пошкодження файлової системи або блокування облікового запису. Щонайменше одна копія має зберігатися у зовнішньому S3-сумісному сховищі, на окремому backup VPS або в об’єктному сховищі іншого облікового запису.

Встановіть restic

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

sudo apt install -y restic
sudo mkdir -p /etc/restic
sudo chmod 700 /etc/restic

Створіть файл оточення для restic. Значення endpoint, bucket і ключів отримайте у використовуваного S3-провайдера. Не додавайте цей файл до Git.

sudo nano /etc/restic/chatwoot.env
RESTIC_REPOSITORY=s3:https://s3.example.net/chatwoot-backups
RESTIC_PASSWORD=CHANGE_TO_A_LONG_BACKUP_ENCRYPTION_PASSWORD
AWS_ACCESS_KEY_ID=CHANGE_TO_ACCESS_KEY
AWS_SECRET_ACCESS_KEY=CHANGE_TO_SECRET_KEY
sudo chmod 600 /etc/restic/chatwoot.env
sudo chown root:root /etc/restic/chatwoot.env

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

Скрипт створює узгоджений дамп PostgreSQL через pg_dump, додає конфігурації та файлове сховище до зашифрованого архіву restic, а потім видаляє тимчасовий SQL-файл. Для великих інсталяцій краще винести PostgreSQL в окремий managed-сервіс або налаштувати фізичні резервні копії, але логічний дамп підходить більшості невеликих команд.

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

APP_DIR="/opt/chatwoot"
BACKUP_DIR="${APP_DIR}/backups"
STAMP="$(date +%F_%H-%M-%S)"
DUMP_FILE="${BACKUP_DIR}/chatwoot_${STAMP}.sql.gz"

set -a
source /etc/restic/chatwoot.env
set +a

mkdir -p "${BACKUP_DIR}"
cd "${APP_DIR}"

docker compose exec -T postgres \
  pg_dump -U "${POSTGRES_USER}" -d "${POSTGRES_DB}" | gzip -9 > "${DUMP_FILE}"

restic backup \
  "${DUMP_FILE}" \
  "${APP_DIR}/.env" \
  "${APP_DIR}/compose.yaml" \
  "${APP_DIR}/Caddyfile" \
  "${APP_DIR}/storage" \
  "${APP_DIR}/caddy/data"

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

rm -f "${DUMP_FILE}"

Скрипту потрібні змінні PostgreSQL із /opt/chatwoot/.env. Додайте завантаження цього файлу перед виконанням pg_dump, інакше змінні не будуть визначені в оточенні скрипту.

sudo sed -i '/cd "${APP_DIR}"/a set -a\nsource "${APP_DIR}/.env"\nset +a' \
  /usr/local/sbin/chatwoot-backup.sh

sudo chmod 700 /usr/local/sbin/chatwoot-backup.sh
sudo /usr/local/sbin/chatwoot-backup.sh

Перший запуск ініціалізує репозиторій restic, якщо це потрібно, або запросить підтвердження. Після успішного завершення перевірте список знімків.

sudo bash -c 'source /etc/restic/chatwoot.env && restic snapshots'

Заплануйте резервне копіювання через cron

Запускайте резервне копіювання вночі, наприклад о 03:30. Вивід перенаправляється до журналу, який стане у пригоді під час розслідування помилок. Раз на тиждень перевіряйте, що новий snapshot справді з’явився.

sudo crontab -e
30 3   * /usr/local/sbin/chatwoot-backup.sh >> /var/log/chatwoot-backup.log 2>&1

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

Наявність backup-файлів не доводить можливість відновлення. Щонайменше раз на квартал розгортайте дамп на тестовому сервері. Для відновлення бази зупиніть застосунок, створіть порожню базу та завантажте SQL-дамп. У production не виконуйте відновлення без підтвердженого плану відкату.

gunzip -c chatwoot_YYYY-MM-DD_HH-MM-SS.sql.gz | \
  docker compose exec -T postgres \
  psql -U chatwoot -d chatwoot_production

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

Для невеликого інстансу використовуйте maintenance window: попередьте операторів, створіть резервну копію, оновіть образ, застосуйте міграції та перевірте журнали. Rolling update без простою потребує кількох web-реплік, спільного storage, окремої бази та балансувальника; для одного VPS це зазвичай невиправдано складно.

cd /opt/chatwoot
sudo /usr/local/sbin/chatwoot-backup.sh
docker compose pull
docker compose run --rm rails bundle exec rails db:migrate
docker compose up -d
docker image prune -f
docker compose ps

Перед оновленням прочитайте release notes цільової версії. Особливу увагу приділіть major-релізам, вимогам до PostgreSQL/Redis та змінам змінних оточення. Якщо оновлення спричиняє помилки, не видаляйте volumes і не запускайте довільні команди міграції: спочатку збережіть журнали та поверніться до попереднього образу.

Також контролюйте дисковий простір і стан контейнерів.

df -h
docker system df
docker compose ps
docker stats --no-stream

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

Чому Caddy не випускає SSL-сертифікат і в журналах видно ACME error?

Спочатку перевірте A-запис домену командою getent ahostsv4 chat.example.com: вона має повертати IP вашого VPS. Потім переконайтеся, що firewall дозволяє 80 і 443, а інший процес не зайняв ці порти: sudo ss -ltnp '( sport = :80 or sport = :443 )'. Також вимкніть проксування DNS-запису через CDN на час первинної діагностики. Перегляньте docker compose logs caddy; там буде точна причина відмови ACME.

Чому сторінка Chatwoot повертає 502 Bad Gateway?

Код 502 означає, що Caddy працює, але не може отримати відповідь від контейнера rails. Виконайте docker compose ps і переконайтеся, що rails має статус Up. Потім прочитайте останні журнали: docker compose logs --tail=150 rails. Часті причини — не виконані міграції бази, неправильний SECRET_KEY_BASE, недоступний PostgreSQL або нестача RAM. Перевірте пам’ять через free -h і kernel-журнали OOM через dmesg -T | grep -i killed.

Чому worker постійно перезапускається?

Контейнер worker залежить від Redis і PostgreSQL, тому спочатку перевірте їхній healthcheck: docker compose ps. Далі відкрийте журнали командою docker compose logs --tail=200 worker. Помилка підключення до Redis зазвичай означає неправильний REDIS_URL; усередині Docker-мережі використовуйте ім’я сервісу redis, а не localhost. Помилка бази вказує на неправильні POSTGRES_HOST, пароль або на те, що завдання db:chatwoot_prepare не було виконано.

Чому Chatwoot не надсилає email-запрошення та сповіщення?

Пошта надсилається Sidekiq worker, тому відкрийте його журнали та знайдіть SMTP-помилку. Перевірте адресу сервера, порт, логін, пароль застосунку та тип шифрування. Для порту 587 зазвичай потрібні SMTP_ENABLE_STARTTLS_AUTO=true і SMTP_AUTHENTICATION=plain. Після зміни .env застосуйте налаштування командою docker compose up -d --force-recreate rails worker. Не забувайте, що поштовий провайдер може блокувати SMTP до підтвердження домену або ввімкнення SMTP-доступу.

Чому листи потрапляють до спаму?

Проблема зазвичай не в Chatwoot, а в репутації домену або SMTP. Адреса MAILER_SENDER_EMAIL має збігатися з перевіреним доменом відправника. Налаштуйте SPF, DKIM і DMARC через DNS-панель поштового сервісу. Не використовуйте випадкову адресу відправника, якщо SMTP-провайдер дозволяє надсилання лише з підтвердженого домену. Перевірте заголовки листа в поштовому клієнті: вони покажуть результати SPF і DKIM. Для транзакційних листів краще використовувати спеціалізований SMTP-сервіс.

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

Для невеликого production-інстансу використовуйте щонайменше 2 vCPU, 4 ГБ RAM і 50 ГБ NVMe. Конфігурація з 2 ГБ пам’яті може працювати в тестовому режимі, але під час оновлень, фонової обробки вкладень та одночасних діалогів зростає ризик OOM-помилок. Якщо у вас увімкнено кілька каналів, активно використовується API або зберігається багато файлів, почніть із 4 vCPU, 8 ГБ RAM і 100 ГБ диска. Обирайте диск із запасом для резервних копій і вкладень.

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

VPS підходить більшості команд із кількома десятками операторів: його простіше запустити, він дешевший і легко масштабується за тарифом. Dedicated обирайте за постійного високого навантаження, вимоги до фізичної ізоляції, великого обсягу локальних вкладень або якщо на одному хості розміщується кілька критичних сервісів. Сам по собі dedicated не вирішує проблем із резервними копіями, безпекою та моніторингом. Для одного інстансу Chatwoot раціональніше почати з VPS і перейти на виділений сервер після вимірювання реального навантаження.

Як безпечно змінити домен Chatwoot?

Спочатку створіть DNS-запис нового домену, потім змініть FRONTEND_URL у .env і домен у Caddyfile. Перезапустіть сервіси: docker compose up -d --force-recreate rails worker caddy. Після цього перевірте curl -I https://new-chat.example.com. Старий домен бажано тимчасово залишити в Caddy як окремий сайт із перенаправленням, щоб старі посилання та вже завантажені віджети не припинили працювати миттєво.

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

Схема: Выводы и следующие шаги
Схема: Висновки та наступні кроки

Тепер у вас є self-hosted Chatwoot на VPS із Docker, PostgreSQL, Redis, HTTPS через Caddy і SMTP для системної пошти. Конфігурація ізолює внутрішні сервіси від інтернету, а резервне копіювання дає змогу відновити базу та файли після збою.

  1. Створіть inbox для сайту та підключіть віджет, потім додайте операторів через запрошення.
  2. Налаштуйте SPF, DKIM, DMARC і протестуйте доставляння листів зі справжньої клієнтської адреси.
  3. Підключіть моніторинг диска, пам’яті, доступності HTTPS та успішності нічних резервних копій.
  4. У разі зростання навантаження перенесіть вкладення до S3-сумісного сховища, а PostgreSQL — на окремий керований сервер або виділений вузол.

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

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

Share this post:

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

Telegram VKVK WhatsApp Facebook LinkedIn XX

встановлення Chatwoot на VPS: Docker, PostgreSQL, Redis, SSL і налаштування email
support_agent
Valebyte Support
Usually replies within minutes
Hi there!
Send us a message and we'll reply as soon as possible.