Генератор статических блогов Pelican

Довольно давно я хотел перевести этот блог на самописный движок. Я даже написал несколько на Django и на flask, но не один из них так и не довел до конца ввиду отсутствия времени, и более приоритетных задач. Со временем я, разумется, понял что занятие это совершенно бессмысленное, и решил оставить Wordpress. И все даже было относительно хорошо, и я мирился с его задумчивостью, разного рода глюками и багами, пока после очередного обновления Wordpress страницы не начали генерироваться в среднем по 5 секунд. Я даже не стал разбираться в чем дело. За то временя сколько я использую Wordpress, мне столько раз нужно было что-то поправлять в нем, что я уже сбился со счета, и мне это порядком надоело. В общем, я решил что пора переходить на какую-то другую платформу.

Кроме всего этого, я внезапно осознал, что на арендованом VPS ничего кроме этого блога не осталось, и держать целый виртуальный сервер ради него одного излишне. Поэтому я решил, что переходить буду на генераторы статических блогов.

В отличии от традиционных блог-платформ таких как Wordpress, для работы статических блог-платформ требуется только веб-сервер. Не требуется ни базы данных, ни интерпретатора какого либо языка. Только веб-сервер. Весь сайт генерируется в самодостаточные html файлы прямо на том же компьютере, на котором вы пишите статьи, и затем загружаются на сервер, или облачную платформу.

Вот далеко не полный список преимуществ которые предоставляют статические генераторы блогов:

  • Производительность - быстрее, чем отдача статического контента уже не может быть ничего;
  • Дешевая масштабируемость - за пару минут блог размещается на Amazon S3 и стоить это будет считанные центы. Если ссылка на какую либо запись окажется на хабре, то S3 с легкостью выдержит такую нагрузку и стоить это будет все те же копейки;
  • Легко найти где разместить блог - не обязательно держать отдельный сервер ради блога. Можно разместить на Github pages, Amazon S3 или даже в Dropbox;
  • Безопасность - нет риска взлома блога. Собственно и ломать то нечего. Не нужно следить за обновлениями, за новыми дырами в безопасности популярных блог платформ;

Я совсем недавно закончил переносить блог, и пока свежи воспоминания решил написать эту заметку на случай, если кому-то ещё это будет интересно.

Из статических блог-платформ сейчас наиболее популярная - Jekyll, но его я сразу отмел так как Ruby мне не очень по душе. Я довольно неплохо знаю Python, поэтому начал искать статические блог-платформы на нем, и, в итоге, остановился на Pelican.

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

Вот кратких список основных возможностей pelican:

  • Поддержка плагинов;
  • Подстветка синтаксиса;
  • Поддержка тем;
  • "Из коробки" поддерживает возможность загружать блог используя ftp или ssh, а так же на Amazon S3, Github Pages, Dropbox;
  • Работает на Linux, MacOS и Windows;
  • Поддержка нескольких языков разметки;

Pelican есть в репозиториях почти всех дистрибутивов, но несмотря на это, лучше устанавливать его в virtualenv:

sudo apt-get install python-virtualenv virtualenv

Используя virtualenv, мы обеспечим лучшую переносимость между платформами и дистрибутивами.

Установка

Создадим виртуальное окружения для pelican и установим его:

# Создаем виртуальное окружение
virtualenv pelicanblog
# Переходим в него
cd pelicanblog
# Активируем виртуальное окружение
source bin/activate
# Устанавливаем pelican
pip install pelican

По-умолчанию pelican поддерживает формат reStructured. Если вы хотите использовать другой формат, например, Markdown то необходимо дополнительно установить соответствующих пакет:

pip install Markdown

Для первоначальной настройки у pelican есть скрипт создающий скелет будущего блога - pelican-quickstart. Запустим его в директории, с будущим блогом:

> Where do you want to create your new web site? [.] .
> What will be the title of this web site? Test Pelican blog
> Who will be the author of this web site? username
> What will be the default language of this web site? [en] ru
> Do you want to specify a URL prefix? e.g., http://example.com   (Y/n) y             
> What is your URL prefix? (see above example; no trailing slash) https://example.com
> Do you want to enable article pagination? (Y/n) y
> How many articles per page do you want? [10]
> What is your time zone? [Europe/Paris] Europe/Moscow
> Do you want to generate a Fabfile/Makefile to automate generation and publishing? (Y/n) y
> Do you want an auto-reload & simpleHTTP script to assist with theme and site development? (Y/n) y
> Do you want to upload your website using FTP? (y/N) n
> Do you want to upload your website using SSH? (y/N) n
> Do you want to upload your website using Dropbox? (y/N) n
> Do you want to upload your website using S3? (y/N) y
> What is the name of your S3 bucket? [my_s3_bucket] example.com
> Do you want to upload your website using Rackspace Cloud Files? (y/N) n
> Do you want to upload your website using GitHub Pages? (y/N) n
Done. Your new project is available at /home/username/pelicanblog

