RE:NODE

Хостинг блога на Ghost: установка, почта, темы, бэкапы и обновления

Автор Команда RE:NODE
16 мин чтения


Блогу на Ghost на собственном сервере нужно меньше, чем обычно ожидают: около 1 ГБ памяти для личного сайта, домен с HTTPS перед ним, настройка url, точно совпадающая с этим доменом, и работающая исходящая почта. Именно на последних двух пунктах ломается почти каждая неудачная установка Ghost. Настройте адрес и почту в первый же день, храните копию папки content где-нибудь кроме самого сервера - и всё остальное, то есть темы, подписчики, рассылки и обновления, превращается в обычную работу в админке.

В этом руководстве разобрано, из чего на самом деле состоит Ghost на сервере, какой сервер ему нужен, несколько настроек, которые действительно важны, разница между двумя видами писем, которые отправляет Ghost, темы, бэкапы и обновления, а также ошибки, с которыми сталкиваются чаще всего.

Из чего состоит установка Ghost на своём сервере#

Ghost - это приложение на Node.js. Всё, что вы видите, - публичный сайт, портал для подписчиков, редактор по адресу /ghost - отдаёт один долгоживущий процесс, который слушает один порт. По умолчанию это порт 2368. Ghost не нужны ни PHP, ни отдельный веб-сервер, ни задачи cron: это один процесс и его файлы.

Эти файлы делятся на две группы, и понимать это разделение полезнее всего, прежде чем что-то трогать:

  • Приложение - собственный код Ghost и его зависимости Node.js. Он заменяется при каждом обновлении, и редактировать его не стоит никогда.
  • Папка `content` - всё, что принадлежит вам. Ваши темы в content/themes, загруженные изображения в content/images, файл маршрутов в content/settings, логи в content/logs и база данных в content/data.

Плюс один файл конфигурации, config.production.json, который сообщает Ghost его публичный адрес, где лежит база данных, как отправлять почту и на каком адресе и порту слушать.

Третья часть - база данных. Ghost умеет работать с MySQL или SQLite. Собственная документация Ghost рекомендует для продакшена MySQL 8, а SQLite считает лёгким вариантом, но SQLite - это один файл внутри content/data, поэтому небольшое издание с ним очень легко запускать и бэкапить: нет отдельного сервера, который надо подбирать по размеру, защищать и оплачивать. Для блога с одним или несколькими авторами это разумный выбор. Где он перестаёт быть разумным, сказано в FAQ.

В RE:NODE Ghost - одна из линеек приложений в один клик. Сервер устанавливает и собирает Ghost при первом запуске и хранит данные в SQLite на самом сервере, так что покупать базу данных не нужно. Каждый файл, который пишет установщик, виден в файловом менеджере и по SFTP, как на любом другом сервере, а изменения, которые вы вносите в темы и конфигурацию, обновление не перезаписывает.

Какой сервер нужен Ghost#

Собственный минимум Ghost - 1 ГБ памяти. Это честная цифра: процесс Ghost в простое заметно ниже этого уровня, и личный блог с несколькими тысячами посещений в день работает на нём без проблем. Память и процессор нагружают не просмотры страниц - Ghost хорошо кэширует, и большинство страниц обходятся дёшево, - а вот что:

  • Загрузка изображений. Ghost создаёт уменьшенные копии каждого изображения для адаптивной вёрстки. Загрузить подряд двадцать больших фотографий - самое тяжёлое, что может сделать небольшой сервер Ghost.
  • Подписчики и рассылки. Отправка рассылки большому списку, импорт CSV с подписчиками и отрисовка раздела для подписчиков стоят больше, чем отдача постов.
  • Сборка при первом запуске. Установка зависимостей и сборка требуют больше памяти, чем работа. Это происходит один раз.

Диск уходит в основном на изображения. Само приложение занимает несколько сотен мегабайт, текстовые посты крошечные, а фотоблог растёт на объём загрузок плюс уменьшенные копии, которые делает Ghost, так что закладывайте примерно вдвое больше, чем загружаете.

ПланRAM / диск / CPUДля чего
Ghost Starter1 GB / 10 GB / 1 vCPUЛичный блог или небольшая рассылка
Ghost Standard2 GB / 20 GB / 1.5 vCPUРастущее издание с подписчиками
Ghost Advanced4 GB / 30 GB / 2 vCPUПосещаемые сайты и большие списки рассылки
Ghost Pro6 GB / 50 GB / 3 vCPUКрупные издания с тяжёлыми медиа

