背景
一直想有一個(gè)個(gè)人博客空間吗购,之前使用過(guò)自建的 WordPress喊递,但是后來(lái)沒(méi)有堅(jiān)持下來(lái)疤剑。后來(lái)學(xué)會(huì)了 Node.js滑绒,想用 Node.js 開發(fā)的個(gè)人博客系統(tǒng),之前查到過(guò) Ghost隘膘,因?yàn)槭褂玫氖?Mysql 數(shù)據(jù)庫(kù)疑故,所以沒(méi)有想使用。由于最近要重做管理平臺(tái)弯菊,數(shù)據(jù)庫(kù)計(jì)劃由 MongoDB 遷移到 Mysql纵势,所以有了使用 Ghost 的充分理由。
目標(biāo)
- 正常安裝 Ghost管钳;
- 正常使用 Ghost钦铁;
- 學(xué)習(xí) Ghost 的代碼;
- Mysql 的連接和使用部分才漆;
- 權(quán)限管理部分牛曹;
- 業(yè)務(wù)部分;
- 配置文件醇滥;
- 啟動(dòng)文件黎比;
安裝過(guò)程
安裝 Ghost
第一次使用 Ghost-CLI 安裝超营,提示一下內(nèi)容:
? Linux version is not Ubuntu 16,? Missing package: systemd,? Missing package: nginx
看來(lái)只有在 Ubuntu 16 上才可以使用 Ghost-CLI,我的 Centos 7 自然是不行了阅虫。因此采用最傳統(tǒng)的安裝方式演闭。
-
下載最新的 Ghost 版本
curl -L https://ghost.org/zip/ghost-latest.zip -o ghost.zip
-
解壓到指定文件夾
unzip ghost.zip -d ./ghost/
-
安裝運(yùn)行所需要的依賴包
npm install --production
-
測(cè)試運(yùn)行
npm start --production
-
建立 PM2 配置文件,使用 PM2 運(yùn)行 Ghost
pm2 ecosystem
pm2 start ecosystem.config.js 配置 Nginx
將數(shù)據(jù)庫(kù)從 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
- 安裝 certbot米碰;
- 修改原有 Nginx 配置文件;
- 下載證書躲履;
- 再次編輯 Nginx 配置文件见间,啟用 HTTP2 和 HTTPS聊闯;
- 定期自動(dòng)更新證書
安裝 certbot
sudo yum install epel-release
sudo yum install certbot
修改原有 Nginx 配置文件
Let's encrypt 為了鑒定域名的所有權(quán)工猜,會(huì)在域名下的 /.well-known/acme-challenge
路徑下放置一個(gè)文件,并做相應(yīng)的鑒權(quán)菱蔬,因此需要保證相關(guān)路徑能夠正確的解析篷帅,最簡(jiǎn)單的辦法就是直接修改 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
然后就會(huì)進(jìn)入安裝界面拴泌,提示輸入郵箱地址等信息魏身,然后就安裝完畢了。證書文件被保存在 /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
開頭的這句分別對(duì)應(yīng)剛剛下載好的證書回季。
另外家制,ssl_dhparam
開頭的這句指向的證書需要通過(guò)以下代碼來(lái)生成。
sudo mkdir /etc/nginx/ssl
sudo openssl dhparam -out /etc/nginx/ssl/dhparam.pem 2048
定期自動(dòng)更新證書
因?yàn)?Let's encrypt 證書的有效期限是 90 天泡一,因此在 90 天必須要更新證書以避免證書失效颤殴。根據(jù) Certbot 官網(wǎng)所述,只有在臨近到期時(shí)才會(huì)真正更換證書鼻忠,因此最好的每天執(zhí)行更新命令涵但,確保證書及時(shí)更新。
測(cè)試更新命令
使用以下命令測(cè)試更新證書帖蔓,但并不會(huì)真的更新矮瘟。
sudo certbot renew --dry-run
設(shè)置更新證書定時(shí)任務(wù)
首先創(chuàng)建定制任務(wù)
sudo crontabe -e
然后在文件中加入以下語(yǔ)句,表示在每天的 3 點(diǎn) 43 分嘗試更新證書塑娇,如果證書更新成功澈侠,則重啟 Nginx 服務(wù)以便讀取新證書
43 3 * * * certbot renew --quiet --post-hook "systemctl reload nginx"
測(cè)試定時(shí)更新語(yǔ)句
為確保定時(shí)更新語(yǔ)句有效,最好單獨(dú)測(cè)試一下钝吮,直接輸入以下語(yǔ)句看執(zhí)行結(jié)果
certbot renew --quiet --post-hook "systemctl reload nginx"
應(yīng)該會(huì)提示還不需要更新埋涧,不過(guò)不要緊板辽,只要測(cè)試語(yǔ)句有效就可以了。至此棘催,HTTP2 和 HTTPS 的配置全部完畢劲弦。
測(cè)試配置成果
測(cè)試服務(wù)器 SSL 的安全性
Qualys SSL Labs 提供了全面的 SSL 安全性測(cè)試,填寫你的網(wǎng)站域名醇坝,給自己的 HTTPS 配置打個(gè)分邑跪。
如果安裝本教程來(lái)配置,正常情況下應(yīng)該會(huì)得到 A+ 的得分呼猪。
測(cè)試 HTTP2
Chrome 下有個(gè)插件叫做 HTTP/2 and SPDY indicator画畅。可以利用它來(lái)查看訪問(wèn)的站點(diǎn)是否支持 HTTP2宋距。
HTTP2 的問(wèn)題
話說(shuō) HTTP2 之前有 2 種實(shí)現(xiàn)的協(xié)商協(xié)議轴踱,分別是 NPN 和 ALPN,后來(lái) Chrome 就只支持 ALPN 了谚赎。但當(dāng)前大部分服務(wù)器的 OpenSSL 都是1.01e 版本淫僻,只支持 NPN。因此按照本教程部署完畢后壶唤,使用 Chrome 剛剛配置好的站點(diǎn)的時(shí)候發(fā)現(xiàn)還是不能使用 HTTP2雳灵,還需要在服務(wù)器上做一些調(diào)整才可以。