После того, как pelican-quickstart закончит, структура директории будет выглядить следующим образом:

.
├── bin
├── content
├── develop_server.sh
├── fabfile.py
├── include
├── lib
├── local
├── Makefile
├── output
├── pelicanconf.py
├── pelicanconf.pyc
└── publishconf.py

Добавляем первую запись

pelican_quickstart уже создал все необходимые файлы и директории. Для статей была создана директория content. Переходим в нее:

cd content

Cоздадим файл с нашей первой записью:

vim first-article.md

И добавим туда:

Title: Hello world!
Date: 2016-04-22 10:40
Author: username
Category: Some_Category
Tags: blogging, test
Slug: hello-world
Status: published

Содержание статьи будет здесь..

ПараметрОписание
TitleНазвание статьи
DateДата публикации
CategoryКатегория статьи
TagsТеги статьи через запятую
SlugURL статьи
Statusстатус статьи. draft - черновик, published - опубликованная

В директории с блогом pelican так же создал Makefile, в котором уже созданы команды облегчающие с ним работу. Сгенерируем с его помощью блог:

╰─➤  make html
pelican /tmp/article/pelicanblog/content -o /tmp/article/pelicanblog/output -s /tmp/article/pelicanblog/pelicanconf.py
Done: Processed 1 article, 0 drafts, 0 pages and 0 hidden pages in 0.18 seconds.

Запустим локальный веб-сервер и посмотрим что получилось:

make serve

Вот так выглядит стандартная тема pelican:

Чтобы посмотреть все доступные команды, нужно написать make:

╰─➤  make
Makefile for a pelican Web site                                           

Usage:                                                                    
   make html                           (re)generate the web site          
   make clean                          remove the generated files         
   make regenerate                     regenerate files upon modification
   make publish                        generate using production settings
   make serve [PORT=8000]              serve site at http://localhost:8000
   make serve-global [SERVER=0.0.0.0]  serve (as root) to :80    
   make devserver [PORT=8000]          start/restart develop_server.sh    
   make stopserver                     stop local server                  
   make ssh_upload                     upload the web site via SSH        
   make rsync_upload                   upload the web site via rsync+ssh  
   make dropbox_upload                 upload the web site via Dropbox    
   make ftp_upload                     upload the web site via FTP        
   make s3_upload                      upload the web site via S3         
   make cf_upload                      upload the web site via Cloud Files
   make github                         upload the web site via gh-pages   

Set the DEBUG variable to 1 to enable debugging, e.g. make DEBUG=1 html   
Set the RELATIVE variable to 1 to enable relative urls

Во время написания статьи или создания темы, можно запустить скрипт, который будет следить за изменениями и при их обнаружении сразу генерировать сайт. Для этого используется команда devserver:

make devserver

Помимо слежения за файлами, так же будет запущен локальный веб-сервер.

Git

Кроме всего прочего, не лишним будет создать git-репозиторий для блога, и все изменения вести в нем. Это позволит не беспокоиться о его сохранности и отпадет необходимость делать периодические резервные копии. Где хранить репозиторий - выбор за вами. Я предпочитаю bitbucket, т.к. у них есть бесплатные приватные репозитории.

Описывать как создать репозиторий и добавить в него ваш новенький блог я не буду. И github и bitbucket при создании нового репозитория расскажут о дальнейших действиях лучше меня. :)

Настройка Pelican

Настройки pelican по-умолчанию в принципе отлично подходят для большинства блогов, но так как я переносил все статьи с Wordpress и хотел сохранить URL-структуру, то мне было необходимо их немного изменить.

Файл конфигурации

В pelican есть два файла конфигурации:

  • pelicanconf.py - в нем хранятся все основные настройки. Используется при локальной разработке темы, и при написании новых статей;
  • publishconf.py - позволяет переопределить какие либо настройки перед публикацией;

