SSD Nodes Learn Hosting plans →
Посібники Matt ConnorВід Matt Connor · Оновлено 2026-08-28

Як встановити Discourse на VPS через Docker

Покрокове встановлення Discourse через офіційний Docker launcher: RAM і swap, домен, SMTP, app.yml, rebuild, TLS та reverse proxy без Compose.

Встановлення Discourse на VPS: один контейнер, один конфігураційний файл

Щоб встановити Discourse на VPS, запустіть власний інсталятор проєкту, дайте відповіді на запитання короткого майстра та дочекайтеся завершення збірки. Discourse постачається як один Docker-контейнер, що містить Rails-застосунок, PostgreSQL, Redis і nginx. Усі подальші зміни вносяться в один файл, /var/discourse/containers/app.yml, а кожна зміна застосовується до сайту через повторну збірку.

Офіційний спосіб встановлення — discourse_docker: shell-скрипт launcher і набір шаблонів YAML. Discourse не підтримує Compose-файл, який ви створюєте самостійно, а контейнер не призначений для ручного розділення. Якщо ви звикли запускати сервіси на VPS за допомогою Docker Compose, очікуйте іншої структури. Тут немає docker compose up -d, а ./launcher rebuild app — це розгортання.

Що потрібно Discourse до початку роботи

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

  • Пам’ять. Один контейнер запускає PostgreSQL, Redis, Sidekiq і Ruby web server. На етапі збірки компілюються ресурси, тому потрібно більше пам’яті, ніж для роботи готового сайту.
  • Справжнє доменне ім’я. У типовій конфігурації прямо зазначено: «Discourse не працюватиме з однією лише IP-адресою».
  • Канал для вихідної пошти. Листи для активації облікових записів, скидання паролів, запрошень адміністраторів і дайджестів надсилаються через SMTP (simple mail transfer protocol).
  • Вільні порти 80 і 443 на хості, якщо ви навмисно не розміщуєте Discourse за наявним reverse proxy.
ChartDiscourse published hardware requirements (official install docs, August 2026)
The data behind this chart
[
  {
    "label": "Documented minimum",
    "ram_gb": 1,
    "storage_gb": 10
  },
  {
    "label": "Documented recommended",
    "ram_gb": 2,
    "storage_gb": 20
  }
]

В офіційній інструкції зі встановлення мінімально потрібно 1 GB RAM зі swap і 10 GB дискового простору. Рекомендовано 2 GB RAM і 20 GB дискового простору. Перший рядок означає обсяг ресурсів, за якого інсталятор завершить роботу, а не обсяг, достатній для розгортання спільноти. Різниця важлива, оскільки пікове споживання пам’яті припадає на збірку, а не на обробку трафіку.

Вкажіть домен на сервер перед інсталяцією

Створіть A-запис для потрібного hostname, а потім перевірте його безпосередньо із сервера.

dig +short forum.example.com
curl -4 -s https://ifconfig.co

Обидві команди мають вивести однакову адресу. Вони повинні збігатися, оскільки майстер налаштування перевіряє з’єднання з вашим hostname, а запис, який досі вказує в інше місце, не проходить цю перевірку. Запис, створений дві хвилини тому, також може залишатися в кеші, тому дочекайтеся завершення старого TTL (time to live), а не намагайтеся обійти перевірку майстра.

Одразу визначтеся, чи буде запис проксійований CDN. Проксійований запис приховує адресу сервера, після чого запит сертифіката для контейнера завершується помилкою, оскільки ACME (automatic certificate management environment) challenge обробляє проксі, а не Discourse. Для першої інсталяції залиште запис без проксі.

Запустіть офіційний інсталятор

Одна команда встановлює git, встановлює Docker за допомогою власного інсталяційного скрипту Docker, клонує discourse_docker у /var/discourse і запускає майстер налаштування.

wget -qO- https://raw.githubusercontent.com/discourse/discourse_docker/main/install-discourse | sudo bash

