Установка 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: это shell-скрипт launcher и набор 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 в виде контейнера с использованием сетевого стека хоста и примонтированным Docker socket, чтобы мастер мог проанализировать машину, которую он настраивает. Мастер запрашивает имя хоста и адреса электронной почты администратора, а затем данные вашего SMTP-блока. Он записывает containers/app.yml, после чего выполняет пересборку.
Перед началом работы стоит учесть два нюанса. Если на машине недостаточно оперативной памяти и отсутствует swap, мастер останавливается и предлагает его создать: оболочка создает файл /swapfile размером 2 ГБ, добавляет его в /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 генерирует абсолютные ссылки, поэтому без этого заголовка на HTTPS-странице будут создаваться ссылки http://, которые браузеры заблокируют как смешанный контент. При работе через сокет управление 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 выполняет фоновые задачи параллельно с ними, поэтому потребление памяти зависит от количества одновременных запросов, а не от числа зарегистрированных пользователей. Тихий форум с несколькими сотнями участников не создает высокой нагрузки. Обычно гораздо важнее то, какие еще сервисы работают на этом же сервере; если это фотохостинг, то измеренные минимальные значения ОЗУ в сравнении PhotoPrism и Immich подскажут, хватит ли ресурсов для завершения пересборки Discourse.
Не выбирайте размер сервера на основе цифр из статьи, включая эту. Проводите собственные измерения.
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, что она указывает на IP-адрес вашего сервера.
Обязательно ли настраивать SMTP для завершения установки?
По состоянию на август 2026 года этот шаг можно пропустить. Мастер настройки предлагает использовать учетные данные Discourse ID, а app.yml содержит флаг, позволяющий пропустить проверку настройки электронной почты. Однако для полноценной работы SMTP необходимо настроить, так как активация учетных записей и сброс паролей выполняются через почтовые уведомления. Используйте аутентифицированный релей на порту 587 или 465, так как большинство провайдеров VPS блокируют исходящий трафик на порту 25.
Почему пересборка Discourse прерывается на середине?
Обычно причиной является нехватка оперативной памяти. Компиляция ресурсов во время сборки требует больше памяти, чем работа уже запущенного сайта, поэтому сервер, который успешно обслуживает форум, может не справиться с его пересборкой. Если dmesg показывает Out of memory: Killed process с упоминанием процесса ruby, добавьте swap (стандартный файл подкачки мастера установки имеет размер 2 GB) и запустите ./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/. Убедитесь, что включена настройка сохранения загружаемых файлов, скопируйте /var/discourse/containers/app.yml вместе с архивом и переместите их на другую машину, так как резервная копия на том же диске, где находится сайт, не защитит от аппаратного сбоя.