Skip to content
Опубликовано: 2015-08-02
Теги: nodejs

Переезд блога на движок Ghost

Больше года мой блог работал на самописаном движке Mojo::Twist, который был форкнут из движка Twist (он ранее обслуживал мой блог). Свой движок я как-то бурно начал, но вскоре кончилось время и переписать админку до вменяемого состояния не осталось ни времени, ни желания. Пару недель назад задумался перевести блог на Ghost.

Я вот тут задумываюсь перевести свой блог на #ghost, вместо самописного движка.

— Angry Unicorn (@_sattellite) 17 июля 2015

Для этого мне необходимо было сделать структуру ссылок на нём крайне похожей на старый движок, во-первых, чтобы поисковики вели куда надо, а не на страницу 404 и, во-вторых, чтобы не потерять комментарии в Disqus. А по ходу дела я ещё и модифицировал одну из тем оформления для этого движка.

Установка на FreeBSD

Первым делом пришлось понять как на FreeBSD запускать продукт написанный на NodeJS. Была куча сомнений, но, как ни странно, это совсем не вызвало проблем. Установка nodejs и npm на FreBSD проста и хорошо описана в документации:

cd /usr/ports/www/node
make install clean
cd /usr/ports/www/npm
make install clean
cd /tmp
fetch https://github.com/TryGhost/Ghost/archive/<X.Y.Z>.tar.gz
mkdir /usr/local/www/ghost
tar xzf master.tar.gz --strip-components=1 -C /usr/local/www/ghost
rm master.tar.gz
cd /usr/local/www/ghost
CXX=c++ npm install sqlite3 --sqlite=/usr/local
npm install --production

Далее правится конфигурация config.js и запускается блог npm start --production. Вроде всё работает.

Автоматизация запуска на FreeBSD

Для автоматизации запуска есть удобная утилита forever.

npm install -g forever

А как с её помощью создать rc-скрипт хорошо описано в статье на Хабре.

#!/bin/sh

# PROVIDE: blog
# REQUIRE: NETWORKING SERVERS DAEMON
# BEFORE:  LOGIN
# KEYWORD: shutdown

. /etc/rc.subr

name="blog"
forever="/usr/local/bin/node /usr/local/bin/forever"
workdir="/usr/local/www/ghost"
script="index.js"

rcvar=`set_rcvar`

start_cmd="start"
stop_cmd="stop"
restart_cmd="restart"

load_rc_config $name
eval "${rcvar}=\${${rcvar}:-'NO'}"

start()
{
  USER=root
  PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/root/bin
  PWD=/root
  HOME=/root
  export NODE_ENV=production
  ${forever} start -a -l /var/log/forever.log -o /dev/null -e ${workdir}/node_err.log --workingDir ${workdir} ${workdir}/${script}
}

stop()
{
  ${forever} stop ${workdir}/${script}
}

restart()
{
  ${forever} restart ${workdir}/${script}
}

run_rc_command "$1"

Не забыть в /etc/rc.conf добавить строку

blog_enable="YES"
Конфигурация Nginx

Привожу пример конфига nginx без объяснений:

upstream blog {
	server	127.0.0.1:2368;
}

server {
	listen		80;
	server_name	b.sattellite.me;

	location / {
		rewrite	^(.*)$ https://b.sattellite.me$1 permanent;
	}
}

