Гид по технологиям

Установка Ghost CMS на Ubuntu 20.04 с Docker, Nginx и Let's Encrypt

• 7 min read • DevOps • Обновлено 21 Nov 2025
Установка Ghost на Ubuntu 20.04 с Docker и SSL
Установка Ghost на Ubuntu 20.04 с Docker и SSL

Обложка: логотип Ghost и сервер

Что вы получите

  • Рабочий блог на Ghost, доступный по HTTPS.
  • Изоляцию сервисов через Docker: Ghost, MariaDB и Nginx.
  • Автоматическое продление SSL с Certbot.
  • Рекомендации по бэкапам, обновлениям и безопасности.

Ключевые термины

  • Docker: платформа для контейнеризации приложений.
  • Docker Compose: инструмент для запуска многоконтейнерных приложений.
  • Certbot: утилита для получения сертификатов Let’s Encrypt.
  • Nginx: веб-сервер и обратный прокси.

Первые шаги и требования

  • Сервер на Ubuntu 20.04 с публичным доменом (например, example.com).
  • Нераутовый пользователь с sudo.
  • Доступ к порту 80/443 и SSH.

Важно: заранее укажите реальный домен вместо example.com в конфигурациях и командах.

Применение в практике

Документ рассчитан на системных администраторов и devops-инженеров. Для контент-менеджеров достаточно раздела “Завершение настройки”.


Преимущества выбранного подхода

  • Простота: конфигурация собирается из нескольких файлов и команд.
  • Повторяемость: можно разворачивать на другом сервере без изменений кода Ghost.
  • Безопасность: TLS от Let’s Encrypt и отделение базы данных в отдельном контейнере.

Важно

Перед изменением продакшн‑сервера выполните резервные копии каталога /home//ghost и /etc/letsencrypt.

Шаг 0 Проверка обновлений системы

Прежде чем начинать, обновите пакеты:

$ sudo apt update 
$ sudo apt upgrade

Это гарантирует совместимость пакетов, таких как snapd и curl.

Шаг 1 Конфигурация брандмауэра UFW

Ubuntu по умолчанию содержит ufw. Разрешите SSH до включения брандмауэра, иначе вы потеряете подключение.

Проверка статуса:

$ sudo ufw status

Если статус inactive, выполните:

$ sudo ufw allow OpenSSH
$ sudo ufw allow 80
$ sudo ufw allow 443
$ sudo ufw enable

Проверка после включения:

$ sudo ufw status

Ожидаемый вывод содержит правила для OpenSSH, 80 и 443.

Шаг 2 Установка Certbot и получение SSL

Мы используем snapd для установки актуальной версии certbot.

Обновите snapd и установите certbot:

$ sudo snap install core 
$ sudo snap refresh core
$ sudo apt remove certbot
$ sudo snap install --classic certbot
$ sudo ln -s /snap/bin/certbot /usr/bin/certbot

Получение сертификата в режиме standalone (порт 80 должен быть доступен):

$ sudo certbot certonly --standalone -d example.com

Сертификат будет лежать в /etc/letsencrypt/live/example.com.

Примечание: если на момент получения сертификата вы уже используете Nginx, можно получить сертификат через вебрут или через плагин nginx. В нашем сценарии мы преднамеренно получаем сертификат standalone, чтобы заполнить директорию before-запуска nginx-контейнера.

Шаг 3 Установка Docker и Docker Compose

Сначала удаляем старые варианты и добавляем официальный репозиторий Docker.

$ sudo apt remove docker docker-engine docker.io containerd runc
$ sudo apt install apt-transport-https ca-certificates curl gnupg lsb-release
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
$ echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
$ sudo apt update
$ sudo apt install docker-ce docker-ce-cli containerd.io

Проверка контейнера hello-world:

$ sudo docker run hello-world

Добавим пользователя в группу docker, чтобы не использовать sudo каждый раз:

$ sudo usermod -aG docker ${USER}
$ su - ${USER}

Установка docker-compose (в примере версия 1.28.6, можно заменить на актуальную):

sudo curl -L "https://github.com/docker/compose/releases/download/1.28.6/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose
$ docker-compose --version