Например, для того, чтобы все ссылки работали корректно в локальном окружении, в pelicanconf.py указан SITEURL = 'localhost:8000'. В publishconf.py эта переменная переопределяется на реальный адрес сайта который будет использоваться при его публикации.

Необходимый для работы минимум за нас уже настроил pelican-quickstart, но как я выше написал, URL структура для статей мне была нужна иная:

ARTICLE_URL = '{date:%Y}/{date:%m}/{date:%d}/{slug}/'
ARTICLE_SAVE_AS = '{date:%Y}/{date:%m}/{date:%d}/{slug}/index.html'

С такими настройками, pelican для статей будет генерировать структуру в формате /ГОД/МЕСЯЦ/ДЕНЬ/SLUG-СТАТЬИ/. Этот URL-формат аналогичен тому, который был у меня в Wordpress.

Я так же поменял URL структуру для категорий, тегов, страниц и RSS:

PAGE_URL = '{slug}/'
PAGE_SAVE_AS = '{slug}/index.html'
CATEGORY_URL = 'category/{slug}'
CATEGORY_SAVE_AS = 'category/{slug}/index.html'
CATEGORIES_SAVE_AS = 'categories/index.html'
TAGS_SAVE_AS = 'tags/index.html'
TAG_URL = 'tag/{slug}'
TAG_SAVE_AS = 'tag/{slug}/index.html'
YEAR_ARCHIVE_SAVE_AS = '{date:%Y}/index.html'
MONTH_ARCHIVE_SAVE_AS = '{date:%Y}/{date:%m}/index.html'
DAY_ARCHIVE_SAVE_AS = '{date:%Y}/{date:%m}/{date:%d}/index.html'
AUTHOR_SAVE_AS = ''

Мне не нужны были страницы со списком всех статей определенного автора, поэтому я поменял значение переменной AUTHOR_SAVE_AS на пустое. Pelican не будет генерировать страницы URL для которых в файле конфигурации не указан.

Подробнее про настройки pelican читайте тут.

Плагины

В pelican реализована поддержка плагинов. Их довольно много, и я нашел там все необходимое. Все плагины для pelican расположены в репозитории. Добавим их все к себе:

git submodule add https://github.com/getpelican/pelican-plugins
git submodule update --init

В pelicanconf.py добавим следующее:

PLUGIN_PATH = 'pelican-plugins'
PLUGINS = ['sitemap', 'neighbors', 'related_posts']

В PELICAN_PLUGINS указываем директорию в которой расположены все наши плагины, в списке PLUGINS плагины, которые нам необходимы. Список всех плагинов с их описанием можно посмотреть тут. У каждого плагина есть описание того как его добавить, и как использовать. Для некоторых плагинов так же может понадобиться установить какой-то дополнительный пакет в виртуальное окружение. Например, есть просто жизненно необходимый плагин assets. Он собирает все разрозненные .css и .js файлы в один, и уменьшает их общий объем путем удаления комментариев и пробелов. Для его работы нужен python пакет webassets:

pip install webassets

Рекомендую как минимум добавить следующие дополнения:

  • sitemap - генерирует .xml со списком всех статей и страниц блога. Поисковые системы очень рады если на сайте такой файл присутствует;
  • neighbors - позволяет добавить в статью ссылки на предыдущую, и следующую статьи;
  • related_posts - позволяет добавить в статью список похожих статей;
  • summary - добавляет тег аналогичный вордпрессовскому <!--more-->;

Темы

Для pelican доступно не мало тем в специальном репозитории. Чтобы использовать тему из репозитория нужно:

  • Склонировать репозиторий с нужной темой, или весь репозиторий с темами;
  • В файле pelicanconf.py изменить переменную THEME на директорию с нужной темой;

Большинство из этих тем можно предварительно просмотреть на этом сайте, или на этом.

Например, если вы хотите использовать тему waterpill, нужно:

  • В директории с блогом выполнить git clone https://github.com/getpelican/pelican-themes/tree/master/waterspill;
  • В файле pelicanconf.py изменить переменную THEME на waterspill;

Создание собственной темы для pelican хорошо документировано в официальной документации pelican.

Переносим данные с Wordpress блога

Переносим посты

Так как я мигрировал с Wordpress блога, для меня было важно перенести все записи в новый блог. К счастью, в комплекте с pelican идет утилита pelican-import которая понимает файлы экспорта Wordpress.