server {
	listen		443 ssl spdy;
	server_name	b.sattellite.me;

	access_log	/var/log/nginx/$host.access_log main;

	ssl							on;
	ssl_session_cache			shared:SSL:10m;
	ssl_session_timeout			5m;
	ssl_prefer_server_ciphers	on;
	ssl_stapling				on;
	ssl_stapling_verify			on;
	ssl_trusted_certificate		/usr/local/etc/nginx/ssl/ca-certs.pem;
	ssl_certificate				/usr/local/etc/nginx/ssl/ssl.cert;
	ssl_certificate_key			/usr/local/etc/nginx/ssl/ssl.key;
	ssl_dhparam					/usr/local/etc/nginx/ssl/dhparam.pem;
	ssl_protocols				TLSv1.2 TLSv1.1 TLSv1;
	ssl_ciphers					'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';

	proxy_set_header	X-Real-IP $remote_addr;
	proxy_set_header	X-Forwarded-For $proxy_add_x_forwarded_for;
	proxy_set_header	X-Forwarded-Proto $scheme;
	proxy_set_header	Host $http_host;

	location ~ ^/(?:ghost) {
		expires		0;
		add_header	Cache-Control "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0";
		proxy_pass	http://blog;
	}

	location ~ ^/(?:p/) {
		expires		0;
		add_header	Cache-Control "no-cache, private, no-store, must-revalidate, max-stale=0, post-check=0, pre-check=0";
		proxy_pass	http://blog;
	}

	location / {
		proxy_ignore_headers	"Set-Cookie";
		proxy_hide_header		"Set-Cookie";
		proxy_ignore_headers	"Cache-Control";
		proxy_hide_header		"Cache-Control";
		proxy_hide_header		"Etag";
		expires					30m;
		proxy_pass				http://blog;
	}

	location ~* \.(?:ico|css|js|gif|jpe?g|png|ttf|woff2?)$ {
		access_log	off;
		expires		30d;
		add_header	Pragma public;
		add_header	Cache-Control "public, mustrevalidate, proxy-revalidate";
		proxy_pass	http://blog;
	}

	location = /robots.txt {
		access_log		off;
		log_not_found	off;
	}

	location = /favicon.ico {
		access_log		off;
		log_not_found	off;
	}

	# Для совместимости со старым движком
	location /article {
		rewrite	^/article/(.*)$ $scheme://$host/$1 permanent;
	}

	location /rss.rss {
		rewrite	^(?:.*)$ $scheme://$host/rss/ permanent;
	}
}
Замена ссылок под необходимый формат

Мне необходимо было, чтобы ссылки на статьи были в формате /year/month/slug и теги были по ссылке /tags. С помощью google нашёл достаточно информации, но в концентрированном виде оставлю её тут.

Для замены формата ссылок статей необходимо в настройках движка на главной странице включить Include the date in your post URLs. После из корневой директории подключиться к SQLite базе и поправить одну опцию:

sqlite3 ./content/data/ghost.db
SQLite version 3.8.10.2 2015-05-20 18:17:19
Enter ".help" for usage hints.
sqlite> update settings set value = '/:year/:month/:slug/' where key = 'permalinks';

Для оценки результата перезапустить блог.

Давно уже открыт тред, в котором предлагается внести изменения в движок, которые помогли бы пользователям самостоятельно менять формат ссылок и даже уже внедрён функционал для этого, но это не работает. Я внёс в БД изменения, но они эффекта не возымели.

uuid был сгенерирован утилитой, которая находится внутри сорцов движка

insert into settings(uuid,key,value,type,created_at,created_by,updated_at,updated_by) values('7348788e-b932-4d38-bf06-e4ed28591044', 'routeKeywords', '{"tag":"tags", "author":"author", "page":"page", "preview":"p", "private":"private"}','blog', 1438524432000, 1, 1438524432000, 1);

Так делать не стоит, на данный момент (версия 0.6.4) это совсем бесполезно. Так что исправим исходники. В файле core/server/config/index.js найти функцию-прототип ConfigManager.prototype.set и в ней объект routeKeywords, а в нём уже необходимый путь tag заменить с tag на tags. Можно перезапускать блог и проверять все свои изменения.

Тема оформления

Родная оформление красивое, но оно у всех, а хотелось своего и чуточку удобнее. Была найдена достаточно популярная тема оформления - Magnum. Она не обновляется уже 2 года, а те редкие коммиты, которые моложе этого срока - простое изменение опечаток. Решил тему немного подогнать под ту тему, что была на старом движке. Подробностей не будет, но в ходе процесса были исправлены шрифты, цвета, вид на мобильных устройствах. Тему решил переименовать и назвал Blognum. А на последок нарисована новая картинка с перловым кодом для этого блога. Как всё выглядит можно оценить на этом сайте.