Это планы Ghost в RE:NODE, от $5 в месяц. Начинайте с малого: переход на тариф выше меняет лимиты на уже существующем сервере, и переустанавливать Ghost не нужно. Если хотите общее понимание того, какой ресурс на самом деле заканчивается первым, статья о лимитах памяти Node применима напрямую, потому что Ghost - такой же процесс Node, как любой другой.

Первый запуск и учётная запись администратора#

На машине, которую вы администрируете сами, Ghost обычно ставят через Ghost-CLI: ghost install на подготовленном Linux-сервере устанавливает зависимости Node.js, базу MySQL, nginx, сертификат и сервис systemd. Это хороший инструмент, но он рассчитывает, что вся машина ваша, поэтому он подходит для VDS, а не для сервера в панели.

На линейке в один клик шагов меньше:

  1. Закажите план. Сервер создаётся, когда проходит оплата, обычно в течение минуты.
  2. Запустите его и следите за консолью. Первый запуск скачивает и собирает Ghost и длится дольше любого следующего. Дождитесь, пока Ghost сообщит, что он работает.
  3. Откройте адрес, показанный в панели, добавив в конце /ghost. Первый заход на /ghost - это экран настройки: название сайта, ваше имя, почта и пароль. Эта учётная запись становится владельцем.
  4. Настройте домен (следующий раздел), прежде чем кого-то приглашать или что-то публиковать, потому что ссылки и письма используют тот адрес, который Ghost считает своим.

Пройдите настройку сразу. Пока владельца нет, его создаёт тот, кто первым откроет /ghost. На свежем сервере адреса ещё никто не знает, но откладывать этот шаг на следующую неделю не стоит.

Дальше идут учётные записи сотрудников: в Ghost есть роли Contributor, Author, Editor и Administrator, и ровно один Owner. Авторов приглашают по почте из настроек сотрудников - а значит, почта должна заработать раньше, и поэтому раздел о почте ниже не является необязательным.

Настройка url и ваш домен#

url - настройка, которая ломает сайты на Ghost чаще любой другой. Из неё Ghost строит каждую ссылку, тег canonical, элемент RSS, запись в sitemap, адрес изображения и ссылку в письме, и на неё же он перенаправляет посетителей. Это должен быть точный публичный адрес вместе со схемой:

config.production.json
{  "url": "https://blog.example.com",  "server": {    "host": "0.0.0.0",    "port": 2368  }}

Те же значения можно передать не через файл, а через переменные окружения. Ghost читает вложенные ключи через двойное подчёркивание, так что server__port задаёт server.port, а mail__transport задаёт mail.transport:

env
url=https://blog.example.comserver__host=0.0.0.0server__port=2368

Переменная окружения побеждает файл. Это стоит помнить, когда правка config.production.json будто бы игнорируется: тот же ключ задаёт что-то ещё. На сервере в панели адрес и порт, которые слушает Ghost, уже настроены установкой под порт, выделенный серверу, поэтому не трогайте server.host и server.port, если не знаете точно, зачем их меняете. Менять нужно url.

В RE:NODE планы приложений включают слот обратного прокси. Добавьте домен в слот прокси, направьте его A-запись на адрес, показанный в панели, и сертификат будет выпущен и продлён автоматически. Затем задайте url как https:// плюс этот домен и перезапустите Ghost. Порядок важен: если указать домен в url раньше, чем готовы DNS и сертификат, Ghost будет перенаправлять каждого посетителя, включая вас, на адрес, который ещё не отвечает.

HTTPS 443выделенный порттранзакционныемассовая отправкаЧитательhttps://blog.example.comСлот проксисертификат HTTPSGhostодин процесс Node.jsSQLitecontent/dataSMTP-сервервход и приглашенияMailgunрассылки
Запрос к блогу на Ghost и письма, которые он отправляет

Сторона домена - A-записи, сколько идёт DNS и что нужно сертификату - разобрана в статье о домене и его сертификате, а статья о том, что делает обратный прокси, объясняет, почему сам Ghost здесь никогда не занимается HTTPS. Одно следствие прокси: Ghost видит, что все посетители приходят от прокси, а реальный адрес клиента передаётся в заголовке X-Forwarded-For.

