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

Что вы получите
- Рабочий блог на 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/
Шаг 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/DockerfileDockerfile:
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
Шаг 6 Завершение настройки через веб-интерфейс
Откройте браузер и перейдите на https://example.com/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.
Критерии приёмки
- Сайт доступен по адресу https://example.com и возвращает 200.
- На странице /ghost доступна административная форма создания пользователя.
- Сертификат TLS корректен и валиден (проверить через openssl или браузер).
- Команда docker-compose ps показывает все сервисы в статусе Up.
- Резервная копия каталога content и mysql создана и восстанавливается локально.
Проверки:
$ curl -I https://example.com
$ docker-compose ps
$ docker exec -it mysql -uroot -p Тесты и сценарии приёмки
- Тест 1: HTTPS соединение и редирект HTTP->HTTPS
- Ожидаем: при заходе на http://example.com браузер перенаправляется на https://example.com.
- Тест 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: воспроизводимость и изоляция. Минусы: требуется управление контейнерным окружением и бэкапом томов.
Советы по обновлениям и откату
- Перед обновлением сделайте полную резервную копию content и mysql.
- Остановите контейнеры: docker-compose down.
- Выполните docker-compose pull.
- Запустите docker-compose up -d и проверьте логи.
- При ошибках — откатите образ: docker-compose pull
или используйте snapshot тома.
Совместимость и миграции
- Ghost использует MySQL/MariaDB. При миграции с другой платформы экспортируйте content через Ghost Admin -> Labs -> Export.
- Для миграции между версиями Ghost проверьте совместимость тем и API.
GDPR и приватность
- Ghost хранит данные пользователей и подписчиков. Обеспечьте доступ по HTTPS.
- При сборе адресов e‑mail используйте явное согласие и храните только минимально необходимую информацию.
- При необходимости реализуйте процедуру удаления данных по запросу.
Краткая инструкция по отладке cron для certbot
- Убедитесь, что /usr/share/nginx/html доступен в контейнере nginx и имеет правильные challenge файлы.
- Запустите certbot с –dry-run и проверьте вывод.
- Проверьте логи /var/log/letsencrypt/.
Примеры команд для повседневного обслуживания
- Просмотр логов:
$ docker-compose logs -f- Перезапуск nginx внутри контейнера:
$ docker exec ghost_nginx_1 nginx -s reload- Остановка и удаление контейнеров и сети:
$ docker-compose down --volumesDecision 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 для автоматизации развёртывания.
Похожие материалы
Несколько аккаунтов Skype: Multi Skype Launcher
Журнал для работы: повысить продуктивность
Персональные звуки уведомлений на Android
Скачивание шоу Hulu для офлайн‑просмотра
Microsoft Start: персонализированная новостная лента