Як розгорнути Chatwoot на VPS через Docker
Покрокове розгортання Chatwoot на VPS через Docker Compose і Traefik: зафіксовані теги, робочий SMTP, резервні копії Postgres та uploads і безпечні оновлення.
Що ви розгортаєте
Щоб розмістити Chatwoot на VPS, потрібно запустити чотири контейнери: вебпроцес Rails, фоновий worker Sidekiq, PostgreSQL із розширенням pgvector і Redis. Chatwoot — це open source система підтримки клієнтів. Вона надає спільну командну скриньку та вебвіджет чату на сервері під вашим керуванням. Встановлення займає близько двадцяти хвилин. Далі все залежить від доставки пошти, резервного копіювання, оновлень і вибору ресурсів. Саме це визначає, чи працюватиме система через рік.
Кожен контейнер має окреме завдання. Rails обслуговує панель оператора та API віджета. Sidekiq виконує повільні операції: надсилає електронні листи, опитує підключені канали, запускає правила автоматизації та формує звіти. Postgres зберігає розмови, контакти, облікові записи операторів і всі налаштування, які ви змінюєте в панелі. Redis зберігає черги Sidekiq і канал pub/sub ActionCable, який передає нове повідомлення у відкриту панель без перезавантаження сторінки. У цій схемі Redis не є тимчасовим кешем, оскільки його втрата означає втрату завдань у черзі.
В upstream-файлі compose використовується образ Postgres pgvector/pgvector:pg16, а не стандартний образ postgres, оскільки схема Chatwoot вмикає розширення vector для функцій AI. Якщо замінити його на стандартний Postgres, перший запуск бази даних завершиться помилкою ERROR: extension "vector" is not available, оскільки в цьому образі немає керівного файла розширення. Використовуйте образ, який постачається upstream.
У цьому посібнику передбачається, що Docker і reverse proxy вже працюють на сервері. Якщо це не так, спочатку ознайомтеся з матеріалом Docker Compose на VPS, а потім поверніться до цього посібника.
Скільки ресурсів VPS потрібно для self-hosted Chatwoot?
Станом на серпень 2026 року на сторінці вимог upstream вказано мінімум 4 GB RAM і 4 CPU cores. Цього достатньо для 10,000 conversations на день. Для 8 GB RAM і 8 CPU cores вказано до 20,000 conversations на день. Також потрібно щонайменше 1 GB swap. Причина прямо зазначена в документації: це запобігає вичерпанню пам’яті під час оновлення. Перед урахуванням file uploads заплануйте від 5 GB до 10 GB дискового простору для Postgres.
Тепер без прикрас. VPS із 2 GB RAM запустить Chatwoot, і за наявності двох агентів та невеликої кількості повідомлень усе може працювати нормально. Проблеми виникають у двох випадках. Перша — Sidekiq. За даними upstream, на завантаженому сервері він використовує понад 1 GB RAM. Сплеск email або запуск завдання для звіту вичерпує пам’ять ще до того, як свою частину отримають Rails, Postgres і Redis. Друга — оновлення. Під час нього db:chatwoot_prepare запускає новий процес Rails для застосування міграцій. На цьому образі запуск Rails потребує сотень мегабайт ще до початку корисної роботи.
Попередження зазвичай не буде. OOM killer ядра надсилає найбільшому процесу SIGKILL. Docker фіксує завершення контейнера, а restart: always запускає його знову. У docker compose ps після цього видно контейнер, який постійно повертається до Exited (137), де 137 означає завершення сигналом 9. Підтвердьте це за допомогою sudo dmesg -T | grep -i "killed process". Команда покаже процес, вибраний ядром.
Якщо 4 GB RAM не входять до бюджету, використовуйте VPS із 2 GB RAM і 2 GB swap. У такому разі під навантаженням час відповіді збільшуватиметься, але сервіс не обов’язково повністю завершуватиметься. У будь-якому разі варто встановити жорстке обмеження пам’яті для кожного сервісу. Це не дасть worker вичерпати пам’ять і зупинити базу даних. Див. обмеження пам’яті в Docker Compose.
File uploads — це дані, обсяг яких зростає без установленого вами обмеження. Кожен screenshot, прикріплений клієнтом, потрапляє у storage volume і залишається там. Тому контролюйте docker system df -v, а не припускайте, що диск заповнила база даних.
Отримайте compose-файл і зафіксуйте тег версії
mkdir -p ~/chatwoot && cd ~/chatwoot
wget -O .env https://raw.githubusercontent.com/chatwoot/chatwoot/develop/.env.example
wget -O docker-compose.yaml https://raw.githubusercontent.com/chatwoot/chatwoot/develop/docker-compose.production.yaml
chmod 600 .envУ щойно завантаженому файлі зазначено image: chatwoot/chatwoot:latest. Змініть це, перш ніж робити щось інше.
services:
base: &base
image: chatwoot/chatwoot:v4.16.2
env_file: .env
volumes:
- storage_data:/app/storagelatest означає, що наступний docker compose pull встановить будь-яку версію, опубліковану того ранку. Це може бути основна версія зі змінами для міграції, про які ви навіть не читали. Міграції Chatwoot на практиці незворотні, тому випадковий перехід на нову версію означає відновлення з резервної копії, а не скасування змін. Зафіксуйте тег і змінюйте його свідомо. v4.16.2 була поточною версією станом на August 2026; перевірте сторінку релізів, щоб визначити тег, який потрібно зафіксувати сьогодні.
Сервіс base — це YAML anchor, який об’єднують rails і sidekiq. Тому зміна тега в одному місці змінює його для обох сервісів. Поки файл відкритий, видаліть рядок version: '3' на початку. Сучасний Compose ігнорує його та виводить the attribute 'version' is obsolete, it will be ignored під час кожної команди.
Заповніть файл .env
Спочатку згенеруйте секрет. Upstream вимагає алфавітно-цифрове значення, оскільки спеціальні символи можуть спотворюватися під час передавання значення через shell або YAML-парсер.
head /dev/urandom | tr -dc A-Za-z0-9 | head -c 63 ; echo ''Потім задайте ці ключі в .env.
SECRET_KEY_BASE=<the 63 characters you just generated>
FRONTEND_URL=https://support.example.com
FORCE_SSL=true
DEFAULT_LOCALE=en
ENABLE_ACCOUNT_SIGNUP=true
POSTGRES_HOST=postgres
POSTGRES_USERNAME=postgres
POSTGRES_PASSWORD=<long random string>
POSTGRES_DATABASE=chatwoot
REDIS_URL=redis://redis:6379
REDIS_PASSWORD=<a different long random string>
RAILS_ENV=production
INSTALLATION_ENV=docker
ACTIVE_STORAGE_SERVICE=localPOSTGRES_HOST=postgres і redis://redis:6379 — це назви сервісів Compose, які визначаються в мережі за замовчуванням цього проєкту. FRONTEND_URL — не декоративне поле. Chatwoot формує з нього URL скрипту віджета та кожного посилання у вихідному електронному листі. Тому неправильне значення створює посилання для скидання пароля на хост, який не відповідає.
Тепер пастка у файлі upstream. Сервіс postgres не читає .env. Він має власний блок environment, де POSTGRES_PASSWORD= залишено порожнім. Тому задання пароля лише в .env залишає базу даних без пароля, а застосунок — із паролем. Вкажіть для сервісу ту саму змінну:
postgres:
image: pgvector/pgvector:pg16
restart: always
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
- POSTGRES_DB=chatwoot
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}Compose читає .env з каталогу проєкту для підстановки ${...}, тому обидві сторони отримують однаковий рядок. Якщо зробити це неправильно, Rails завершує роботу з помилкою PG::ConnectionBad: FATAL: password authentication failed for user "postgres".
Одна особливість дивує майже всіх: образ Postgres застосовує POSTGRES_PASSWORD лише під час ініціалізації порожнього каталогу даних. Подальша зміна значення не впливає на результат, оскільки initdb не запускається повторно. Якщо стек уже було запущено, змініть пароль безпосередньо в базі даних.
docker compose exec postgres psql -U postgres -c "ALTER USER postgres WITH PASSWORD 'the-new-password';"ENABLE_ACCOUNT_SIGNUP=true — тимчасове налаштування. Воно відкриває публічну форму реєстрації, щоб ви могли створити перший обліковий запис. Щойно обліковий запис буде створено, задайте false і знову виконайте docker compose up -d. Інакше будь-хто, хто знайде URL, зможе зареєструватися у вашій системі підтримки. Надалі агенти отримують доступ за запрошеннями, а їхні паролі зберігаються лише в цьому застосунку. Цього достатньо, доки ви не запустите близько півдюжини сервісів і не втомитеся вести окремий список облікових записів у кожному. На цьому етапі self-hosted постачальник ідентифікації на кшталт Authentik замінює ці окремі списки.
.env тепер містить усі секрети цього стека у відкритому тексті. Тому встановіть для файлу режим 600 і не додавайте його до git. У матеріалі Як Compose читає env-файли та де витікають секрети розглянуто критичні нюанси, зокрема різницю між env_file і environment.
Розміщення Chatwoot за наявним Traefik
Не створюйте другий reverse proxy для одного застосунку. Якщо Traefik уже завершує TLS (transport layer security) для інших контейнерів на цьому сервері, Chatwoot підключається до нього через блок labels. Якщо Traefik ще не налаштований, спочатку налаштуйте його один раз за інструкцією Traefik перед кількома застосунками Docker Compose, а потім поверніться сюди.
Не змінюйте upstream docker-compose.yaml без потреби, щоб згодом можна було порівняти його з новішою копією через diff. Зміни виносьте в override-файл. Compose автоматично об’єднує docker-compose.override.yaml, а в матеріалі розділення Compose на кілька файлів описано правила цього об’єднання.
services:
rails:
networks:
- default
- proxy
labels:
- "traefik.enable=true"
- "traefik.http.routers.chatwoot.rule=Host(`support.example.com`)"
- "traefik.http.routers.chatwoot.entrypoints=websecure"
- "traefik.http.routers.chatwoot.tls.certresolver=letsencrypt"
- "traefik.http.services.chatwoot.loadbalancer.server.port=3000"
networks:
proxy:
external: trueВикористовуйте власні назви entrypoint і certresolver. Контейнер має перебувати в тій самій Docker network, що й Traefik. Саме це забезпечує запис proxy. Водночас контейнер має залишатися також у default, інакше він втратить доступ до Postgres і Redis. Про цей другий рядок часто забувають.
Не змінюйте блок ports:. Upstream прив’язує його до 127.0.0.1:3000, а це loopback-адреса. Тому сервіс недоступний з інтернету, але залишається придатним для тестування зсередини сервера через curl -I http://127.0.0.1:3000.
Панель оператора підтримує websocket-з’єднання з /cable для доставки повідомлень у реальному часі. Traefik пересилає HTTP upgrade без додаткової конфігурації, тому нічого додавати не потрібно. Якщо згодом розмістите CDN або інший proxy перед Traefik, дозвольте websocket-з’єднання на цьому рівні. Інакше панель завантажуватиметься нормально, але нові повідомлення з’являтимуться лише після ручного оновлення сторінки.
Ініціалізуйте базу даних і запустіть стек
Спочатку запустіть сервіси даних і дочекайтеся завершення першого запуску Postgres.
docker compose up -d postgres redis
docker compose logs postgres | tail -n 5Дочекайтеся database system is ready to accept connections. Потім створіть схему.
docker compose run --rm rails bundle exec rails db:chatwoot_prepareЦя команда створює базу даних, якщо її немає, а потім завантажує схему та стандартні початкові дані. Вона виводить рядки міграції та завершується без помилок. Якщо вона продовжує виводити postgres:5432 - no response, entrypoint очікує базу даних, яка ще не приймає підключення. Під час першого запуску це зазвичай означає, що initdb ще виконується. Дочекайтеся завершення, перегляньте журнали Postgres і запустіть команду ще раз. Якщо виконання зупиняється на розширенні vector, ви замінили образ pgvector на стандартний Postgres.
docker compose up -d
docker compose ps
docker compose logs --tail 30 railsДля всіх чотирьох контейнерів має відображатися Up, а журнал rails має завершуватися рядком Puma, що прослуховує http://0.0.0.0:3000. Потім перевірте публічний шлях:
curl -sI https://support.example.com | head -n 1HTTP/2 200 означає, що весь ланцюжок працює. Відповідь 404 від Traefik означає, що правило маршрутизатора не збіглося, зазвичай через помилку в імені хоста. Відповідь 502 означає, що Traefik зіставив маршрутизатор, але не зміг підключитися до контейнера. Майже завжди причина — відсутня мережа proxy або loadbalancer.server.port, що має значення, відмінне від 3000.
Відкрийте URL, створіть обліковий запис на /app/auth/signup, потім установіть ENABLE_ACCOUNT_SIGNUP=false і виконайте docker compose up -d, щоб закрити форму.
Чому скидання пароля та листування електронною поштою не працюють без SMTP
Chatwoot без налаштувань SMTP (простого протоколу передавання пошти) — це служба підтримки, яка не може надсилати електронні листи. Через це перестають працювати не лише сповіщення. Скидання пароля не працює, тому адміністратор, який втратив доступ, не може його відновити. Запрошення агентів також не надсилаються, оскільки запрошення надходить електронною поштою. Відповіді клієнту в електронному листуванні не надсилаються, тому розмова працює лише в одному напрямку. Це налаштування часто пропускають, а потім виявляють проблему в найгірший момент.
Механізм простий. Без налаштувань SMTP ActionMailer зберігає стандартне значення: доставляти пошту до localhost через порт 25. Усередині контейнера Rails немає поштового сервера, тому завдання доставки завершується помилкою Errno::ECONNREFUSED: Connection refused - connect(2) for "localhost" port 25. Пошта надсилається з фонового завдання, тому цей рядок з’являється в журналі Sidekiq, а не в журналі Rails. Водночас користувач, який натискає «забули пароль», бачить повідомлення про успішне виконання, але нічого не отримує.
MAILER_SENDER_EMAIL=Support <support@example.com>
SMTP_DOMAIN=example.com
SMTP_ADDRESS=smtp.example.com
SMTP_PORT=587
SMTP_USERNAME=support@example.com
SMTP_PASSWORD=<the relay password>
SMTP_AUTHENTICATION=plain
SMTP_ENABLE_STARTTLS_AUTO=trueВикористовуйте порт 587 із STARTTLS. Він відкриває з’єднання у відкритому вигляді, а перед автентифікацією переводить його в зашифрований режим. Більшість VPS-провайдерів блокують вихідний порт 25, щоб обмежити спам. Тому relay на порту 587 зазвичай є єдиним варіантом, який взагалі встановлює з’єднання. SMTP_DOMAIN — це домен, який сервер оголошує під час SMTP-сеансу. Деякі relay відхиляють невідповідність цього домену.
Застосуйте налаштування та моніторте worker:
docker compose up -d rails sidekiq
docker compose logs -f sidekiqЗапустіть скидання пароля зі сторінки входу. Якщо доставка працює, у журналі Sidekiq буде видно штатне завершення завдання mailer. У разі помилки спочатку відображається клас винятку, після чого Sidekiq повторює спробу зі щоразу довшою затримкою. Тому несправний relay спричиняє ту саму помилку кожні кілька хвилин протягом кількох годин.
Поширені два типи відхилення, і жоден із них не є помилкою Chatwoot. 535 Authentication failed означає, що ім’я користувача або пароль для цього relay неправильні. Багато провайдерів вимагають пароль застосунку, а не пароль облікового запису. 550 Sender address rejected означає, що MAILER_SENDER_EMAIL — це адреса, від якої relay не дозволяє надсилати листи. Тому це має бути поштова скринька або домен, які ви підтвердили в цього провайдера.
Отримання електронних листів у розмову — окреме завдання. Для цього потрібні MAILER_INBOUND_EMAIL_DOMAIN і RAILS_INBOUND_EMAIL_SERVICE, а також поштовий сервер, який передає вхідні повідомлення Chatwoot. Оренда relay — найшвидший варіант. Якщо ви хочете самостійно керувати всім шляхом доставки пошти, у матеріалі про запуск власного поштового сервера з Mailcow описано, що передбачає таке рішення.
Що потрібно резервувати і як перевірити відновлення
Резервна копія Chatwoot складається з чотирьох частин. Якщо пропустити будь-яку з них, відновлення перетвориться на повторне розгортання.
- База даних Postgres, у якій зберігаються розмови, контакти, облікові записи агентів і всі налаштування.
- Том
storage_data, оскількиACTIVE_STORAGE_SERVICE=localзаписує завантажені файли на диск і зберігає в Postgres лише рядок із посиланням на файл. - Файл
.env, оскільки в ньому зберігаютьсяSECRET_KEY_BASEі ключіACTIVE_RECORD_ENCRYPTION_*. - Файли compose, оскільки в них зафіксовано точний тег образу, якому відповідає схема бази даних.
Якщо відновити лише базу даних, усі розмови повернуться з непрацюючими вкладеннями, оскільки в рядках будуть посилання на файли, яких більше немає на диску.
cd ~/chatwoot
docker compose exec -T postgres pg_dump -U postgres -Fc chatwoot > db-$(date +%F).dumpПараметр -T має значення. Без нього Compose виділяє псевдотермінал, який змінює байти нового рядка у потоці. У результаті ви отримуєте файл дампа, який pg_restore відхиляє. -Fc — це власний формат, який стискає дані та дає змогу pg_restore працювати вибірково.
docker run --rm -v chatwoot_storage_data:/data:ro -v "$PWD":/backup alpine \
tar czf /backup/storage-$(date +%F).tgz -C /data .Назва тому складається з назви каталогу проєкту та _storage_data. Перевірте її командою docker volume ls | grep storage_data, перш ніж довіряти цій команді, оскільки Docker створює порожній том замість помилки, якщо вказати неіснуючий том. У результаті ви отримаєте коректний порожній архів без жодної помилки. Після цього перевірте його розмір командою ls -lh storage-*.tgz.
Тепер обидва файли розміщені на тому самому диску, що й дані, які вони мають захищати. Це не захищає вас від втрати диска. Передайте файли на інший майданчик і зашифруйте їх, оскільки дамп бази даних містить усі повідомлення клієнтів у відкритому вигляді. У розділі Зашифровані резервні копії на іншому майданчику за допомогою restic описано планування та зберігання резервних копій.
Перевірка відновлення: виконайте її до виникнення потреби
Відновлюйте дані на другому VPS, а не на робочому сервері. Скопіюйте .env, файли compose і обидва архіви на другий сервер, а потім виконайте:
docker compose up -d postgres
docker compose exec -T postgres pg_restore -U postgres -d chatwoot --clean --if-exists < db-2026-08-10.dump
docker run --rm -v chatwoot_storage_data:/data -v "$PWD":/backup alpine \
sh -c 'rm -rf /data/* && tar xzf /backup/storage-2026-08-10.tgz -C /data'
docker compose up -d--clean --if-exists видаляє наявні об’єкти перед завантаженням даних. Тому використовуйте цю команду лише для бази даних, яку можна втратити. Потім увійдіть у систему та відкрийте розмову з вкладенням. Якщо список повідомлень завантажується, а файл можна завантажити, резервна копія справна.
Відновлення з іншим SECRET_KEY_BASE робить недійсними всі cookies сеансів, тому всі користувачі вийдуть із системи. Відновлення з іншими ключами ACTIVE_RECORD_ENCRYPTION_* має серйозніші наслідки: Chatwoot не може розшифрувати стовпці з обліковими даними каналів і генерує ActiveRecord::Encryption::Errors::Decryption. Саме тому .env потрібно включати до резервної копії.
Як оновити Chatwoot до нового тегу
Порядок дій важливіший за самі команди.
- Прочитайте примітки до випуску між вашим тегом і цільовим тегом та перевірте, чи потрібні ручні дії.
- Створіть свіжий дамп бази даних і архів сховища. Переконайтеся, що розміри обох файлів виглядають коректно.
- Змініть тег образу для сервісу
baseуdocker-compose.yaml. - Завантажте новий образ, зупиніть стек, виконайте міграції, а потім знову запустіть стек.
docker compose pull
docker compose down
docker compose run --rm rails bundle exec rails db:chatwoot_prepare
docker compose up -d
docker compose imagesЗавантажте образ до запуску міграцій, оскільки міграцію потрібно виконувати з нового образу: старий образ не містить нових файлів міграцій. Зупиніть стек перед міграцією, оскільки старий код і нова схема несумісні. Запущений процес Rails зі старим кодом може створювати помилки або записувати рядки, які нова схема не прийме. Зупинка також звільняє пам’ять, потрібну міграції. Саме тому upstream вимагає swap.
docker compose images виводить тег, під яким фактично запущений кожен контейнер. Це допомагає виявити ситуацію, коли ви змінили тег, але забули завантажити новий образ.
Не переходьте одразу через багато версій. Для старої інсталяції upstream радить послідовно проходити проміжні теги, оскільки міграції видаляють після перенесення їхньої логіки до базової схеми. Через це дуже стара база даних може опинитися у стані, для якого немає подальшого шляху оновлення. Переходьте на одну minor-версію за раз і після кожного переходу виконуйте крок підготовки.
Якщо Rails запускається до виконання міграції, він відмовляється обслуговувати запити та записує в журнал ActiveRecord::PendingMigrationError: Migrations are pending. Якщо встановлено restart: always, контейнер перезапускається по колу, тому docker compose ps показує час роботи, який скидається кожні кілька секунд. Виконайте крок підготовки, і проблема зникне.
Відкат означає повернення старого тегу та відновлення дампу. На надійний шлях зворотної міграції розраховувати не можна. Саме для цього потрібен крок 2.
Режими відмов і повідомлення, які ви побачите
502 Bad Gateway від Traefik. Маршрутизатор знайшов відповідний маршрут, але бекенд не відповів. Перевірте, що docker compose ps показує rails як Up, потім виконайте docker network inspect proxy і переконайтеся, що контейнер rails є у списку контейнерів. Контейнер, який не підключений, невидимий для Traefik. Тому запит відповідає маршрутизатору, але далі не проходить.
Панель завантажується, але для перегляду нових повідомлень потрібно оновити сторінку. WebSocket-з’єднання з /cable не проходить або FRONTEND_URL не відповідає адресі в адресному рядку браузера. Якщо адреси не збігаються, сторінка намагається відкрити WebSocket-з’єднання з іншим origin, а браузер його блокує.
FATAL: password authentication failed for user "postgres". Пароль у .env відрізняється від пароля, збереженого у томі даних Postgres. Виправте його за допомогою ALTER USER у запущеному контейнері, оскільки повторне редагування .env не змінить уже ініціалізовану базу даних.
NOAUTH Authentication required. Redis запущено з --requirepass, але застосунок підключився без пароля. Отже, REDIS_PASSWORD відсутній у .env або його значення не було застосовано. Перевірте це безпосередньо за допомогою docker compose exec redis redis-cli -a "$REDIS_PASSWORD" ping. У відповідь має бути PONG.
Контейнери завершуються з кодом 137. Це SIGKILL. На невеликому сервері його зазвичай надсилає механізм ядра, який завершує процеси через нестачу пам’яті. Додайте swap, встановіть обмеження пам’яті для окремих сервісів або перейдіть на більший план.
FAQ
Скільки RAM потрібно VPS із self-hosted Chatwoot?
Станом на August 2026 upstream вимагає щонайменше 4 GB RAM і 4 CPU cores для навантаження до 10,000 розмов на день, а для 20,000 розмов — 8 GB і 8 cores. Додайте щонайменше 1 GB swap, оскільки під час оновлення запускається другий Rails-процес для застосування міграцій, і саме тоді на малих VPS закінчується пам’ять. VPS із 2 GB запускається та працює для кількох агентів, але лише Sidekiq під навантаженням може використати понад 1 GB. Тому під час пікових періодів і оновлень очікуйте завершення контейнерів з exit code 137.
Чому листи для скидання пароля Chatwoot ніколи не надходять?
Тому що SMTP-параметри не налаштовані. Через це ActionMailer намагається доставити лист на localhost через port 25, але всередині контейнера немає mail server. Завдання завершується помилкою в Sidekiq з Errno::ECONNREFUSED: Connection refused - connect(2) for "localhost" port 25, хоча браузер продовжує показувати повідомлення про успішне виконання. Встановіть SMTP_ADDRESS, SMTP_PORT, SMTP_USERNAME, SMTP_PASSWORD і MAILER_SENDER_EMAIL у .env, перезапустіть сервіси rails і sidekiq, а потім моніторте docker compose logs -f sidekiq під час запуску процедури скидання пароля.
Що потрібно резервно копіювати для відновлення Chatwoot?
Базу даних Postgres, Docker volume storage_data, файл .env і compose-файли. Однієї бази даних недостатньо, оскільки завантажені файли зберігаються у volume, а Postgres містить лише посилання на них. Тому відновлення лише бази даних дає розмови з пошкодженими вкладеннями. .env важливий, оскільки інший SECRET_KEY_BASE вийде з облікових записів усіх користувачів, а інші ключі ACTIVE_RECORD_ENCRYPTION_* зроблять зашифровані стовпці непридатними для читання.
Як оновити Chatwoot без пошкодження бази даних?
Створіть резервну копію, змініть image tag у compose-файлі, а потім виконайте docker compose pull, docker compose down, docker compose run --rm rails bundle exec rails db:chatwoot_prepare і docker compose up -d. Спочатку завантажте новий image, оскільки міграції мають виконуватися з нього. Перед цим зупиніть stack, оскільки старий код у разі роботи з новою схемою спричиняє помилки. У старій інсталяції переходьте на одну minor version за раз, оскільки міграції видаляються після включення до базової схеми.
Чи можна використовувати стандартний image postgres замість pgvector?
Ні. Схема Chatwoot вмикає extension vector, тому стандартний image postgres завершує роботу з помилкою під час db:chatwoot_prepare: ERROR: extension "vector" is not available. Це відбувається тому, що control file extension відсутній у цьому image. Залиште pgvector/pgvector:pg16 з upstream compose-файлу або використовуйте інший image, який постачає pgvector для вашої major version Postgres.