Если нужно, чтобы работали и example.com, и www.example.com, выберите один из них для url, а другой перенаправьте на него: Ghost отвечает на одном каноническом адресе. Какой выбрать, разобрано в статье о www и голом домене и редиректах.

Почта: транзакционные письма и рассылки#

Ghost отправляет два разных вида писем двумя разными путями, и путаница между ними - самая частая причина, по которой новый сайт кажется наполовину сломанным.

Транзакционные письма - это одно сообщение одному человеку: приглашения сотрудникам, сброс пароля и, самое важное, ссылки для входа, которые получают подписчики. У подписчиков Ghost нет паролей: они входят по ссылке из письма. Если транзакционная почта не работает, никто не может ни зарегистрироваться, ни войти, а со стороны читателя портал просто молча не срабатывает. Эти письма уходят через блок mail в конфигурации, обычно по SMTP:

config.production.json
{  "mail": {    "from": "'Example Blog' <noreply@example.com>",    "transport": "SMTP",    "options": {      "host": "smtp.example.com",      "port": 465,      "secure": true,      "auth": {        "user": "noreply@example.com",        "pass": "your-smtp-password"      }    }  }}
КлючТипичное значениеЧто делает
mail.transportSMTPОтправка через SMTP-сервер
mail.fromваш адресОтправитель, которого видят читатели
mail.options.hostхост провайдераSMTP-сервер для подключения
mail.options.port465 или 587465 с secure: true, 587 без него
mail.options.authлогин и парольВход на SMTP

Порт 465 использует TLS с первого байта и требует secure: true; порт 587 начинает без шифрования и потом переключается, и для него secure оставляют false. Если перепутать, получится тайм-аут или ошибка TLS вместо понятного сообщения. Адрес from должен быть таким, от имени которого SMTP-сервер имеет право отправлять, на домене, чьи записи SPF и DKIM включают этот сервер, иначе письма попадут в спам - записи разобраны в статье о том, почему письма уходят в спам.

Откуда взять SMTP-сервер, решаете вы: провайдер транзакционной почты, исходящий сервер существующего ящика или собственный. RE:NODE продаёт линейку Mail Server на Stalwart, которая может быть SMTP-сервером для Ghost - об этом статья о настройке почтового сервера Stalwart, а варианты сравниваются в статье о транзакционной почте из приложения. Ghost нужно лишь достучаться до порта отправки, например 587 или 465; порт 25 ему не нужен никогда.

Рассылки - это массовый путь: один пост уходит письмом каждому подписчику. Рассылки Ghost по SMTP не отправляет. Массовая отправка идёт через Mailgun, который настраивается в админке Ghost, в настройках почты для рассылок, с доменом Mailgun и ключом API, а не в config.production.json. Без него Ghost всё равно публикует посты и даёт подписчикам регистрироваться, но возможности отправить пост письмом не будет. Блог без рассылки может вообще обойтись без Mailgun; блог, ради рассылки и существующий, - нет.

Темы и доработка внешнего вида#

Тема Ghost - это папка с шаблонами Handlebars (файлы .hbs), CSS, JavaScript и файлом package.json, который описывает тему и её настройки. Последние версии идут с темой по умолчанию, а официальные темы и темы из маркетплейса - это бесплатные или платные zip-архивы.

Установить тему можно двумя способами:

  • Загрузить zip в админке Ghost, в настройках оформления. Ghost проверяет тему, показывает ошибки и предупреждения и даёт её активировать. Это обычный путь.
  • Скопировать папку в `content/themes` по SFTP или через файловый менеджер, затем перезапустить Ghost, чтобы он заметил новую тему, и активировать её в админке. Удобно для темы, которую вы разрабатываете, или для слишком большой для загрузки.

Правьте тему как копию, никогда на месте. Переименуйте папку (и name в её package.json), чтобы обновление темы от автора не заменило ваши правки молча, и храните изменённую тему в Git или хотя бы как zip на своём компьютере. Данные для подключения, чтобы работать с файлами напрямую, есть в статье о SFTP и файловом менеджере.

