×

安装 Ghost

96
onizuka_jp
2017.01.13 20:47* 字数 1155

背景

一直想有一个个人博客空间,之前使用过自建的 WordPress,但是后来没有坚持下来。后来学会了 Node.js,想用 Node.js 开发的个人博客系统,之前查到过 Ghost,因为使用的是 Mysql 数据库,所以没有想使用。由于最近要重做管理平台,数据库计划由 MongoDB 迁移到 Mysql,所以有了使用 Ghost 的充分理由。

目标

  • 正常安装 Ghost;
  • 正常使用 Ghost;
  • 学习 Ghost 的代码;
  • Mysql 的连接和使用部分;
  • 权限管理部分;
  • 业务部分;
  • 配置文件;
  • 启动文件;

安装过程

安装 Ghost

第一次使用 Ghost-CLI 安装,提示一下内容:

⚠ Linux version is not Ubuntu 16,⚠ Missing package: systemd,⚠ Missing package: nginx

看来只有在 Ubuntu 16 上才可以使用 Ghost-CLI,我的 Centos 7 自然是不行了。因此采用最传统的安装方式。

  1. 下载最新的 Ghost 版本

    curl -L https://ghost.org/zip/ghost-latest.zip -o ghost.zip

  2. 解压到指定文件夹

    unzip ghost.zip -d ./ghost/

  3. 安装运行所需要的依赖包

    npm install --production

  4. 测试运行

    npm start --production

  5. 建立 PM2 配置文件,使用 PM2 运行 Ghost

    pm2 ecosystem
    pm2 start ecosystem.config.js

  6. 配置 Nginx

  7. 将数据库从 SQLite3 更换为 MariaDB,修改配置文件 config.js

database: {
  client: 'mysql',
  connection: {
    host     : '127.0.0.1',
    user     : 'your_database_user',
    password : 'your_database_password',
    database : 'ghost_db',
    charset  : 'utf8'
  }
}

配置 HTTPS

  1. 安装 certbot;
  2. 修改原有 Nginx 配置文件;
  3. 下载证书;
  4. 再次编辑 Nginx 配置文件,启用 HTTP2 和 HTTPS;
  5. 定期自动更新证书

安装 certbot

sudo yum install epel-release
sudo yum install certbot

修改原有 Nginx 配置文件

Let's encrypt 为了鉴定域名的所有权,会在域名下的 /.well-known/acme-challenge 路径下放置一个文件,并做相应的鉴权,因此需要保证相关路径能够正确的解析,最简单的办法就是直接修改 Nginx 配置文件。

location ^~ /.well-known/acme-challenge/ {
  root /usr/share/nginx/html;
}

location = /.well-known/acme-challenge/ {
  return 404;
}

下载证书

certbot certonly --webroot -w /usr/share/nginx/html/ -d domain1.com -d domain2.com

然后就会进入安装界面,提示输入邮箱地址等信息,然后就安装完毕了。证书文件被保存在 /etc/letsencrypt/live/domain.com/fullchain.pem 下。

再次编辑 Nginx 配置文件,启用 HTTP2 和 HTTPS

upstream my_nodejs_upstream {
    server 127.0.0.1:2368;
    keepalive 64;
}

server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name domain.com;

# Redirect all HTTP requests to HTTPS with a 301 Moved
Permanently response.
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name domain.com;

    # certs sent to the client in SERVER HELLO are concatenated in ssl_certificate
    ssl_certificate /etc/letsencrypt/live/domain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/domain.com/privkey.pem;
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;
    ssl_session_tickets off;

    # Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits
    ssl_dhparam /etc/nginx/ssl/dhparam.pem;

    # intermediate configuration. tweak to your needs.
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
    ssl_prefer_server_ciphers on;

    # HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months)
    add_header Strict-Transport-Security max-age=15768000;

    # OCSP Stapling ---
    # fetch OCSP records from URL in ssl_certificate and cache them
    ssl_stapling on;
    ssl_stapling_verify on;

    resolver 8.8.8.8 8.8.4.4;

    location / {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-NginX-Proxy true;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_max_temp_file_size 0;
        proxy_pass http://my_nodejs_upstream/;
        proxy_redirect off;
        proxy_read_timeout 240s;
    }

    location ^~ /.well-known/acme-challenge/ {
        root    /usr/share/nginx/html;
    }

    location = /.well-known/acme-challenge/ {
        return 404;
    }
}

其中,ssl_certificate 开头的和 ssl_certificate_key 开头的这句分别对应刚刚下载好的证书。
另外,ssl_dhparam 开头的这句指向的证书需要通过以下代码来生成。

sudo mkdir /etc/nginx/ssl
sudo openssl dhparam -out /etc/nginx/ssl/dhparam.pem 2048

定期自动更新证书

因为 Let's encrypt 证书的有效期限是 90 天,因此在 90 天必须要更新证书以避免证书失效。根据 Certbot 官网所述,只有在临近到期时才会真正更换证书,因此最好的每天执行更新命令,确保证书及时更新。

测试更新命令

使用以下命令测试更新证书,但并不会真的更新。

sudo certbot renew --dry-run

设置更新证书定时任务

首先创建定制任务

sudo crontabe -e

然后在文件中加入以下语句,表示在每天的 3 点 43 分尝试更新证书,如果证书更新成功,则重启 Nginx 服务以便读取新证书

43 3 * * * certbot renew --quiet --post-hook "systemctl reload nginx"

测试定时更新语句

为确保定时更新语句有效,最好单独测试一下,直接输入以下语句看执行结果

certbot renew --quiet --post-hook "systemctl reload nginx"

应该会提示还不需要更新,不过不要紧,只要测试语句有效就可以了。至此,HTTP2 和 HTTPS 的配置全部完毕。

测试配置成果

测试服务器 SSL 的安全性

Qualys SSL Labs 提供了全面的 SSL 安全性测试,填写你的网站域名,给自己的 HTTPS 配置打个分。

如果安装本教程来配置,正常情况下应该会得到 A+ 的得分。

测试 HTTP2

Chrome 下有个插件叫做 HTTP/2 and SPDY indicator。可以利用它来查看访问的站点是否支持 HTTP2。

HTTP2 的问题

话说 HTTP2 之前有 2 种实现的协商协议,分别是 NPN 和 ALPN,后来 Chrome 就只支持 ALPN 了。但当前大部分服务器的 OpenSSL 都是1.01e 版本,只支持 NPN。因此按照本教程部署完毕后,使用 Chrome 刚刚配置好的站点的时候发现还是不能使用 HTTP2,还需要在服务器上做一些调整才可以。

参考资料

实践
Web note ad 1