我的Ghost博客的搭建

一、环境准备

1.1.系统环境

查看环境
cat /etc/centos-release
CentOS Linux release 7.3.1611 (Core)

1.2.更换系统的yum源

yum -y install wget
mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak
wget http://mirrors.163.com/.help/CentOS7-Base-163.repo
mv CentOS7-Base-163.repo /etc/yum.repos.d/CentOS-Base.repo
yum clean all && yum makecache && yum -y update

1.3.关闭防火墙

systemctl stop firewalld
systemctl disable firewalld

1.4.关闭selinux

setenforce 0
sed -i 's/enforcing/disabled/g' /etc/selinux/config
sed -i 's/enforcing/disabled/g' /etc/sysconfig/selinux

1.5.安装docker

这里选择yum安装,如果想安装其他版本可以参考官方的文档docker安装
或者我以前根据文档写的一个脚本docker脚本安装
yum -y install epel-release && yum -y install docker
yum -y install python-pip && systemctl start docker
systemctl enable docker && systemctl daemon-reload
查看docker版本
docker version
添加国内镜像源
echo {\"registry-mirrors\":[\"https://nr630v1c.mirror.aliyuncs.com\"]} > /etc/docker/daemon.json

1.6.安装docker-compose

pip install docker-compose && pip install --upgrade pip
查看docker-compose版本
docker-compose version

1.7.docker部署的原因

由于以前的博客版本为中文版,版本比较低,很多功能不全,喜欢的模板无法使用,所以决定升级到最新的英文版,因为工作环境在使用docker,所以就想试一试能不能通过docker来搭建博客,上网查了一些资料发现使用docker安装还是比较方便的,同时升级ghost要比源码安装简单

二、正式安装

2.1.镜像拉取

docker pull centos
docker pull ghost
docker pull mysql:5.7
docker pull nginx

2.2.创建相关文件目录

2.2.1.日志文件创建

mkdir -p /data/blog/ghost
nginx日志目录
touch access.log
touch error_nginx.log
mysql日志目录
touch mysql.log
touch error_mysql.log
后面将容器内的日志文件映射出来需要将我们上面创建的文件赋予权限
chmod 777 access.log error_nginx.log mysql.log error_mysql.log

2.2.2.mysql配置文件

cat mysqld.cnf

[mysqld]
pid-file = /var/run/mysqld/mysqld.pid
socket = /var/run/mysqld/mysqld.sock
datadir = /var/lib/mysql
symbolic-links=0
character-set-server=utf8
back_log=500
wait_timeout=1800
max_connections=3000
max_user_connections=800
innodb_thread_concurrency=40
default-storage-engine=innodb
key_buffer_size=400M
innodb_buffer_pool_size=1G
innodb_log_file_size=256M
innodb_flush_method=O_DIRECT
innodb_log_buffer_size=20M
query_cache_size=40M
read_buffer_size=4M
sort_buffer_size=4M
read_rnd_buffer_size=8M
tmp_table_size=64M
thread_cache_size=64
max_allowed_packet=200M
server-id=1
log_bin=mysql-bin
general-log=1
general_log_file=/var/log/mysql/general.log
log-error=/var/log/mysql/error.log
#bind-address           = 127.0.0.1

2.2.3.ghost配置文件

cat config.production.json

{
  "url": "https://linuxwt.com",
  "server": {
    "port": 2368,
    "host": "0.0.0.0"
  },
  "database": {
    "client": "mysql",
    "connection": {
     "host": "mysql_ghost",
     "user": "username",
     "password": "password",
     "database": "databasename", 
      "filename": "/var/lib/ghost/content/data/ghost.db"
    }
  },
  "mail": {
    "transport": "Direct"
  },
  "logging": {
    "transports": [
      "file",
      "stdout"
    ]
  },
  "process": "systemd",
  "paths": {
    "contentPath": "/var/lib/ghost/content"
  }
}

2.2.4.获取CA证书

git clone https://github.com/letsencrypt/letsencrypt
cd letsencrypt
./letsencrypt-auto certonly --server https://acme-v01.api.letsencrypt.org/directory --agree-dev-preview
要求输入邮箱和要配置https的域名
1.Place files in webroot directory(webroot)
2.Spin up a temporary webserver(standalone)
选择2
生成相应的证书文件,其路径为
/etc/letsencrypt/live/linuxwt.com/privkey.pem
/etc/letsencrypt/live/linuxwt.com/fullchain.pem

2.2.5.nginx配置文件

cat nginx.conf

worker_processes  1;
error_log  /var/log/nginx/error.log warn;  
pid        /var/run/nginx.pid;
events {  
    worker_connections  1024;
}
http {  
    include        /etc/nginx/mime.types;
    server_tokens off;
    default_type  application/octet-stream;
    access_log  /var/log/nginx/access.log;
    error_log   /var/log/nginx/error.log;
    sendfile        on;
    tcp_nopush     on;
    tcp_nodelay    on;
    keepalive_timeout  60;
    gzip  on;
    gzip_min_length  1k;
    gzip_buffers     16 8K;
    gzip_http_version 1.1;
    gzip_comp_level 6;
    gzip_types text/plain image/png  application/javascript application/x-javascript  text/javascript text/css application/xml image/x-icon application/xml+rss 
    application/json; 
    gzip_vary on;
    gzip_proxied   any;
    gzip_disable   "msie6";
    include /etc/nginx/conf.d/*.conf;
}

cat nginx_reverse.conf

upstream ghostapp {  
    server myghost:2368;
    }
    server {
        listen       80;
        server_name  linuxwt.com;
        charset utf-8;
        location / {
                return       301 https://linuxwt.com$request_uri;
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }

    server {
         listen       443 ssl;
         server_name  linuxwt.com;
         #禁止Scrapy等工具的抓取
         if ($http_user_agent ~* (Scrapy|Curl|HttpClient)) {
                    return 403;
         }
         # 禁止非GET请求,用于防止远程脚本攻击,注意加了这条无法访问后台
         #  if ($request_method = POST) { 
         #  return 403;
         #  }
         #禁止指定UA及UA为空的访问
         if ($http_user_agent ~ "WinHttp|WebZIP|FetchURL|node-superagent|java/|FeedDemon|Jullo|JikeSpider|Indy Library|Alexa Toolbar|AskTbFXTV|AhrefsBot|CrawlDaddy|Java|Feedly|Apache-HttpAsyncClient|UniversalFeedParser|ApacheBench|Microsoft URL Control|Swiftbot|ZmEu|oBot|jaunty|Python-urllib|lightDeckReports Bot|YYSpider|DigExt|HttpClient|MJ12bot|heritrix|EasouSpider|Ezooms|BOT/0.1|YandexBot|FlightDeckReports|Linguee Bot|^$") {    
                    return 403;    
         }
         charset utf-8;
         ssl_certificate      /etc/letsencrypt/live/linuxwt.com/fullchain.pem;
         ssl_certificate_key  /etc/letsencrypt/live/linuxwt.com/privkey.pem;
         ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
         ssl_ciphers  HIGH:!aNULL:!MD5;
         location / {
         proxy_set_header X-Real-IP $remote_addr;
         proxy_set_header HOST $http_host;
         proxy_set_header X-NginX-Proxy true;
         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
         proxy_set_header X-Forwarded-Proto $scheme;
         proxy_pass http://ghostapp;
         proxy_redirect off;
         client_max_body_size 35m;
      }
    }

2.2.6.编写docker-compose.yml

version: '2'
services:
  nginx_ghost:  
      restart: always
      image: nginx
      container_name: nginx_ghost
      volumes:
          - /etc/localtime:/etc/localtime
          - ./nginx.conf:/etc/nginx/nginx.conf 
          - ./nginx_reverse.conf:/etc/nginx/conf.d/default.conf
          - /etc/timezone:/etc/timezone
          - ./access.log:/var/log/nginx/access.log
          - ./error_nginx.log:/var/log/nginx/error.log
          - /etc/letsencrypt:/etc/letsencrypt
      links:
          - myghost
      privileged: true
      ports:
          - 80:80
          - 443:443
  myghost:  
      restart: always
      image: ghost
      container_name: myghost
      volumes:
          - /etc/localtime:/etc/localtime
          - /etc/timezone:/etc/timezone
          - ./content:/var/lib/ghost/content
          - ./config.production.json:/var/lib/ghost/config.production.json
      privileged: true
      expose:
          - "2368"
      links:
          - mysql_ghost
  mysql_ghost:
      restart: always
      image: mysql:5.7
      container_name: mysql_ghost
      volumes:
          - /etc/localtime:/etc/localtime
          - /etc/timezone:/etc/timezone
          - $PWD/mysql:/var/lib/mysql
          - $PWD/mysqld.cnf:/etc/mysql/mysql.conf.d/mysqld.cnf
          - $PWD/mysql.log:/var/log/mysql/general.log
          - $PWD/error_mysql.log:/var/log/mysql/error.log
      ports:
          - 3306:3306
      environment:
          MYSQL_ROOT_PASSWORD: rootpassword

启动容器
docker-compose up -d
docker ps -a发现myghost容器没有起来,这是因为我们前面在ghost配置文件里面设置了相关数据库,我们需要进入mysql创建ghost用于连接mysql的用户和库
docker exec -it mysql_ghost bash
mysql -u root -p
输入root密码登陆
create database databasename;
create user 'username'@'%' identified by 'password';
grant all privileges on databasename.* to 'username'@'%';
flush privileges;
docker-compose down
docker-compose up -d
docker ps -a发现容器均已启动

三、后期维护

3.1.数据备份

  • 编写备份脚本
    cat mysql_backup.sh
#!/bin/bash

LOG="/data/blog/ghost/backup.log"
TIME1=`date +%Y%m%d_%R`
>$LOG
TIME1=`date +%Y%m%d_%R`

database=databasename
basedir="/data/blog/ghost/bak"
if [ ! -d $basedir ];then
   mkdir $basedir
fi

for db in $database
do
docker exec mysql_ghost mysqldump -uusername -ppassword --databases ${db} > ${basedir}/ghost-$(date +%Y%m%d).sql
find $basedir -mtime +7 -name "*.sql" -exec rm -Rf {} \; 
done

if [ $? -eq  0 ];then
    TIME2=`date +%Y%m%d_%R`

    echo " ${TIME1} start to backup.   Mysql database backup Success at ${TIME2} " >> $LOG
else
    TIME2=`date +%Y%m%d_%R`
    echo " ${TIME1} start to backup.   Mysql database backup Fail.Please check it. time: ${TIME2} " >>$LOG
    exit 1;
fi
find $basedir -mtime +7 -name "*.sql" -exec rm -Rf {} \;
  • 计划执行脚本
    echo "0 23 * * * root /data/blog/ghost/mysql_backup.sh" >> /etc/crontab
    systemctl restart cornd.service

3.2.证书续期

使用的ssl证书只有3个月的有效期,过期后需要进行重新认证
cat autoCA.sh

#!/bin/bash

cd /data/blog/ghost
/usr/local/letsencrypt/certbot-auto renew   --force-renewal   --pre-hook "docker-compose down" --post-hook "docker-compose up -d"  

有时候证书续期会出现问题,报下面的错误

Couldn't download https://raw.githubusercontent.com/certbot/certbot/v0.39.0/letsencrypt-auto-source/letsencrypt-auto. <urlopen error [Errno 110]

可以加上参数--no-self-upgrade