Loading...
Navigation
Table of Contents

👻Ghost博客搭建Tech

Aug 19, 2017Jiaxi

0. 服务器环境部署

node.js

先在Ubuntu x64上安装好Node.js,这里参见Digital Ocean官方给的一个在服务器上搭建ghost的教程,虽然不适用于新版的ghost,但是值得参考。

#做好准备工作
curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
sudo apt-get install -y nodejs

nginx

server {
    listen 80;
    server_name example.me; 
    location / {
        proxy_set_header   X-Real-IP $remote_addr;
        proxy_set_header   Host      $http_host;
        proxy_pass         http://127.0.0.1:2368;
    }
}

1. 使用ghost-cli安装ghost dev

安装ghost dev

ghost-cli(Command Line Interface)是官方在1.0版本后引入的一个便捷搭建ghost环境的工具,使用它安装ghost更加方便运行、停止和升级ghost,参考官方doc

ghost分为production和development两种。这里采用dev的模式进行安装,其好处是其用本地的sqlite数据库,而不是mysql。dev模式下会生成配置文件config.development.json,数据文件ghost-dev.db;如果采用prod的方法安装,还需要配置mysql,比较麻烦。

环境是Ubuntu 16.04 x64,首先安装ghost-cli,然后使用ghost-cli安装ghost。

sudo npm install -g ghost-cli@latest --registry=http://registry.npm.taobao.org
sudo mkdir -p /var/www/ghost #递归建立文件夹
sudo chown -R [user]:[user] /var/www/ghost #添加权限
#如sudo chown ubuntu:root /var/www/ghost
cd /var/www/ghost
ghost install local #安装最新版ghost development
ghost install 1.25.5 --local #指定1.25.5版本进行development安装
ghost stop #注意到ghost已经自行启动,先关掉
mv config.development.json config.production.json #参考

以下几点需要注意:

  • 代理: ghost-cli可能下载速度很慢,可以挂淘宝代理加速
  • 权限问题:如果不添加权限,之后可能得sudo ghost start/stop
  • 切换production:由于是dev模式,默认情况下,只存在config.development.json。但如果development.jsonproduction.json同时存在,ghost start时会首选production,检查ghost status时也会显示为status为production;ghost run的作用是可以实时在bash中看输出。但是,在没有production.json的情况下,运行ghost run会报错,需要拷贝一份development.json文件;综上,只需保留一份production.json

