先前是以 systemd-nspawn 自行建立管理 image 來運行 ghost 的, 但它的升級更新常會掛掉. 再加上放在前面的 nginx 查不到 ghost 所在的 hostname 時就停止運行, 管理起來實在不方便. 因此, 決定重新整理服務管理方式.

目標

  • 改以 docker-compose 安裝及管理服務
  • 加上 code block syntax highlight 功能
  • 整合 plantuml 產生 UML diagram
  • 整合 :smile: 這樣的 emoji 替換功能
  • 整合 TOC 產生功能
  • 整合留言功能
  • 整合 Google analytics

安裝 Docker + Docker Compose

在 server 上, 我用的是 debian 9 (stretch), 安裝 docker 的完整說明見此頁

$ sudo apt-get remove docker docker-engine docker.io
$ sudo apt-get install \
     apt-transport-https \
     ca-certificates \
     curl \
     gnupg2 \
     software-properties-common
$ curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add -
$ sudo add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/debian \
   $(lsb_release -cs) \
   stable"
$ sudo apt-get update
$ sudo apt-get install docker-ce

接著安裝 Docker Compose, 完整說明請見此頁

$ sudo curl -L https://github.com/docker/compose/releases/download/1.22.0/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose

安裝 Ghost

建立目錄放置服務相關設定

$ mkdir my-services && cd my-services
$ vi docker-compose.yml

docker-compose.yml 內容如下, 官方的 image 來源於此

version: '3'

services:
  blog:
    image: ghost:alpine
    restart: always
    volumes:
      - blog-data:/var/lib/ghost/content
    ports:
      - 127.0.0.1:8080:2368

volumes:
  blog-data:

用的 image 是基於 alpine 的版本, 總體容量會小一點, 省 VPS 空間

  blog:
    image: ghost:alpine
  ...
volumes:
  blog-data:

讓這個 container 在系統重新啟動或是 docker 重新啟動後都會自動啟動

    restart: always

配置 volume 存放永久資料

    volumes:
      - blog-data:/var/lib/ghost/content

這個 image 預設 listen 在 2368 上, 暫時 map 到 127.0.0.1 的 8080 上不對外

    ports:
      - 127.0.0.1:8080:2368

啟動並測試是否能連上

$ sudo docker-compose up -d
$ curl http://localhost:8080
<!DOCTYPE html>
<html lang="en">
<head>

    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />

    <title>Ghost</title>
    <meta name="HandheldFriendly" content="True" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

查看 ghost 的 log

$ sudo docker-compose logs -f blog
Attaching to my-services_blog_1
blog_1   | [2018-07-30 23:18:38] INFO Creating table: posts
blog_1   | [2018-07-30 23:18:38] INFO Creating table: users
blog_1   | [2018-07-30 23:18:38] INFO Creating table: posts_authors
blog_1   | [2018-07-30 23:18:38] INFO Creating table: roles
blog_1   | [2018-07-30 23:18:38] INFO Creating table: roles_users
blog_1   | [2018-07-30 23:18:38] INFO Creating table: permissions
blog_1   | [2018-07-30 23:18:38] INFO Creating table: permissions_users
blog_1   | [2018-07-30 23:18:38] INFO Creating table: permissions_roles
blog_1   | [2018-07-30 23:18:38] INFO Creating table: permissions_apps
blog_1   | [2018-07-30 23:18:38] INFO Creating table: settings
blog_1   | [2018-07-30 23:18:38] INFO Creating table: tags
blog_1   | [2018-07-30 23:18:38] INFO Creating table: posts_tags
blog_1   | [2018-07-30 23:18:38] INFO Creating table: apps
blog_1   | [2018-07-30 23:18:38] INFO Creating table: app_settings
...

安裝 nginx

為了讓 80 & 443 能提供更多功能, 需要在 ghost 前放個 nginx 提供 reverse proxy 功能,

docker-compose.yml 修改如下

version: '3'

services:
  proxy:
    image: nginx:alpine
    restart: always
    volumes:
      - ./proxy-conf.d:/etc/nginx/conf.d:ro
      - ./proxy-root:/usr/share/nginx/html:ro
      - proxy-log:/var/log/nginx
    ports:
      - 6080:80
      - 6443:443
    depends_on:
      - blog
    networks:
      - proxy-blog

  blog:
    image: ghost:alpine
    restart: always
    volumes:
      - blog-data:/var/lib/ghost/content
    networks:
      - proxy-blog

volumes:
  blog-data:
  proxy-log:

networks:
  proxy-blog:

nginx 也同樣是用基於 alpine 的版本

  proxy:
    image: nginx:alpine

提供空間放置設定, 靜態內容及 nginx 的 log (具體的路徑可參考這裡)

    volumes:
      - ./proxy-conf.d:/etc/nginx/conf.d:ro
      - ./proxy-root:/usr/share/nginx/html:ro
      - proxy-log:/var/log/nginx

建立一個用在 nginx 與 ghost 間的網路, 不讓 ghost 被其他的 container (如果有的話) 看到

  proxy:
    image: nginx:alpine
    
    ...
    
    networks:
      - proxy-blog

...

networks:
  proxy-blog:

接下來, 去掉 ghost 原本的 port map, 改用運才建立的 netowrk 與 nginx 連接

  blog:
    image: ghost:alpine
    restart: always
    volumes:
      - blog-data:/var/lib/ghost/content
    networks:
      - proxy-blog

幫 ghost 加上 nginx 設定, 放在 ./proxy-conf.d/default.conf

upstream ghost {
    server blog:2368;
}

server {
    server_name co-op.space;
    listen 80;
    listen [::]:80;

    root /usr/share/nginx/html;

    location / {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forward-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forward-Proto $scheme;
        proxy_set_header HOST $http_host;
        proxy_set_header X-NginX-Proxy true;
        proxy_pass http://ghost;
        proxy_redirect off;
    }
}

存檔後, 確認設定的正確性並重新載入 nginx 設定

$ sudo docker-compose exec proxy nginx -t
$ sudo docker-compose exec proxy nginx -s reload

curl 確認下 ghost 的可用性

$ curl http://localhost:6080

沒問題的話, 就可用 browser 連上管理頁面 https://localhost:6080/ghost/ 進行設定