Якщо Docker уже встановлено на сервері й ви хочете бачити кожен крок, виконайте ці дії вручну.

sudo -s
git clone https://github.com/discourse/discourse_docker.git /var/discourse
cd /var/discourse
./discourse-setup

Запускайте команду від імені root. Якщо запустити її від звичайного користувача, discourse-setup одразу завершується з This script must be run as root. Please sudo or log in as root first.. Якщо Docker не встановлено на сервері, команда завершується з Docker is not installed. Please install Docker first., оскільки ручне клонування нічого не встановлює.

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

Станом на серпень 2026 discourse-setup є тонкою обгорткою. Вона запускає discourse/setup-wizard:release як контейнер із host network і змонтованим Docker socket, щоб майстер міг перевірити машину, яку він налаштовує. Майстер запитує hostname та email-адреси адміністраторів, а потім параметри SMTP. Він записує containers/app.yml, після чого виконує повторну збірку.

Перед початком важливо знати про дві особливості. Якщо на машині недостатньо пам’яті й немає swap, майстер зупиняється та пропонує створити його: після цього обгортка створює 2 GB /swapfile, додає його до /etc/fstab, записує vm.swappiness = 10 у /etc/sysctl.d/30-discourse-swap.conf і повторно запускає майстер. Після завершення майстер виводить Rebuilding app in 5 seconds (Ctrl+C to cancel)... і запускає ./launcher rebuild app на host. Ця збірка на невеликому VPS триває кілька хвилин. Перша збірка найдовша, оскільки кожен asset компілюється з нуля.

./discourse-setup --help містить список прапорців, важливих для діагностики проблем. --skip-rebuild записує конфігурацію без збірки, а --skip-connection-test пропускає перевірки DNS і портів. Використовуйте --skip-connection-test лише тоді, коли вже знаєте причину помилки перевірки, наприклад якщо host працює за мережевим firewall, який ви контролюєте.

Прочитайте app.yml перед першою повторною збіркою

Майстер створює файл, який тепер потрібно підтримувати самостійно. Відкрийте його за допомогою sudo nano /var/discourse/containers/app.yml. Саме ці параметри визначають майже все.

templates:
  - "templates/postgres.template.yml"
  - "templates/redis.template.yml"
  - "templates/web.template.yml"
  - "templates/web.ratelimited.template.yml"
  ## Uncomment these two lines if you wish to add Lets Encrypt (https)
  #- "templates/web.ssl.template.yml"
  #- "templates/web.letsencrypt.ssl.template.yml"

expose:
  - "80:80"   # http
  - "443:443" # https

env:
  DISCOURSE_HOSTNAME: "forum.example.com"
  DISCOURSE_DEVELOPER_EMAILS: "you@example.com"
  DISCOURSE_SMTP_ADDRESS: smtp.example.com
  DISCOURSE_SMTP_PORT: 587
  DISCOURSE_SMTP_USER_NAME: user@example.com
  DISCOURSE_SMTP_PASSWORD: "your-smtp-password"

DISCOURSE_HOSTNAME — це адреса, на якій сайт приймає запити, а Discourse формує посилання на її основі. Тому неправильне значення дає сайт, який спочатку завантажується, а потім перенаправляє вас в інше місце. DISCOURSE_DEVELOPER_EMAILS — це список адрес, розділених комами. Під час першої реєстрації ці адреси автоматично отримують права адміністратора. Додайте туди власну адресу та зареєструйтеся з нею, оскільки саме так створюється перший обліковий запис адміністратора.

Файл зберігає пароль SMTP у відкритому вигляді, тому обмежте доступ до каталогу за допомогою sudo chmod 700 /var/discourse/containers. Це також YAML, а отже, пробіли є частиною конфігурації. Неправильне вирівнювання ключа призводить до помилки синтаксичного аналізу під час збірки, і сайт не створюється. Один із типових підводних каменів описано безпосередньо у прикладі файлу. # у паролі без лапок починає коментар, тому пароль, який містить цей символ, потрібно взяти в лапки.