恢复content和theme

  1. 登录后台,注册帐户(流浪西,Jiaxi's Website),注意邮箱无需使用jiaxi域名的邮箱
  2. 进入Labs界面,选择Delete all content,然后import content。如果备份的json文件过大 (如>2MB),可先压缩为zip文件,再次进行导入
  3. 恢复content目录内的image和theme目录

如果使用直接覆盖content目录的方法迁移,ghost本身也可以正常工作,但是ghost-algolia会无法更新索引,因为其无法登录ghost内部的帐户,提示NoPermissionError,这点在ghost run时候可以检测出。

ghost-algolia进行bulk indexing (v1版本)

首先清空algolia官网内的index,然后进入v1版本的ghost目录

ghost stop
cd content/apps
git clone https://github.com/jsxzljx/ghost-algolia.git #恢复定制版的ghost-algolia
cd ghost-algolia
npm install #安装对应的包
cd /path/to/ghost
patch -p1 < ./content/apps/ghost-algolia/ghost_algolia_init.patch
ghost run

ghost不产出自适应大小图片

如果没有自适应大小的图片产出,原因是因为ghost node_modules没有安装sharp这个可选包,参见这里

  • sharp是optional node_modules,npm/ghost默认不会安装;
  • 如果首先在个人目录下安装好sharp,再进行ghost update,那么会发现versions/{ver_num}/node_modules目录下有sharp包;
  • 如果先ghost update,然后手动在新的versions/{ver_num}/node_modules里安装sharp,会破坏ghost程序导致无法启动。

所以采用如下方法来解决

npm install -g sharp@0.23.4  #确定下versions/{ver_num}/package.json中依赖的sharp版本,此版本是0.23.4
# 因为需要下载github的内容,所以有可能需要挂载代理
# 如果安装sharp时提示fatal error: vips/vips8: No such file or directory,那么则需要先安装minpass
# npm install -g minipass
# 参见 https://github.com/lovell/sharp/issues/1882
ghost update
# 然后手动check下ghost/versions/{ver_num}/node_modules是否有sharp包

有关npm install相关,参见这里

npm install packageName  #本地安装,安装到项目目录下,不在package.json中写入依赖
npm install packageName -g #全局安装,安装在Node安装目录下的node_modules下,如~/.npm-global
npm install packageName --save #安装到项目目录下,并在package.json文件的dependencies中写入依赖,简写为-S
npm install packageName --save-dev #安装到项目目录下,并在package.json文件的devDependencies中写入依赖,简写为-D

2. 本地评论系统isso

由于国外的Disqus经常无法访问,国内的畅言有广告,所以可以自己搭一个评论系统,isso是一个用python开发的,以sqlite做存储的开源评论系统,主要参考Github的教程

使用源代码安装isso

由于isso的release非常慢,使用pip的方法只能安装非常旧的版本,所以使用源码安装。

sudo pip install python python-dev virtualenv
sudo npm install -g bower requirejs uglify-js jade
wget https://github.com/posativ/isso/archive/0.11.1.zip
unzip 0.11.1.zip
#git clone https://github.com/posativ/isso.git
#这里使用的是release-0.11.1版本,其在我的魔改版js下能够work
cd isso
virtualenv . #在isso目录下安装py2
source ./bin/activate #进入虚拟环境
python setup.py develop #注意不得使用python setup.py install
make init #初始化js文件
make js #生成embed.min.js
deactivate #退出虚拟环境

python setup.py develop的安装方法是在isso目录里build文件,然后链接到python库里,而不是直接生成可执行文件放在库里,适合开发使用,参见这里,所以不能安装完后删掉isso目录。注意不得使用python setup.py install,否则之后会访问不到embed.min.js

server端配置

isso的配置文件有很多,具体参见GitHub的例子。

[general]
dbpath = /var/www/isso/comments.db
host = http://example.me/isso/
notify = smtp
reply-notifications = true

[server]
listen = http://127.0.0.1:1234/

[moderation]
enabled = false

[guard]
enabled = true
ratelimit = 5
reply-to-self = true
require-author = true
require-email = true

[smtp]
username = username@qq.com
password = password
host = smtp.qq.com
port = 465
security = ssl
to = targetname@example.com
from = "Isso Comment Notification"<username@qq.com>
timeout = 30

具体解释如下:

  • host 填一个可以ping得通的网站主页,否则会在isso run时warning. 以本地Django测试为例,host地址则为Django的127.0.0.1:8000
  • notify[smtp] 使用qq邮箱作为bot进行提醒(网易邮箱会报垃圾游戏,无法发送),如果不需要,删除notify[smtp]的信息即可
  • reply-notifications 给留言进行留言时可以收到Isso Comment Notification的邮件提醒
  • listen isso监听的端口,不同于host
  • moderation = false 留言不需要审核就可以展示出来
  • [guard] 反垃圾邮件机制,reply-to-self = true可以使得debug时候能自我回复,require-authorrequire-email设置为true时,需要在client端同样配置为true
  • 与官网教程不同,不要使用跨域名,如comment.example.me(和example.me是两个域名),否则会发生最后无法提交评论的情况

此时可以运行isso,然后查看embed.min.js是否存在。

/var/www/isso/bin/isso -c /var/www/isso/isso.conf run
curl http://127.0.0.1:1234/js/embed.min.js

nginx转发

与官网教程不同,为了避免跨域名,这里使用http://example.me/isso子目录,所以nginx的配置如下。注意,与官网教程不同,第一行的listen 80一定要有,否则会出现nginx无法转发成功的情况。此外,不妨把ghost nginx配置和isso nginx配置放在一个文件里。

server {
    listen 80;
    listen [::]:80;
    server_name example.me;
    location /isso {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Script-Name /isso;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_pass http://localhost:8090;
    }
}

上述配置完成,可以通过http://example.me/isso/js/embed.min.js来测试,注意如果有CDN,先刷新预取一下。

client端配置

在网页中添加如下内容(最简版本),注意这里的data-isso要和之前的host,nginx里的转发都一致. 全部版本参考GitHub

<section id="isso-thread"></section>
<script data-isso="http://example.me/isso"
    data-isso-css="false"
    data-isso-lang="en"
    data-isso-reply-to-self="true"
    data-isso-require-author="true"
    data-isso-require-email="true"
    data-isso-max-comments-top="10"
    data-isso-max-comments-nested="5"
    data-isso-reveal-on-click="5"
    data-isso-avatar="true"
    data-isso-reply-notifications="true"
    data-isso-avatar-bg="#F2F3F5"
    data-isso-avatar-fg="#9abf88 #5698c4 #e279a3 #9163b6 ..."
    data-isso-vote="false"
    src="http://example.me/isso/js/embed.min.js"></script>

这里的data-isso-reply-to-self-to-authorto-email要和server端对应起来。

使用nohub挂载isso

nohup your_command > my_nohup.log 2>&1 &
#将日志输出在my_nohup.log文件中,并将stderr重定向至stdout

使用systemd启动isso

systemd即为system daemon,是linux下的一种init软件.首先编辑/lib/systemd/system/isso.service文件

[Unit]
Description=lightweight Disqus alternative

[Service]
User=jiaxi
ExecStart=/home/USER/isso-0.11.1/bin/isso -c /home/USER/isso-0.11.1/isso.conf run

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload #每次修改isso.service后都需要重载
sudo systemctl restart isso.service
sudo systemctl status isso.service

使用supervisor启动isso (已废弃)

supervisor是用py2写的一个进程管理程序[1],首先安装supervisor。


  1. 之所以不用py3写,据说因为py3下其会产生崩溃的问题 ↩︎

deactivate #如果之前进入了虚拟环境,先退出
sudo pip install supervisor #用pip2安装supervisor
vim /var/www/isso/supervisor.conf #在isso目录下建立配置文件
mkdir -p /var/log/supervisor #生成日志目录

supervisord.conf文件如下

[unix_http_server]
file=/var/log/supervisor/supervisor.sock   ; the path to the socket file

[supervisord]
logfile=/var/log/supervisor/supervisord.log ; main log file; default $CWD/supervisord.log
logfile_maxbytes=50MB        ; max main logfile bytes b4 rotation; default 50MB
logfile_backups=10           ; # of main logfile backups; 0 means none,default 10
loglevel=info                ; log level; default info; others: debug,warn,trace
pidfile=/var/log/supervisor/supervisord.pid ; supervisord pidfile; default supervisord.pid
nodaemon=false               ; start in foreground if true; default false
minfds=1024                  ; min. avail startup file descriptors; default 1024
minprocs=200                 ; min. avail process descriptors;default 200

[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface

[supervisorctl]
serverurl=unix:///var/log/supervisor/supervisor.sock

[program:isso]
command = /var/www/isso/bin/isso -c /var/www/isso/isso.conf run
directory = /var/www/isso/
user = ubuntu
autostart = true
autorestart = true
stdout_logfile = /var/log/supervisor/isso.log
stderr_logfile = /var/log/supervisor/isso.err
environment = LANG="en_US.UTF-8"

然后注意,先运行一次supervisord,不要直接就运行supervisorctl,否则会报socket.error错误。

cd isso #supervisord会首先在当前目录寻找supervisord.conf
supervisord
supervisorctl stop isso #停止isso
supervisorctl start isso #启动isso

如果有其他错误,先删除/var/log/supervisor里的所有文件,然后运行一次supervisord. 更多命令参考官方文档


搜索组件ghost-algolia

在ghost v2版本中,可在Integrations中配置后台触发逻辑,实现在进行更新/删除文章等操作后,自动将消息给第三方server,因此可以使用Node.js的netlify-cli搭建一个接收server,来实时建立索引。

npm install netlify-cli -g #安装netlify-cli
git clone https://github.com/jsxzljx/ghost-algolia-online.git
cd ghost-algolia-online
npm install #安装package.json中指定的dependencies
vim src/functions/update-post.js #修改algolia设置
#注意algolia有两个api key,这里填有写权限的那个
npm run serve > algolia.log 2>&1 & #后台执行

这里npm run serve实际就是执行package.json中的scripts中的serve命令,即

netlify-lambda serve --config ./webpack.functions.js src/functions

其中

  • --config ./webpack.functions.js好像和环境变量有关,可以删掉的
  • 每次执行netlify-lambda serve命令,其会把src/functions进行编译,生成一个大的js文件,放到netlify.toml中指定的functions目录并执行,原理参考官方doc

algolia触发逻辑

保存/发布/不发布/删除会触发的逻辑:

  • 新post只编辑不发布:Post updated
  • 新post首次发布:Post publishedPost updated
  • 编辑保存已发布的post:Published post updatedPost updated
  • 发布的post改为不发布状态:Post unpublishedPost updated
  • 不发布的post改为发布状态:Post publishedPost updated
  • 删除发布状态的post:Post deletedPost unpublished
  • 删除不发布状态的post:Post deleted

因此,最后我们需要的触发逻辑只有Published post updatedPost publishedPost unpublished

algolia js client调试记录

可以自己起一个调试环境,使用algoliasearch-client-javascript进行读写调试。

在调试的过程中,发现index的deleteBy({filters: "..."})方法不work,后来谷歌搜到这篇Q&A,才发现要到algolia网页后台的Indices - Configuration - Filtering and Faceting > Facets中,把filters要用的属性添加进去,这个属性有两个用处:1) to turn an attribute into a facet;2) to make any string attribute filterable。


