Как установить Discourse на VPS через Docker
Пошаговое руководство по развертыванию Discourse с помощью официального скрипта launcher. Узнайте, как настроить app.yml, SMTP, swap и TLS для корректной работы контейнера.
Установка Discourse на VPS: один контейнер, один файл конфигурации
Для установки Discourse на VPS необходимо запустить собственный инсталлятор проекта, ответить на вопросы мастера настройки и дождаться завершения сборки. Discourse поставляется как единый Docker-контейнер, содержащий приложение Rails, PostgreSQL, Redis и nginx. Все последующие изменения вносятся в один файл, /var/discourse/containers/app.yml, и каждое изменение применяется к сайту через пересборку.
Официальный способ установки — discourse_docker: это launcher shell-скрипт и набор YAML-шаблонов. Discourse не поддерживает файлы Compose, написанные вручную, и контейнер не предназначен для разделения на части вручную. Если вы привыкли к запуску сервисов на VPS с помощью Docker Compose, будьте готовы к другой структуре. Здесь нет docker compose up -d, а деплой выполняется через ./launcher rebuild app.
Что необходимо для работы Discourse перед началом установки
Четыре требования часто вызывают затруднения, и каждое из них проявляется еще до того, как вы попадете на страницу входа.
- Оперативная память. Один контейнер запускает PostgreSQL, Redis, Sidekiq и веб-сервер на Ruby. Этап сборки компилирует статические файлы и требует больше памяти, чем работающий сайт.
- Реальное доменное имя. В поставляемом примере конфигурации прямо сказано: "Discourse не будет работать с использованием только IP-адреса".
- Исходящая почта. Активация учетных записей, сброс паролей, приглашения администраторов и дайджесты рассылаются по протоколу SMTP (simple mail transfer protocol).
- Свободные порты 80 и 443 на хосте, если только вы намеренно не размещаете Discourse за уже работающим прокси-сервером.
The data behind this chart
[
{
"label": "Documented minimum",
"ram_gb": 1,
"storage_gb": 10
},
{
"label": "Documented recommended",
"ram_gb": 2,
"storage_gb": 20
}
]В официальной документации по установке указан минимум в 1 ГБ оперативной памяти с учетом swap и 10 ГБ дискового пространства, а рекомендуется 2 ГБ оперативной памяти и 20 ГБ дискового пространства. Первое значение — это тот минимум, который позволит завершить установку, а не тот, который нужен для комфортной работы сообщества. Разница важна, так как пиковое потребление памяти приходится на процесс сборки, а не на обработку сетевого трафика.
Направьте домен на сервер перед установкой
Создайте A-запись для используемого имени хоста, а затем проверьте её с самого сервера.
dig +short forum.example.com
curl -4 -s https://ifconfig.coОбе команды должны вывести одинаковый IP-адрес. Они должны совпадать, так как мастер установки выполняет проверку соединения с вашим именем хоста, и запись, указывающая на другой адрес, приведет к ошибке. Созданная две минуты назад запись может всё ещё находиться в кэше, поэтому дождитесь истечения старого TTL (time to live), вместо того чтобы пытаться обойти проверку мастера.
Заранее решите, будет ли запись проксироваться через CDN. Проксируемая запись скрывает адрес вашего сервера, из-за чего запрос сертификата для контейнера завершится ошибкой, так как на запрос ACME (automatic certificate management environment) ответит прокси, а не Discourse. Для первой установки оставьте запись без проксирования.
Запуск официального установщика
Одна команда устанавливает git, инсталлирует 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, чтобы мастер мог проанализировать машину, которую он настраивает. Мастер запрашивает имя хоста и адреса электронной почты администратора, а затем данные вашего SMTP-блока. Он записывает containers/app.yml, после чего выполняет пересборку.
Перед началом работы стоит учесть два нюанса. Если на машине недостаточно оперативной памяти и отсутствует swap, мастер останавливается и предлагает его создать: оболочка создает файл /swapfile объемом 2 GB, добавляет его в /etc/fstab, устанавливает vm.swappiness = 10 в /etc/sysctl.d/30-discourse-swap.conf и снова запускает мастер. По завершении работы мастер выводит Rebuilding app in 5 seconds (Ctrl+C to cancel)... и выполняет ./launcher rebuild app на хосте. Эта сборка занимает несколько минут на небольшом VPS, причем первая сборка самая медленная, так как все ресурсы компилируются с нуля.
./discourse-setup --help перечисляет флаги, которые важны при возникновении проблем. --skip-rebuild записывает конфигурацию без выполнения сборки, а --skip-connection-test пропускает проверки DNS и портов. Используйте --skip-connection-test только в том случае, если вы уже знаете причину сбоя теста, например, когда хост находится за сетевым межсетевым экраном, который вы контролируете.
Изучите 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, пробелы имеют значение: смещенный ключ приведет к ошибке парсинга при сборке, и сайт не запустится. Одна из ловушек описана в самом файле-примере. Символ # внутри пароля без кавычек начинает комментарий, поэтому обязательно заключайте в кавычки любой пароль, содержащий этот символ.
Настройка электронной почты — этап, на котором останавливается большинство установок
По состоянию на август 2026 года мастер установки позволяет пропустить настройку SMTP и использовать вместо этого учетные записи Discourse ID, а app.yml поддерживает соответствующий переключатель DISCOURSE_SKIP_EMAIL_SETUP, который, согласно описанию, отключает проверку настроек почты. Пропуск этого этапа оправдан для первого знакомства с ПО. Однако это плохой выбор для сообщества, так как без исходящей почты пользователи не смогут активировать учетные записи или сбросить пароль.
Практическая проблема заключается в том, что большинство VPS-провайдеров блокируют исходящий 25 порт, поэтому обычный почтовый сервер на хосте не сможет доставлять сообщения. Используйте аутентифицируемый релей на 587 порту или на 465 порту с использованием implicit TLS (transport layer security). Для 465 порта установите DISCOURSE_SMTP_FORCE_TLS: true, что рекомендуется в примере конфигурации для этого порта. Проверьте доступность перед пересборкой.
nc -vz smtp.example.com 587Успешным результатом является одна строка, заканчивающаяся на succeeded!. Если команда зависает и завершается по таймауту, это означает, что порт заблокирован на пути из вашего VPS, и никакие настройки Discourse это не исправят. Перейдите на порт, разрешенный вашим провайдером, или попросите провайдера открыть его.
После запуска сайта отправьте тестовое сообщение со страницы Email в панели администратора, затем проверьте вкладки Skipped и Bounced на той же странице. На этих вкладках Discourse фиксирует почту, которую он отказался отправлять, и сообщения, отклоненные релеем, с указанием причины. Это быстрее, чем изучать логи.
TLS: позвольте контейнеру получить собственный сертификат
Если Discourse занимает порты 80 и 443, используйте встроенный механизм выпуска сертификатов. Раскомментируйте две строки шаблона SSL, показанные выше, а затем выполните пересборку. Шаблон управляет acme.sh, сохраняет сертификаты в общем томе по пути /shared/ssl, обновляет их по расписанию внутри контейнера и настраивает Discourse на принудительное использование HTTPS.
Для работы этого механизма порт 80 должен оставаться доступным из Интернета, так как именно там происходит проверка HTTP challenge. Если межсетевой экран разрешает только порт 443, сборка завершится успешно, но сертификат не будет выпущен. Проверьте результат с помощью ./launcher logs app сразу после пересборки.
Стоит ли использовать nginx или Caddy в качестве фронтенда?
Если Discourse — единственный веб-сервис на VPS, делать этого не нужно. Контейнер уже содержит настроенный nginx, а дополнительный прокси добавит лишнее звено, необходимость обновлять еще один сертификат и новый источник ошибок в заголовках.
Используйте внешний прокси, если на этом же VPS работают другие сайты. Добавьте templates/web.socketed.template.yml в список шаблонов, закомментируйте обе строки expose и оставьте оба SSL-шаблона закомментированными. После этого контейнер будет слушать unix-сокет по адресу /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-сокетов в nginx, и sudo nginx -t отклонит конфигурацию без него. Параметр X-Forwarded-Proto также обязателен. Discourse генерирует абсолютные ссылки, поэтому без этого заголовка он будет выдавать http:// ссылки на HTTPS-странице, которые браузеры заблокируют как смешанный контент (mixed content). При работе через сокет ответственность за TLS ложится на вас, поэтому выпустите сертификат на хостовой системе, следуя руководству Certbot в Ubuntu 24.04 и nginx. Если вы еще не выбрали прокси, сравнение nginx, Caddy и Traefik поможет оценить преимущества и недостатки каждого решения.
Пересборка, обновление и команды, которые вам действительно понадобятся
cd /var/discourse
./launcher rebuild apprebuild уничтожает работающий контейнер, создает новый из 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 cleanuplogs выводит логи контейнера, enter открывает оболочку внутри него, а cleanup удаляет контейнеры, которые были остановлены более 24 часов назад. Периодически запускайте cleanup, так как каждая пересборка оставляет после себя старый контейнер, и на небольшом VPS место на диске может закончиться незаметно.
Резервные копии и файлы, которые в них не входят
Создавайте резервные копии на странице Backups в разделе Admin. Архив сохраняется на хосте по пути /var/discourse/shared/standalone/backups/default/. Эту же задачу можно запустить из командной строки.
cd /var/discourse
./launcher enter app
discourse backupКоманда discourse restore <filename> выполняет обратную операцию, при этом восстановление блокируется до тех пор, пока вы не выполните discourse enable_restore. Эта защита существует для того, чтобы случайная команда не перезаписала работающий форум.
Есть два нюанса, которые нужно учитывать самостоятельно. Архив содержит базу данных, а загруженные файлы — только если в настройках резервного копирования включена соответствующая опция, поэтому проверяйте этот параметр, прежде чем полагаться на архив. В него никогда не включается app.yml, поэтому при восстановлении на новый VPS вам всё равно потребуются настройки имени хоста и блока SMTP. Это означает, что данный файл также необходимо копировать с сервера отдельно.
Кроме того, архив хранится на том же диске, что и сам сайт, что не является полноценным резервным копированием. Регулярно копируйте архивы на стороннее хранилище по расписанию.
rsync -avz root@forum.example.com:/var/discourse/shared/standalone/backups/default/ ~/discourse-backups/Сколько оперативной памяти требует активный форум
Процесс начальной настройки устанавливает UNICORN_WORKERS и db_shared_buffers на основе обнаруженного объема памяти и количества ядер процессора, а пример конфигурации ограничивает shared buffers одной четвертью от общего объема памяти. Каждый воркер unicorn — это полноценный процесс Ruby, а Sidekiq выполняет фоновые задачи параллельно с ними, поэтому потребление памяти зависит от количества одновременных запросов, а не от числа зарегистрированных пользователей. Тихий форум с несколькими сотнями участников не создает высокой нагрузки.
Не выбирайте размер сервера на основе цифр из статей, включая эту. Проводите измерения на своей системе.
free -m
docker stats --no-streamПостоянное использование swap в сочетании с медленной загрузкой страниц означает нехватку оперативной памяти. Стабильное потребление памяти при медленной работе страниц обычно указывает на другие причины, поэтому ознакомьтесь с ./launcher logs app перед покупкой более дорогого тарифного плана. Также добавьте проверку извне, так как форум, которому не хватило памяти в 3 часа ночи, завершает работу незаметно: самостоятельно развернутый монитор состояния 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 для завершения установки?
По состоянию на август 2026 года этот шаг можно пропустить. Мастер настройки предлагает использовать логины Discourse ID, а app.yml содержит флаг, позволяющий пропустить проверку настройки электронной почты. Однако для полноценной работы SMTP необходимо настроить, так как активация аккаунтов и сброс паролей выполняются через почту. Используйте аутентифицированный релей на порту 587 или 465, так как большинство провайдеров VPS блокируют исходящий порт 25.
Почему пересборка Discourse прервалась на середине?
Обычно причина кроется в нехватке оперативной памяти. Компиляция ресурсов во время сборки требует больше памяти, чем работа уже запущенного сайта, поэтому сервер, который успешно обслуживает форум, может не справиться с его пересборкой. Если dmesg показывает Out of memory: Killed process с упоминанием процесса ruby, добавьте swap (стандартный swapfile мастера настройки имеет размер 2 ГБ) и запустите ./launcher rebuild app снова. Если сборка останавливается с ошибкой YAML, это указывает на ошибку в отступах в файле app.yml.
Стоит ли размещать Discourse за собственным Nginx или Caddy?
Только если на этом же VPS работают другие сайты. Если сервер выделен только под Discourse, позвольте контейнеру занять порты 80 и 443 и самостоятельно выпускать сертификаты — это упрощает архитектуру. Для совместного использования сервера добавьте templates/web.socketed.template.yml, закомментируйте строки expose и настройте проксирование на unix-сокет по пути /var/discourse/shared/standalone/nginx.http.sock. Передавайте заголовок X-Forwarded-Proto, иначе Discourse будет генерировать ссылки http:// на HTTPS-странице.
Как выполнять резервное копирование собственного экземпляра Discourse?
Используйте страницу Backups в панели администратора или выполните команду discourse backup после ./launcher enter app. Архивы сохраняются на хосте по пути /var/discourse/shared/standalone/backups/default/. Убедитесь, что включена настройка включения загружаемых файлов (uploads), скопируйте /var/discourse/containers/app.yml вместе с архивом и перенесите их на другую машину, так как резервная копия на том же диске, где находится сайт, не защитит от аппаратного сбоя.