Если у вас современный Docker, можно использовать плагин docker compose (v2). Однако в этом руководстве мы используем классический бинарник docker-compose, совместимый с yaml v3.


Шаг 4 Установка Ghost через Docker Compose

Архитектура: Ghost (порт 2368 внутри сети), MariaDB и Nginx как фронтенд.

Создайте рабочую папку и файл docker-compose.yml:

$ mkdir ghost && cd ghost
$ nano docker-compose.yml

Вставьте следующий файл. Важно: замените example.com, your_mysql_root_password, ghostdbpass и на ваши значения.

version: '3.3'
services:

  ghost:
    image: ghost:latest
    restart: always
    depends_on:
      - db
    environment:
      url: https://example.com
      database__client: mysql
      database__connection__host: db
      database__connection__user: ghost
      database__connection__password: ghostdbpass
      database__connection__database: ghostdb
      mail__transport: SMTP
      mail__options__host: {Your Mail Service host}
      mail__options__port: {Your Mail Service port}
      mail__options__secureConnection: {true/false}
      mail__options__service: {Your Mail Service}
      mail__options__auth__user: {Your User Name}
      mail__options__auth__pass: {Your Password}
    volumes:
      - /home//ghost/content:/var/lib/ghost/content

  db:
    image: mariadb:latest
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: your_mysql_root_password
      MYSQL_USER: ghost
      MYSQL_PASSWORD: ghostdbpass
      MYSQL_DATABASE: ghostdb
    volumes:
      - /home//ghost/mysql:/var/lib/mysql

  nginx:
    build:
      context: ./nginx
      dockerfile: Dockerfile
    restart: always
    depends_on:
      - ghost
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /etc/letsencrypt/:/etc/letsencrypt/
      - /usr/share/nginx/html:/usr/share/nginx/html

Пояснения по томам:

  • /home//ghost/content — контент Ghost (темы, изображения, экспорт и т. д.).
  • /home//ghost/mysql — данные MariaDB.
  • /etc/letsencrypt — доступ Nginx к сертификатам.
  • /usr/share/nginx/html — вебрут для валидации ACME.

Создайте локальные каталоги и права доступа:

$ cd ~/ghost
$ mkdir content
$ mkdir mysql
$ sudo mkdir -p /usr/share/nginx/html
$ sudo chown -R ${USER}:${USER} content mysql

Создание образа Nginx

Создайте директорию nginx и Dockerfile:

$ mkdir nginx
$ touch nginx/Dockerfile

Dockerfile:

FROM nginx:latest
RUN rm /etc/nginx/conf.d/default.conf
COPY ghost.conf /etc/nginx/conf.d

Создайте файл конфигурации nginx/ghost.conf. Везде замените example.com на ваш домен.