腾讯云记录

由于腾讯云CDN免费版套餐不区别http和https,为了使用https,决定迁移对象存储,CDN到腾讯云

https证书

FreeSSL.org网站上可以免费申请https证书,建议选择一年期的. 只需要云解析添加其要求的txt记录就可以验证域名的所有权,非常方便. 注意每个整数的keypem都是和域名一一对应的。对于a.jiaxi.mejiaxi.me,需要申请两个不同的证书。

数据万象和对象存储

首先在数据万象中新建bucket,其bucket会自动关联到对象存储cos中,注意勾选CDN加速,其会自动建立数据万象的CDN加速域名. 以后就使用这个域名访问包括图片的静态资源. 之所以不使用自定义域名或者cos的加速域名,是因为

  • 自定义域名在CDN控制台设置了HTTP Header的Access-Control-Allow-Origin值为*时,在跨域访问的时候依然总是报错,怀疑腾讯云有bug
  • cos的域名/加速域名是为了下载而使用的,如打开图片会自动下载而不是直接显示; 此外没有?imageInfo的功能

然后到对象存储的设置界面,添加Access-Control-Allow-Origin的值为*,便于跨域访问。

CDN控制台

上传证书到腾讯云后,可以为每个域名开启https. 具体方法为,在CDN设置界面,开启强制跳转HTTPS,跳转方式可以选301跳转(永久跳转)。


调试手机网页

由于手机上浏览器的内核和chrome的不一样,同样的网页显示出来不同; 所以一个办法就是连接手机,用chrome的审查元素进行调试。

手机上安装UC浏览器开发者版本,打开开发者选项-USB调试,连接电脑; 打开chrome://inspect/#devices就能看到手机UC浏览器中当前显示的页面,点击Inspect Pages进行调试,此时手机上会高亮显示当前选中的dom块。

Win10下调试iPhone iOS:这里,注意电脑需要安装safari。


Tips

  • 小banner比例为2:12.2:1,大banner是靠上30%对齐的,一般用4:3
  • MathJax配置教程,更建议参考官方文档
  • Chrome用woff2字体(带有Unicode Range),IE/夸克使用woff字体,搜狗会使用ttf字体

Last updated on Feb 08, 2020.