Email — це етап, на якому зупиняється більшість інсталяцій

Станом на August 2026 майстер налаштування дає змогу пропустити SMTP і використовувати логіни Discourse ID. app.yml також містить відповідний перемикач DISCOURSE_SKIP_EMAIL_SETUP, який описаний як пропуск перевірки налаштування email. Пропустити цей етап доцільно, щоб уперше ознайомитися із software. Для community це невдалий вибір, оскільки без вихідної пошти ніхто не зможе активувати обліковий запис або скинути пароль.

Практична проблема полягає в тому, що більшість VPS-провайдерів блокують вихідний порт 25, тому звичайний mail server на цьому сервері не доставлятиме пошту. Використовуйте автентифікований relay на порту 587 або на порту 465 з implicit TLS (transport layer security). Для порту 465 встановіть DISCOURSE_SMTP_FORCE_TLS: true; це рекомендує sample config для цього порту. Перевірте доступність із host до повторного складання конфігурації.

nc -vz smtp.example.com 587

Успішний результат — один рядок, що закінчується на succeeded!. Якщо команда зависає, а потім завершується за timeout, це означає, що порт заблокований на вихідному шляху з вашого VPS. Жодне налаштування Discourse не усуне цю проблему. Перейдіть на порт, який дозволяє ваш провайдер, або попросіть провайдера відкрити цей порт.

Після запуску сайту надішліть тестове повідомлення зі сторінки Email у розділі Admin, а потім перегляньте вкладки Skipped і Bounced на цій самій сторінці. У цих вкладках Discourse записує пошту, яку він відмовився надсилати, і пошту, яку відхилив relay. Там також указано причину, тому це швидше, ніж читати журнали.

TLS: дозвольте контейнеру отримати власний сертифікат

Якщо Discourse використовує порти 80 і 443, скористайтеся вбудованим отриманням сертифіката. Розкоментуйте два рядки шаблону SSL, показані вище, а потім виконайте повторне складання. Шаблон керує acme.sh, зберігає сертифікати у спільному томі в /shared/ssl, поновлює їх за розкладом усередині контейнера та налаштовує Discourse на примусове використання HTTPS.

Порт 80 має залишатися доступним з інтернету, оскільки саме на ньому обробляється HTTP challenge. Якщо firewall дозволяє лише 443, збірка завершиться успішно, але сертифікат не буде отримано. Перевірте результат за допомогою ./launcher logs app одразу після повторного складання.

Чи варто розміщувати nginx або Caddy перед Discourse?

Якщо Discourse — єдиний вебсервіс на VPS, не робіть цього. Контейнер уже використовує оптимізований nginx, а другий проксі додає ще один мережевий перехід, ще один сертифікат для поновлення та нове джерело помилок у заголовках.

Розміщуйте проксі перед Discourse, якщо той самий VPS обслуговує інші сайти. Додайте templates/web.socketed.template.yml до списку шаблонів, закоментуйте обидва рядки expose і залиште два SSL-шаблони закоментованими. Тоді контейнер слухатиме unix socket за адресою /var/discourse/shared/standalone/nginx.http.sock і взагалі не займатиме порти. Порти 80 і 443 залишаться вільними для вашого проксі.

server {
  listen 443 ssl;
  server_name forum.example.com;

  location / {
    proxy_pass http://unix:/var/discourse/shared/standalone/nginx.http.sock:;
    proxy_set_header Host $http_host;
    proxy_http_version 1.1;
    proxy_set_header X-Forwarded-For $remote_addr;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Real-IP $remote_addr;
  }
}