Ещё два файла и механизма внутри content стоит знать:

  • content/settings/routes.yaml управляет структурой URL: собственные коллекции, статическая главная страница, таксономии. Его можно скачать и загрузить из админки. Ошибочный файл маршрутов может заставить целые разделы сайта отдавать 404, поэтому сохраняйте предыдущую версию перед изменением.
  • Code injection в админке добавляет фрагменты в head и footer сайта - аналитику, шрифт, небольшую правку стилей - не трогая тему. Предпочитайте его для мелких изменений: они переживают смену темы.

Крупные изменения темы проще проверять не на рабочем сайте. Второй небольшой сервер Ghost для тестов стоит недорого, об этом статья о тестовом сервере рядом с продакшеном.

Бэкапы, которые включают всё#

Сайт на Ghost - это три вещи: база данных, папка content и config.production.json. Бэкап, в котором нет хотя бы одной из них, неполный.

С SQLite база данных лежит внутри content/data, поэтому полный бэкап - это копия content плюс файл конфигурации. Подвох в согласованности. Если копировать файл SQLite, пока Ghost в него пишет, можно получить копию, которая не откроется. Безопасные варианты в порядке предпочтения:

  1. Остановить Ghost, скопировать файлы, снова запустить. Несколько секунд простоя и гарантированно чистая копия.
  2. Использовать собственную команду резервного копирования SQLite, если доступна утилита sqlite3: она делает согласованную копию живой базы.
  3. Снимать копию в тихий час и хранить несколько, чтобы одна неудачная копия не оказалась единственной.
bash
$ sqlite3 content/data/ghost.db ".backup 'ghost-backup.db'"$ tar czf ghost-content-$(date +%F).tar.gz content config.production.json

Имя файла ghost.db обычное, но прежде чем что-то автоматизировать, проверьте, что на самом деле лежит в content/data.

В настройках Ghost есть и экспорт, который скачивает посты, страницы, теги и настройки одним файлом JSON, а подписчиков можно экспортировать в CSV. Это полезно - экспорт JSON служит для переноса контента между установками Ghost разных версий, - но сам по себе бэкапом не является. Экспорт JSON не включает изображения и темы, а восстановление целого сайта из него медленнее и с большими потерями, чем восстановление файлов.

В RE:NODE у каждого плана Ghost есть слоты для бэкапов: от одного на Starter до четырёх на Pro. Бэкап можно сделать вручную или по расписанию, он хранится вне машины, которую защищает, его можно скачать и восстановить одной кнопкой. Вкладка Schedules может остановить сервер, сделать бэкап и снова запустить его одной упорядоченной задачей - это та самая схема «остановить, скопировать, запустить», только без человека, который не спит ради неё. Заблокируйте бэкап, сделанный перед обновлением, чтобы ротация его не удалила. Удаление сервера удаляет и его бэкапы, заблокированные тоже, поэтому держите скачанную копию всего, что жалко потерять. Почему иногда стоит восстанавливать бэкап на пробу, объясняет статья о бэкапах, которые действительно восстанавливаются, а шаги в панели - в руководстве по бэкапам.

Как безопасно обновлять Ghost#

Ghost выходит часто. Минорные обновления обычно проходят безболезненно; мажорные версии меняют то, на что опираются темы и интеграции, и в заметках к выпуску сказано, что именно. На машине, которой вы управляете через Ghost-CLI, ghost update скачивает новую версию, выполняет миграции базы данных и перезапускает Ghost. Как версия обновляется на сервере в один клик, зависит от его установки; смотрите вывод консоли при запуске и спросите поддержку перед мажорным обновлением, если не уверены, что произойдёт.

Чем бы ни выполнялось обновление, порядок один и тот же:

  1. Прочитайте заметки к выпуску для каждой мажорной версии между вашей и целевой.
  2. Проверьте тему на совместимость с новой версией. Валидатор тем Ghost (тот же, что срабатывает при загрузке) сообщает о шаблонах и хелперах, которые больше не поддерживаются. Тема, работавшая на старой мажорной версии, может отказаться активироваться на новой.
  3. Сделайте бэкап при остановленном Ghost и заблокируйте его.
  4. Обновитесь и следите за логом, пока Ghost выполняет миграции базы данных. Не останавливайте сервер посреди миграции.
  5. Пройдитесь по сайту: главная, пост, страница тега, портал подписчиков, редактор в админке. Отправьте себе тестовое письмо.