Заходим в интерфейс администрирования Wordpress блога. Далее инструменты -> экспорт:

Выбираем "Все содержимое" и нажимаем "Скачать файл экспорта".

Сохраняем файл туда же, где находится ваш блог, и сконвертируем все наши записи в markdown файлы:

pelican-import --wpfile --dir-page \
    --output content -markup markdown \
    site.wordpress.xml

Переносим комментарии

Один из недостатков статических сайтов, это отсутствие возможности сделать обработку комментариев посетителей средствами сервера.

Если вы хотите добавить возможность комментирования на свой блог, то необходимо использовать систему комментирования предоставляему какими либо сторонними сервисами, такими как, например, Disqus. Комментарии хранятся и обрабатываются на серверах этих сервисов, на ваш же сайт необходимо добавить javascript код который будет их загружать.

В своем блоге я использую именно Disqus. Он довольно просто настраивается. Для его использования, необходимо создать аккаунт на сайте disqus, добавить новый сайт в панели администратора, и в переменной DISQUS_SITENAME в файле pelicanconf.py указать shortname сайта из disqus.

Я так же хотел сохранить все комментарии, поэтому экспортировал их в Disqus. Для этого нужно:

  1. Установить дополнение Disqus comment system в Wordpress блог;
  2. Настроить плагин;
  3. Экспортировать все существующие комментарии нажав на кнопку Export Comments;

Экспорт комментариев длится примерно сутки. Во время экспорта может потеряться несколько комментариев. Для меня это было не критично.

Готовимся к публикации блога

Статическому сайту, в отличии от динамического не нужна база данных и интерпретатор, и, соответственно можно обойтись без выделенного сервера или хостинга. Есть множество альтертанивных, и более экономных мест где его можно разместить: Github Pages, Amazon S3, Dropbox, Rackspace.

Для размещения этого сайта я выбрал Amazon S3. У amazon s3 очень приятные цены, и кроме того его довольно просто использовать. Он быстрый, удобный и с большим количеством дата-центров в самых разных уголках планеты.

Настраиваем Amazon S3

Для загрузки сайта на S3 мы будем использовать пакет s3cmd. Его необходимо установить в виртуальное окружение:

pip install s3cmd

И настроить командой s3cmd --configure. В процессе настройки, потребуются ключи для доступа. Их необходимо создать в панели администрирования AWS, в разделе Users.

Затем в интерфейсе S3 создаем два "бакета" для сайта. Название бакетов должны быть аналогичным названию домена на котором сайт будет расположен. Один бакет с www, другой без.

Для бакета с www, включаем переадресацию на бакет без www:

На основном бакете выбираем Enable website hosting, указываем Index document и Error Document:

Так же необходимо дать права на просмотр содержимого бакета всем. Заходим в Permission, выбираем Add Bucket Policy и вставляем следующее:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AddPerm",
            "Effect": "Allow",
            "Principal": {
                "AWS": "*"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::example.com/*"
        }
    ]
}

Не забываем заменять example.com на название своего сайта.

Настройка DNS

Чтобы сайт был доступен не только по адресу выданному amazon для бакета, нужно создать CNAME запись для домена, указывающую на домен выданный amazon. После обновления DNS записи сайт будет доступен по нужному домену. Присвоенный бакету адрес виден в настройках бакетов, в разделе Static Website Hosting:

Я так же хотел чтобы сайт был доступен по https. Для этого есть несколько вариантов:

  • Использовать Amazon Cloudfront с сертификатом выданным Amazon;
  • Перенести домен к clouldflare (не путать с clouldfront!), и использовать их сертификат;

Для себя я выбрал второй вариант т.к. у clouldflare есть множество других приятных и полезных возможностей. Вкратце, необходимо сделать следующее:

  • Зарегистрироваться в cloudflare, добавить нужный домен и пройти все шаги мастера добавления домена. В процессе, cloudflare сам найдет все поддомены, и добавит их;
  • В панеле управления вашего регистратора, изменить DNS сервера для домена, на DNS сервера cloudflare. Они будут отображены после добавления домена, которое выполнялось на предыдущем шаге;
  • В панели управления cloudflare удалить корневой домен, www поддомен и добавить новые CNAME записи указывающие на соответствующие адреса бакетов выданных Amazon;

После обновления информации о DNS зонах, сайт будет загружаться уже с S3. Обычно обновление происходит в течении 24 часов.


Понравилась статья? Поделись с друзьями!




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