Двокрапка після .sock є частиною синтаксису unix socket в nginx, а sudo nginx -t відмовляється приймати конфігурацію без неї. X-Forwarded-Proto також є обов’язковим. Discourse формує абсолютні посилання, тому без цього заголовка він генеруватиме посилання http:// на сторінці HTTPS, а браузери блокуватимуть їх як mixed content. Якщо контейнер працює через socket, TLS стає вашою відповідальністю, тому отримайте сертифікат на хості за допомогою Certbot в Ubuntu 24.04 і nginx. Якщо ви ще не обрали проксі, у порівнянні nginx, Caddy і Traefik описано компроміси між цими варіантами.

Перебудова, оновлення та команди, які ви фактично використовуватимете

cd /var/discourse
./launcher rebuild app

rebuild видаляє запущений контейнер, створює новий із app.yml і запускає його. Сайт недоступний протягом усієї перебудови, тому кожну зміну конфігурації слід планувати як кілька хвилин простою.

Зміни лише значень у env: цього не потребують. ./launcher destroy app && ./launcher start app повторно створює контейнер з уже зібраного образу, що займає кілька секунд. Будь-які зміни в templates: або hooks: змінюють сам образ, тому потребують повної перебудови.

Оновлення надходять двома способами. Точкові випуски встановлюються через вебінтерфейс у /admin/upgrade за допомогою плагіна docker_manager, який app.yml клонує під час збирання. Зміни базового образу або шаблонів надходять із git.

cd /var/discourse
git pull
./launcher rebuild app

Саме під час перебудови на невеликих серверах найчастіше виникають проблеми, оскільки компіляція ресурсів створює пікове навантаження на пам’ять у всій системі. Якщо збирання зупинилося на півдорозі, а dmesg показує рядок на кшталт Out of memory: Killed process із назвою процесу ruby, під час збирання завершилася доступна пам’ять, хоча до цього сайт працював нормально. Додайте swap і повторіть перебудову.

./launcher logs app
./launcher enter app
./launcher cleanup

logs виводить журнали контейнера, enter відкриває shell усередині нього, а cleanup видаляє контейнери, зупинені понад 24 години тому. Час від часу виконуйте cleanup, оскільки після кожної перебудови залишається старий контейнер, а дисковий простір на невеликому VPS непомітно закінчується.

Резервні копії та файл, якого в резервній копії немає

Створюйте резервні копії на сторінці Backups у розділі Admin. Архів зберігається на хості в /var/discourse/shared/standalone/backups/default/. Те саме завдання можна виконати з shell.

cd /var/discourse
./launcher enter app
discourse backup

discourse restore <filename> скасовує цю дію, а відновлення заборонено, доки не виконати discourse enable_restore. Цей захист потрібен, щоб випадкова команда не перезаписала робочий форум.

Є два моменти, які потрібно врахувати самостійно. Архів містить базу даних і завантажені файли лише тоді, коли ввімкнено параметр резервного копіювання, який додає uploads. Тому перевірте цей параметр, перш ніж покладатися на резервну копію. Архів ніколи не містить app.yml. Тому для відновлення на новому VPS все одно потрібні hostname і блок SMTP. Отже, цей файл також потрібно скопіювати за межі сервера.

Архів зберігається на тому самому диску, що й сайт, який він захищає. Це не є резервною копією. Регулярно копіюйте його в інше місце.

rsync -avz root@forum.example.com:/var/discourse/shared/standalone/backups/default/ ~/discourse-backups/

Скільки RAM потребує активний форум

Bootstrap встановлює UNICORN_WORKERS і db_shared_buffers на основі виявлених обсягу пам’яті та кількості CPU, а приклад конфігурації обмежує shared buffers до чверті загального обсягу пам’яті. Кожен worker unicorn — це окремий повноцінний Ruby-процес, а Sidekiq виконує фонові завдання паралельно з ними. Тому використання пам’яті залежить від кількості одночасних запитів, а не від кількості зареєстрованих учасників. Спокійний форум із кількома сотнями учасників не створює значного навантаження. Зазвичай важливіше, які інші сервіси працюють на цьому сервері. Якщо це фототека, виміряні мінімальні значення RAM у порівнянні PhotoPrism та Immich покажуть, чи залишиться достатньо ресурсів для завершення перебудови Discourse.

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