Если обновление пошло не так, восстановление бэкапа возвращает файлы и базу данных ровно в состояние до него - поэтому бэкап делают до обновления, а не после первой ошибки. Общие привычки для этого описаны в статье о деплоях без простоя на небольшом сервере, хотя у одиночного процесса Ghost короткий перезапуск будет в любом случае.

Решение проблем#

Сайт уходит в бесконечный редирект или всё время отправляет на неправильный адрес. url не совпадает с тем, как открывают сайт. Проверьте схему (https или http), имя хоста (с www или без) и что в конце не добавлен лишний путь. За обратным прокси Ghost также полагается на то, что прокси сообщает ему через заголовок X-Forwarded-Proto, что исходный запрос был по HTTPS; если заголовка нет, url с https вызывает бесконечный редирект.

Подписчики не получают ссылку для входа. Транзакционная почта не настроена или не работает. Ищите ошибку SMTP в логе Ghost. Частые причины: неправильное сочетание порта и secure, логин SMTP, которому не разрешено отправлять от адреса from, или письмо доходит, но попадает в спам из-за отсутствия SPF или DKIM.

Нет возможности отправить пост письмом. Для рассылок нужен Mailgun, настроенный в админке. Настройки SMTP массовую отправку не включают.

Изображения или ссылки ведут на старый адрес после смены домена. Поменяйте url, перезапустите, и сгенерированные ссылки последуют за ним. Изображения, вставленные в посты до смены, хранятся с путями, которые Ghost переписывает из url, но всё, что жёстко прописано в теме или в code injection, придётся исправить вручную.

Загрузка темы падает с ошибками. Валидатор нашёл шаблоны или хелперы, которые запущенная версия Ghost не поддерживает. Прочитайте список ошибок: в них указан файл. Исправьте их в своей копии темы или возьмите версию темы, сделанную под ваш выпуск Ghost.

Ghost перезапускается при больших загрузках или импорте. Процесс упёрся в лимит памяти. Загружайте меньше изображений за раз, уменьшайте фотографии перед загрузкой или перейдите на тариф выше. Бесконечный цикл перезапусков разобран в статье о том, почему сервер постоянно перезапускается - диагностика одинакова для любого процесса.

Правка `config.production.json` ничего не меняет. Либо Ghost не перезапустили (он читает файл только при запуске), либо тот же ключ задаёт переменная окружения, и она побеждает.

FAQ#

Достаточно ли SQLite для блога на Ghost?

Для личного блога или небольшого издания - да: она быстрая, не требует отдельного сервера и бэкапится как файл. Собственные рекомендации Ghost для продакшена отдают предпочтение MySQL 8, и сайт с большим числом авторов, очень большим списком подписчиков или интенсивной параллельной записью - это тот случай, когда MySQL начинает окупаться. Переезд позже - это экспорт контента и импорт в новую установку, настроенную на MySQL.

Нужен ли Mailgun, чтобы запустить Ghost?

Только для рассылок. Ссылки для входа, приглашения сотрудникам и сброс пароля идут через обычный SMTP. Блог, который никогда не рассылает посты подписчикам, может работать без Mailgun сколько угодно.

Можно ли использовать свой домен с бесплатным HTTPS?

Да. Добавьте домен в слот прокси, направьте A-запись на адрес сервера, дождитесь сертификата, затем задайте в url адрес с https и перезапустите Ghost. Сертификат продлевается автоматически.

Сколько памяти нужно блогу на Ghost?

Около 1 ГБ для личного блога - это собственный заявленный минимум Ghost. Больше помогает при загрузке крупных изображений, больших импортах подписчиков и отправке рассылок. Одни только просмотры страниц редко оправдывают план крупнее.

Перезапишет ли обновление мои правки темы?

Обновление Ghost заменяет приложение, а не папку content, так что ваши темы и изображения остаются. Риск в другом: обновление темы от её автора может перезаписать ваши правки, поэтому изменённую тему и переименовывают. В любом случае делайте бэкап перед каждым обновлением.

Можно ли перенести существующий сайт на Ghost на новый сервер?

Да. Экспортируйте контент в JSON на старом сайте, скопируйте папку content/images и свою тему, затем импортируйте JSON в новую установку и загрузите тему. Подписчики экспортируются и импортируются через CSV. Копирование всей папки content тоже работает, если обе установки работают на одной версии Ghost.

Это было полезно?