server {
  listen 80;
  listen [::]:80;
  server_name example.com;
  # Useful for Let's Encrypt
  location /.well-known/acme-challenge/ { root /usr/share/nginx/html; allow all; }
  location / { return 301 https://$server_name$request_uri; }
}

server {
  listen 443 ssl http2;
  listen [::]:443 ssl http2;
  server_name example.com;
    
  access_log /var/log/nginx/ghost.access.log;
  error_log /var/log/nginx/ghost.error.log;
  client_max_body_size 20m;

  ssl_protocols TLSv1.2 TLSv1.3;
  ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
  ssl_prefer_server_ciphers on;
  ssl_session_timeout 1d;
  ssl_session_cache shared:SSL:10m;

  ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

  location / {
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-Proto https;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass http://ghost:2368;
  }
}

Обратите внимание: в конфигурации proxy_set_header и proxy_pass используются переменные Nginx. Они должны оставаться без изменений.

Шаг 5 Запуск сервисов

Запустите docker-compose в фоновом режиме:

$ docker-compose up -d

Проверьте статус контейнеров:

$ docker-compose ps

Если сайт не открывается сразу, посмотрите логи:

$ docker-compose logs -f

Чтобы временно запустить в прикреплённом режиме (на экран) для отладки:

$ docker-compose up

Для остановки в фоне:

$ docker-compose down

Главная страница Ghost

Шаг 6 Завершение настройки через веб-интерфейс

Откройте браузер и перейдите на https://example.com/ghost. Вас встретит форма создания администратора и названия блога.

Страница настройки Ghost

Заполните данные и завершите первичную настройку. После этого вы попадёте в админ-панель.

Данные для настройки

Панель администратора Ghost

Совет: сначала создайте резервную копию темы и экспорт контента перед внесением массовых изменений.


Шаг 7 Обновление Ghost

Чтобы обновить образы, выполните:

$ docker-compose down
$ docker-compose pull && docker-compose up -d

Рекомендация: тестируйте обновления в staging среде перед продакшном. В критичных проектах фиксируйте тег образа Ghost вместо latest.

Шаг 8 Автоматическое продление сертификатов

Let’s Encrypt действует 90 дней. Добавьте cron для автоматического продления и перезагрузки Nginx внутри контейнера.

Откройте crontab для root:

$ sudo crontab -e

Добавьте строку (ежедневный запуск в 23:00):

0 23 * * *   certbot certonly -n --webroot -w /usr/share/nginx/html -d example.com --deploy-hook='docker exec ghost_nginx_1 nginx -s reload'

Проверьте dry-run:

$ sudo bash -c "certbot certonly -n --webroot --dry-run -w /usr/share/nginx/html -d example.com --deploy-hook='docker exec ghost_nginx_1 nginx -s reload'"

Если контейнер nginx имеет другое имя, скорректируйте deploy-hook.


Критерии приёмки

  1. Сайт доступен по адресу https://example.com и возвращает 200.
  2. На странице /ghost доступна административная форма создания пользователя.
  3. Сертификат TLS корректен и валиден (проверить через openssl или браузер).
  4. Команда docker-compose ps показывает все сервисы в статусе Up.
  5. Резервная копия каталога content и mysql создана и восстанавливается локально.

Проверки:

$ curl -I https://example.com
$ docker-compose ps
$ docker exec -it  mysql -uroot -p

Тесты и сценарии приёмки

  • Тест 1: HTTPS соединение и редирект HTTP->HTTPS
  • Тест 2: Почтовая рассылка
    • Ожидаем: отправка письма с формы восстановления работает при корректной SMTP настройке.
  • Тест 3: Резервное восстановление
    • Ожидаем: развёрнутая копия content и mysql позволяет восстановить сайт на другом сервере.

Отладка и распространённые ошибки

  • Контейнер nginx ругается на сертификат: убедитесь, что путь /etc/letsencrypt смонтирован и сертификаты находятся в live/example.com.
  • Ghost не подключается к БД: проверьте одинаковые значения MYSQL_PASSWORD и databaseconnectionpassword.
  • Cron не перезагружает nginx: проверьте имя контейнера через docker ps и скорректируйте deploy-hook.

Логи проверяются командами:

$ docker-compose logs -f nginx
$ docker-compose logs -f ghost
$ docker-compose logs -f db

Если контейнеры завершаются с ошибкой, выполните docker-compose up без -d и смотрите вывод в реальном времени.


Рекомендации по безопасности

  • Ограничьте доступ к SSH через ключи и disablePasswordAuthentication.
  • Используйте UFW для разрешения только нужных портов.
  • Ограничьте права на каталоги content и mysql: 700/600 как нужно.

Примеры команд для жёстких прав:

$ sudo chown -R root:root /etc/letsencrypt
$ sudo chmod -R 700 /home//ghost/mysql
$ sudo chmod -R 750 /home//ghost/content
  • Включите fail2ban для защиты SSH и, при необходимости, панели администратора.
  • Защитите базу данных: не используйте простые пароли и открывайте её только для локальной сети Docker.

Резервные копии и стратегия восстановления

Минимально нужно бэкапить:

  • /home//ghost/content
  • /home//ghost/mysql
  • /etc/letsencrypt

Простой cron-скрипт для бэкапа content:

0 2 * * * tar -czf /backups/ghost_content_$(date +\%F).tar.gz -C /home//ghost content

Для MySQL можно использовать mysqldump внутри контейнера:

docker exec  sh -c 'exec mysqldump --all-databases -uroot -p"$MYSQL_ROOT_PASSWORD"' > /backups/mysql_all_$(date +%F).sql

Роли и чек-листы

Администратор сервера:

  • Настроить UFW и SSH.
  • Установить Docker и snapd.
  • Обеспечить права на каталоги и SSL.

DevOps:

  • Подготовить docker-compose.yml и Nginx конфигурацию.
  • Настроить CI/CD для обновлений образов.
  • Настроить мониторинг и бэкапы.

Контент-редактор:

  • Зарегистрировать администратора Ghost.
  • Настроить тему и загрузить первые посты.

Альтернативные подходы

  • Использовать готовый Ghost CLI и запуск на хосте без Docker.
  • Развернуть Ghost на платформе PaaS (например, DigitalOcean App Platform, Heroku-подобные решения).
  • Использовать managed MySQL/Managed Database вместо контейнера для упрощения бэкапа и отказоустойчивости.

Плюсы Docker: воспроизводимость и изоляция. Минусы: требуется управление контейнерным окружением и бэкапом томов.


Советы по обновлениям и откату

  1. Перед обновлением сделайте полную резервную копию content и mysql.
  2. Остановите контейнеры: docker-compose down.
  3. Выполните docker-compose pull.
  4. Запустите docker-compose up -d и проверьте логи.
  5. При ошибках — откатите образ: docker-compose pull или используйте snapshot тома.

Совместимость и миграции

  • Ghost использует MySQL/MariaDB. При миграции с другой платформы экспортируйте content через Ghost Admin -> Labs -> Export.
  • Для миграции между версиями Ghost проверьте совместимость тем и API.

GDPR и приватность

  • Ghost хранит данные пользователей и подписчиков. Обеспечьте доступ по HTTPS.
  • При сборе адресов e‑mail используйте явное согласие и храните только минимально необходимую информацию.
  • При необходимости реализуйте процедуру удаления данных по запросу.

Краткая инструкция по отладке cron для certbot

  1. Убедитесь, что /usr/share/nginx/html доступен в контейнере nginx и имеет правильные challenge файлы.
  2. Запустите certbot с –dry-run и проверьте вывод.
  3. Проверьте логи /var/log/letsencrypt/.

Примеры команд для повседневного обслуживания

  • Просмотр логов:
$ docker-compose logs -f
  • Перезапуск nginx внутри контейнера:
$ docker exec ghost_nginx_1 nginx -s reload
  • Остановка и удаление контейнеров и сети:
$ docker-compose down --volumes

Decision flow для действий при недоступности сайта

flowchart TD
  A[Сайт недоступен] --> B{Проверить DNS}
  B -- Нет записи --> C[Добавить A/AAAA запись]
  B -- Есть запись --> D{Проверить сертификат}
  D -- Просрочен --> E[Запустить certbot --dry-run]
  D -- Валиден --> F{Проверить docker}
  F -- Контейнеры упали --> G[docker-compose up]
  F -- Контейнеры работают --> H[Проверить логи nginx и ghost]

Факты и контрольные числа

  • Let’s Encrypt: сертификат действителен 90 дней.
  • Рекомендуется запускать продление ежедневно или раз в сутки.
  • Частота бэкапов зависит от активности: минимум раз в сутки для баз данных.

Итог и дальнейшие шаги

  • Вы установили Ghost через Docker с SSL и Nginx.
  • Сделайте резервные копии, настройте мониторинг и протестируйте план восстановления.
  • Рассмотрите использование фиксированных тегов образов в production и staging окружение для проверки обновлений.

Задайте вопросы или оставьте отзыв, если хотите пример CI/CD для автоматического обновления образов или шаблон terraform/ansible для автоматизации развёртывания.

Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

Несколько аккаунтов Skype: Multi Skype Launcher
Программное обеспечение

Несколько аккаунтов Skype: Multi Skype Launcher

Журнал для работы: повысить продуктивность
Productivity

Журнал для работы: повысить продуктивность

Персональные звуки уведомлений на Android
Android.

Персональные звуки уведомлений на Android

Скачивание шоу Hulu для офлайн‑просмотра
Стриминг

Скачивание шоу Hulu для офлайн‑просмотра

Microsoft Start: персонализированная новостная лента
Новости

Microsoft Start: персонализированная новостная лента

Как изменить имя в Epic Games быстро
Гайды

Как изменить имя в Epic Games быстро