free -m
docker stats --no-stream

Постійне використання swap разом із повільним завантаженням сторінок означає, що RAM недостатньо. Якщо використання пам’яті стабільне, а сторінки повільні, причина, імовірно, інша. Перед придбанням дорожчого тарифу прочитайте ./launcher logs app. Додайте також перевірку із зовнішньої системи, оскільки форум, у якого о 3:00 закінчилася пам’ять, може непомітно припинити роботу: self-hosted моніторинг стану Uptime Kuma на окремому хості повідомить про проблему раніше, ніж її помітять учасники.

Коли Discourse — невдалий вибір

Discourse — це великий застосунок зі складним встановленням і циклом перебудови для кожного параметра, що зберігається в app.yml. Ці витрати виправдані повноцінними інструментами модерації та пошуком, який працює навіть у великому архіві. Для тридцяти людей, яким потрібне місце для спілкування, це надмірно потужне рішення. Спочатку прочитайте порівняння self-hosted форумного ПЗ і обирайте Discourse тому, що вам потрібні його можливості, а не тому, що ви вже знали цю назву.

FAQ

Чи можна встановити Discourse на VPS без доменного імені?

Ні. Конфігурація, що постачається з Discourse, вказує, що він не працюватиме з простою IP-адресою, а потрібен DISCOURSE_HOSTNAME. Discourse формує абсолютні посилання на основі цього імені хоста, тому IP-адреса порушує посилання та блокує видачу сертифіката. Створіть A-запис до початку встановлення та перевірте за допомогою dig +short forum.example.com, що він вказує на адресу вашого сервера.

Чи потрібно налаштовувати SMTP, щоб завершити встановлення?

Станом на August 2026 це можна пропустити. Майстер налаштування натомість пропонує входити через Discourse ID, а app.yml містить перемикач, який пропускає перевірку налаштування електронної пошти. Для повноцінного використання налаштуйте SMTP, оскільки активація облікових записів і скидання паролів надсилаються електронною поштою. Використовуйте автентифікований relay на порту 587 або 465, оскільки більшість VPS-провайдерів блокують вихідний порт 25.

Чому перебудова Discourse завершилася помилкою?

Найчастіше причина полягає в недостатньому обсязі пам’яті. Компіляція ресурсів під час складання потребує більше пам’яті, ніж запущений сайт, тому сервер, на якому форум працює без проблем, усе одно може не впоратися з його перебудовою. Якщо dmesg показує Out of memory: Killed process із назвою процесу ruby, додайте swap і знову виконайте ./launcher rebuild app. Власний swapfile майстра має розмір 2 GB. Якщо складання зупиняється через помилку YAML, це вказує на помилку відступів у app.yml.

Чи варто розміщувати Discourse за моїм nginx або Caddy?

Лише якщо VPS також обслуговує інші сайти. Якщо на сервері працює тільки Discourse, дозвольте контейнеру використовувати порти 80 і 443 та самостійно випускати сертифікат. Так буде менше компонентів для обслуговування. Щоб використовувати сервер спільно з іншими сайтами, додайте templates/web.socketed.template.yml, закоментуйте рядки expose і налаштуйте proxy до Unix-сокета за адресою /var/discourse/shared/standalone/nginx.http.sock. Передавайте X-Forwarded-Proto, інакше Discourse формуватиме посилання http:// на сторінці HTTPS.

Як створити резервну копію self-hosted Discourse?

Скористайтеся сторінкою Backups в Admin або виконайте discourse backup після ./launcher enter app. Архіви зберігаються на хості в /var/discourse/shared/standalone/backups/default/. Переконайтеся, що параметр включення uploads увімкнений, скопіюйте /var/discourse/containers/app.yml разом з архівом і перемістіть обидва файли на іншу машину. Резервна копія на тому самому диску, що й сайт, не переживе збій, від якого вона має захистити.