centos7+nginx+docker+ghost1.18.0部署手册

【概述】

  • 简单docker搭建Ghost
  • 复杂docker-compose搭建Ghost+Nginx

核心步骤

  1. 解析域名
  2. 启动docker容器
  3. 访问网页

具体步骤

  1. 域名:购买服务器VPS+解析域名
  2. 环境:创建帐号,并预设权限
  3. 环境:安装docker和docker-compose
  4. 环境:创建docker网络,用于串联ghost和nginx等容器
  5. 博客:配置ghost的映射目录和博客配置文件
  6. 博客:创建运行ghost容器
  7. 代理:配置nginx映射目录和代理配置文件
  8. 代理:创建运行nginx容器
  9. 证书:创建运行certbot容器,并更新证书
  10. 部署成果,访问成功

部署过程

购买服务器VPS+解析域名

  • Linode注册充值(已弃用,改用oracle的)
    官网:www.linode.com
    推荐码:注册充值时,填写推荐码,可以获得20美金赠送。
    推荐码:acd1469162f9392327ba6850077ea3512a521ec3
  • Linode创建多个实例
  • ping一番,考察下哪里的服务器快,保留快的那个实例,其它都可以删了
  • 部署centos7系统,linode4669841_tokyo » Dashboard » Deploy an Image
  • 在域名服务商那,修改dns记录,添加a记录指向你的服务器IP

创建帐号,并预设权限

  • 创建ghost专用帐号
# 创建帐号
[opc@instance-20210526-1447 ~]$ sudo -i
[root@instance-20210526-1447 ~]# groupadd ghost
[root@instance-20210526-1447 ~]# useradd -m -g ghost ghost -c "Ghost Blog User"
[root@instance-20210526-1447 ~]# passwd ghost
Changing password for user ghost.
New password: 
Retype new password: 
passwd: all authentication tokens updated successfully.
[root@instance-20210526-1447 ~]# mkdir /www
[root@instance-20210526-1447 ~]# mkdir -p /www/ghost/content
[root@instance-20210526-1447 ~]# mkdir -p /www/nginx
[root@instance-20210526-1514 ~]# chown -R ghost /www
[root@instance-20210526-1447 ~]# ll /www | grep ghost
drwxr-xr-x. 3 ghost ghost 21 May 26 07:01 ghost
  • 给ghost帐号增加一些权限
[root@instance-20210526-1447 ~]# visudo
#修改sudoers文件,
#使得用户ghost执行docker相关命令时,不需要密码
ghost ALL=/sbin/service,/bin/systemctl
ghost ALL=(ALL) NOPASSWD: /usr/bin/docker,/usr/bin/docker-compose,/usr/bin/yum,/bin/ln,/bin/snap,/bin/tar
[root@instance-20210526-1447 ~]# sudo su ghost
[ghost@instance-20210526-1447 root]$ cd ~
[ghost@instance-20210526-1447 ~]$ ls -a
.  ..  .bash_history  .bash_logout  .bash_profile  .bashrc
[ghost@instance-20210526-1447 ~]$ vi .bashrc
alias docker="sudo /usr/bin/docker"  
alias docker-compose="sudo /usr/bin/docker-compose"
alias apt-get="sudo /usr/bin/yum" 
[ghost@instance-20210526-1447 ~]$ source ~/.bashrc
  • ssh免密登录
[ghost@instance-20210526-1514 ~]$ mkdir .ssh
[ghost@instance-20210526-1514 ~]$ chmod 700 .ssh
[ghost@instance-20210526-1514 ~]$ sudo yum install -y lrzsz
# 上传xshell的pub公钥文件
[ghost@instance-20210526-1514 .ssh]$ rz
[ghost@instance-20210526-1514 ~]$ cd .ssh
[ghost@instance-20210526-1514 .ssh]$ touch authorized_key
[ghost@instance-20210526-1514 .ssh]$ cat oracle_20210526_rsa_2048.pub >> authorized_keys 
[ghost@instance-20210526-1514 .ssh]$ chmod 600 authorized_keys
[ghost@instance-20210526-1514 .ssh]$ sudo systemctl restart sshd.service
  • 防火墙改用iptables
[ghost@instance-20210526-1514 nginx]$ sudo su
[sudo] password for ghost:
[root@instance-20210526-1514 nginx]# systemctl stop firewalld
# 启用iptables管理 22,80,443
[root@instance-20210526-1514 nginx]# yum install -y iptables-services 
[root@instance-20210526-1514 nginx]# systemctl start iptables
# 拷贝iptables备份文件覆盖/etc/sysconfig/iptables
[root@instance-20210526-1514 nginx]# vi /etc/sysconfig/iptables
[root@instance-20210526-1514 nginx]# cp /home/ghost/iptables /etc/sysconfig/iptables
cp: overwrite ‘/etc/sysconfig/iptables’? yes
[root@instance-20210526-1514 nginx]# systemctl restart iptables.service

安装docker和docker-compose

  • 安装docker

[root@instance-20210526-1514 ~]# yum-config-manager --add-repo http://download.docker.com/linux/centos/docker-ce.repo  # 使用官方源
[root@instance-20210526-1514 ~]# yum list docker-ce --showduplicates | sort -r  # 查看可安装版本
 * updates: ftp.iij.ad.jp
This system is not registered with an entitlement server. You can use subscription-manager to register.
              : subscription-manager
Loading mirror speeds from cached hostfile
Loaded plugins: fastestmirror, langpacks, product-id, search-disabled-repos,
 * extras: ftp.iij.ad.jp
 * epel: www.ftp.ne.jp
docker-ce.x86_64            3:26.1.4-1.el7                      docker-ce-stable
...
 * base: ftp-srv2.kddilabs.jp
Available Packages
[root@instance-20210526-1514 ~]# yum install docker-ce 	 	# 默认安装最新版
Loaded plugins: fastestmirror, langpacks, product-id, search-disabled-repos, subscription-manager

This system is not registered with an entitlement server. You can use subscription-manager to register.

Loading mirror speeds from cached hostfile
 * base: ftp-srv2.kddilabs.jp
 * epel: www.ftp.ne.jp
 * extras: ftp.iij.ad.jp
 * updates: ftp.iij.ad.jp
Resolving Dependencies
--> Running transaction check
---> Package docker-ce.x86_64 3:26.1.4-1.el7 will be installed
--> Processing Dependency: containerd.io >= 1.6.24 for package: 3:docker-ce-26.1.4-1.el7.x86_64
--> Processing Dependency: docker-ce-cli for package: 3:docker-ce-26.1.4-1.el7.x86_64
--> Processing Dependency: docker-ce-rootless-extras for package: 3:docker-ce-26.1.4-1.el7.x86_64
--> Running transaction check
---> Package containerd.io.x86_64 0:1.6.33-3.1.el7 will be installed
---> Package docker-ce-cli.x86_64 1:26.1.4-1.el7 will be installed
--> Processing Dependency: docker-buildx-plugin for package: 1:docker-ce-cli-26.1.4-1.el7.x86_64
--> Processing Dependency: docker-compose-plugin for package: 1:docker-ce-cli-26.1.4-1.el7.x86_64
---> Package docker-ce-rootless-extras.x86_64 0:26.1.4-1.el7 will be installed
--> Running transaction check
---> Package docker-buildx-plugin.x86_64 0:0.14.1-1.el7 will be installed
---> Package docker-compose-plugin.x86_64 0:2.27.1-1.el7 will be installed
--> Finished Dependency Resolution

Dependencies Resolved

==================================================================================================================================================================================
 Package                                             Arch                             Version                                    Repository                                  Size
==================================================================================================================================================================================
Installing:
 docker-ce                                           x86_64                           3:26.1.4-1.el7                             docker-ce-stable                            27 M
Installing for dependencies:
 containerd.io                                       x86_64                           1.6.33-3.1.el7                             docker-ce-stable                            35 M
 docker-buildx-plugin                                x86_64                           0.14.1-1.el7                               docker-ce-stable                            14 M
 docker-ce-cli                                       x86_64                           1:26.1.4-1.el7                             docker-ce-stable                            15 M
 docker-ce-rootless-extras                           x86_64                           26.1.4-1.el7                               docker-ce-stable                           9.4 M
 docker-compose-plugin                               x86_64                           2.27.1-1.el7                               docker-ce-stable                            13 M

Transaction Summary
==================================================================================================================================================================================
Install  1 Package (+5 Dependent packages)

Total download size: 114 M
Installed size: 401 M
Is this ok [y/d/N]: y
Downloading packages:
warning: /var/cache/yum/x86_64/7/docker-ce-stable/packages/docker-buildx-plugin-0.14.1-1.el7.x86_64.rpm: Header V4 RSA/SHA512 Signature, key ID 621e9f35: NOKEY1 MB  00:00:20 ETA 
Public key for docker-buildx-plugin-0.14.1-1.el7.x86_64.rpm is not installed
(1/6): docker-buildx-plugin-0.14.1-1.el7.x86_64.rpm                                                                                                        |  14 MB  00:00:05     
(2/6): containerd.io-1.6.33-3.1.el7.x86_64.rpm                                                                                                             |  35 MB  00:00:11     
(3/6): docker-ce-cli-26.1.4-1.el7.x86_64.rpm                                                                                                               |  15 MB  00:00:03     
(4/6): docker-ce-rootless-extras-26.1.4-1.el7.x86_64.rpm                                                                                                   | 9.4 MB  00:00:01     
(5/6): docker-compose-plugin-2.27.1-1.el7.x86_64.rpm                                                                                                       |  13 MB  00:00:02     
(6/6): docker-ce-26.1.4-1.el7.x86_64.rpm                                                                                                                   |  27 MB  00:00:14     
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Total                                                                                                                                             5.7 MB/s | 114 MB  00:00:19     
Retrieving key from https://download.docker.com/linux/centos/gpg
Importing GPG key 0x621E9F35:
 Userid     : "Docker Release (CE rpm) <docker@docker.com>"
 Fingerprint: 060a 61c5 1b55 8a7f 742b 77aa c52f eb6b 621e 9f35
 From       : https://download.docker.com/linux/centos/gpg
Is this ok [y/N]: y
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
  Installing : docker-buildx-plugin-0.14.1-1.el7.x86_64                                                                                                                       1/6 
  Installing : containerd.io-1.6.33-3.1.el7.x86_64                                                                                                                            2/6 
  Installing : docker-compose-plugin-2.27.1-1.el7.x86_64                                                                                                                      3/6 
  Installing : 1:docker-ce-cli-26.1.4-1.el7.x86_64                                                                                                                            4/6 
  Installing : docker-ce-rootless-extras-26.1.4-1.el7.x86_64                                                                                                                  5/6 
  Installing : 3:docker-ce-26.1.4-1.el7.x86_64                                                                                                                                6/6 
  Verifying  : docker-compose-plugin-2.27.1-1.el7.x86_64                                                                                                                      1/6 
  Verifying  : containerd.io-1.6.33-3.1.el7.x86_64                                                                                                                            2/6 
  Verifying  : 3:docker-ce-26.1.4-1.el7.x86_64                                                                                                                                3/6 
  Verifying  : 1:docker-ce-cli-26.1.4-1.el7.x86_64                                                                                                                            4/6 
  Verifying  : docker-ce-rootless-extras-26.1.4-1.el7.x86_64                                                                                                                  5/6 
  Verifying  : docker-buildx-plugin-0.14.1-1.el7.x86_64                                                                                                                       6/6 

Installed:
  docker-ce.x86_64 3:26.1.4-1.el7                                                                                                                                                 

Dependency Installed:
  containerd.io.x86_64 0:1.6.33-3.1.el7        docker-buildx-plugin.x86_64 0:0.14.1-1.el7  docker-ce-cli.x86_64 1:26.1.4-1.el7  docker-ce-rootless-extras.x86_64 0:26.1.4-1.el7 
  docker-compose-plugin.x86_64 0:2.27.1-1.el7 

Complete!
  • 设置docker
[root@instance-20210526-1514 ~]# docker version 				 # 查看更新后的版本
Client: Docker Engine - Community
 Version:           26.1.4
 API version:       1.45
 Go version:        go1.21.11
 Git commit:        5650f9b
 Built:             Wed Jun  5 11:32:04 2024
 OS/Arch:           linux/amd64
 Context:           default
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
[root@instance-20210526-1514 ~]# systemctl start docker 		# 启动docker服务
[root@instance-20210526-1514 ~]# systemctl enable docker  		# 设置为开机服务
Created symlink from /etc/systemd/system/multi-user.target.wants/docker.service to /usr/lib/systemd/system/docker.service.
[root@instance-20210526-1514 ~]# docker version
Client: Docker Engine - Community
 Version:           26.1.4
 API version:       1.45
 Go version:        go1.21.11
 Git commit:        5650f9b
 Built:             Wed Jun  5 11:32:04 2024
 OS/Arch:           linux/amd64
 Context:           default

Server: Docker Engine - Community
 Engine:
  Version:          26.1.4
  API version:      1.45 (minimum version 1.24)
  Go version:       go1.21.11
  Git commit:       de5c9cf
  Built:            Wed Jun  5 11:31:02 2024
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.6.33
  GitCommit:        d2d58213f83a351ca8f528a95fbd145f5654e957
 runc:
  Version:          1.1.12
  GitCommit:        v1.1.12-0-g51d5e94
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0
  • 安装docker-compose
[root@instance-20210526-1514 ~]# curl -L "https://github.com/docker/compose/releases/download/v2.18.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/bin/docker-compose
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
100 52.0M  100 52.0M    0     0  6025k      0  0:00:08  0:00:08 --:--:-- 5873k
[root@instance-20210526-1514 ~]# sudo chmod +x /usr/bin/docker-compose
[ghost@instance-20210526-1514 certbot]$ docker-compose version
Docker Compose version v2.18.1
  • 卸载清理docker 
有可能你的服务器已经有docker和一些残留容器,需要手动清理
------------------卸载docker和docker-compose-----------------
[root@instance-20210526-1514 ~]# yum list installed | grep docker   # 查看docker的本地版本
docker.x86_64                      2:1.13.1-210.git7d71120.el7.centos  @extras  
docker-client.x86_64               2:1.13.1-210.git7d71120.el7.centos  @extras  
docker-common.x86_64               2:1.13.1-210.git7d71120.el7.centos  @extras  
docker-compose.noarch              1.18.0-4.el7                        @epel    
python36-docker.noarch             2.6.1-3.el7                         @epel    
python36-docker-pycreds.noarch     0.2.1-2.el7                         @epel    
python36-dockerpty.noarch          0.4.1-18.el7                        @epel   
[root@instance-20210526-1514 ~]# yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine docker-compose  # 卸载
Loaded plugins: fastestmirror, langpacks, product-id, search-disabled-repos, subscription-manager
You need to be root to perform this command.
[ghost@instance-20210526-1514 certbot]$ sudo yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine
Loaded plugins: fastestmirror, langpacks, product-id, search-disabled-repos, subscription-manager

This system is not registered with an entitlement server. You can use subscription-manager to register.

No Match for argument: docker-client-latest
No Match for argument: docker-latest
No Match for argument: docker-latest-logrotate
No Match for argument: docker-logrotate
No Match for argument: docker-engine
Resolving Dependencies
--> Running transaction check
---> Package docker.x86_64 2:1.13.1-210.git7d71120.el7.centos will be erased
---> Package docker-client.x86_64 2:1.13.1-210.git7d71120.el7.centos will be erased
---> Package docker-common.x86_64 2:1.13.1-210.git7d71120.el7.centos will be erased
--> Finished Dependency Resolution

Dependencies Resolved

===========================================================================================================================================================
 Package                            Arch                        Version                                                 Repository                    Size
===========================================================================================================================================================
Removing:
 docker                             x86_64                      2:1.13.1-210.git7d71120.el7.centos                      @extras                       64 M
 docker-client                      x86_64                      2:1.13.1-210.git7d71120.el7.centos                      @extras                       13 M
 docker-common                      x86_64                      2:1.13.1-210.git7d71120.el7.centos                      @extras                      4.4 k

Transaction Summary
===========================================================================================================================================================
Remove  3 Packages

Installed size: 76 M
Is this ok [y/N]: y
Downloading packages:
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
  Erasing    : 2:docker-1.13.1-210.git7d71120.el7.centos.x86_64                                                                                        1/3 
warning: /etc/sysconfig/docker-storage saved as /etc/sysconfig/docker-storage.rpmsave
  Erasing    : 2:docker-client-1.13.1-210.git7d71120.el7.centos.x86_64                                                                                 2/3 
  Erasing    : 2:docker-common-1.13.1-210.git7d71120.el7.centos.x86_64                                                                                 3/3 
  Verifying  : 2:docker-client-1.13.1-210.git7d71120.el7.centos.x86_64                                                                                 1/3 
  Verifying  : 2:docker-common-1.13.1-210.git7d71120.el7.centos.x86_64                                                                                 2/3 
  Verifying  : 2:docker-1.13.1-210.git7d71120.el7.centos.x86_64                                                                                        3/3 

Removed:
  docker.x86_64 2:1.13.1-210.git7d71120.el7.centos                             docker-client.x86_64 2:1.13.1-210.git7d71120.el7.centos                     
  docker-common.x86_64 2:1.13.1-210.git7d71120.el7.centos                     

Complete!
[root@instance-20210526-1514 ~]# docker version   			# 验证卸载成功
[root@instance-20210526-1514 ~]# yum remove docker-compose
[root@instance-20210526-1514 ~]# docker-compose version

------------------关闭docker实例-----------------

执行:docker-compose down停掉容器
报错:docker-compose down validating /www/certbot/docker-compose.yml: (root) Additional property certbot is not allowed
解决:这是旧版yml配置写法与新版docker-compose不兼容导致,根据 docker-compose 的标准,所有服务应该放在 services 下。
报错:docker-compose down validating /www/ghost/docker-compose.yml: services.ghost Additional property net is not allowed
解决:新版不支持net属性标签,改为networks,并且值为换行的- net_name
报错:docker-compose down service "ghost" refers to undefined network ghost_net: invalid compose project
解决:如果ghost_net已经存在,则需要定义一下服务节点“networks: ghost_net: external: true”

创建docker网络

[ghost@instance-20210526-1514 ~]$ docker network create ghost_net
6622eb06ad225655bf8b680a0de93825413ad8569b98d2ba0bc7cf60fb5b752b
[ghost@instance-20210526-1514 ghost]$ docker network ls
NETWORK ID NAME DRIVER SCOPE
8dce76598c2e bridge bridge local
179cc6d32121 certbot_default bridge local
3ba098121ff5 ghost_net bridge local
67fca2971343 host host local
d837e32119cb none null local

配置ghost的映射目录和博客配置文件

  • 宿主机目录将用于映射到容器里被读写,做到程序和数据分离
[ghost@instance-20210526-1514 ghost]$ mkdir -p data/var/lib/ghost/content
[ghost@instance-20210526-1514 ghost]$ mkdir -p data/var/lib/ghost/current/content
[ghost@instance-20210526-1514 ghost]$ cat data/var/lib/ghost/config.production.json  # 这个文件可以在容器启动生成后修改
{
  "url": "https://ghost.atibm.com/", 
  "server": {
    "port": 2368,	
    "host": "0.0.0.0"	
  },
  "database": {
    "client": "sqlite3",
    "connection": {
      "filename": "/var/lib/ghost/content/data/ghost.db"
    }
  },
  "logging": {
    "transports": [
      "file",
      "stdout"
    ]
  },
  "process": "systemd",
  "paths": {
    "contentPath": "/var/lib/ghost/content"
  }
}

创建运行ghost容器

[ghost@instance-20210526-1514 nginx]$ cat /www/ghost/docker-compose.yml
version: '3.8'

services:
  ghost:
    container_name: ghost
    restart: unless-stopped
    image: ghost:5.30.0 #4.24.0 # 4.5.0
    #privileged: true
    networks: 
      - ghost_net
    volumes:
      - /www/ghost/data/config.production.json:/var/lib/ghost/config.production.json
      - /www/ghost/data/content:/var/lib/ghost/content
      - /www/ghost/data/currentcontent:/var/lib/ghost/current/content

networks:
  ghost_net:
    external: true
  • 启动ghost容器
[ghost@instance-20210526-1514 ghost]$ docker-compose up -d
[+] Building 0.0s (0/0)                                                                                                                                    
[+] Running 1/1
 ✔ Container ghost  Started                                                                                                                           1.9s 
[ghost@instance-20210526-1514 ghost]$ docker-compose logs
ghost  | [2024-06-12 02:06:35] INFO Ghost is running in production...
ghost  | [2024-06-12 02:06:35] INFO Your site is now available on https://ghost.atibm.com/
ghost  | [2024-06-12 02:06:35] INFO Ctrl+C to shut down
ghost  | [2024-06-12 02:06:35] INFO Ghost server started in 4.068s
ghost  | [2024-06-12 02:06:37] INFO Database is in a ready state.
ghost  | [2024-06-12 02:06:37] INFO Ghost database ready in 5.194s

配置nginx映射目录和代理配置文件

[ghost@instance-20210526-1514 ~]$ cd /www/nginx
[ghost@instance-20210526-1514 nginx]$ cat data/nginx.conf  # 映射的nginx配置文件
user  nginx;
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;
    default_type  application/octet-stream;

    log_format  main  '\$remote_addr - \$remote_user [\$time_local] "\$request" '
                      '\$status \$body_bytes_sent "\$http_referer" '
                      '"\$http_user_agent" "\$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

    #gzip  on;

    include /etc/nginx/conf.d/*.conf;
}

[ghost@instance-20210526-1514 nginx]$ cat data/conf.d/default.conf  # 映射的代理配置模板文件
server {
    listen       80;
    #server_name  localhost;
    server_name localhost nginx.atibm.com;

    #charset koi8-r;
    #access_log  /var/log/nginx/host.access.log  main;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    #error_page  404              /404.html;

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    # proxy the PHP scripts to Apache listening on 127.0.0.1:80
    #
    #location ~ \.php$ {
    #    proxy_pass   http://127.0.0.1;
    #}

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #
    #location ~ \.php$ {
    #    root           html;
    #    fastcgi_pass   127.0.0.1:9000;
    #    fastcgi_index  index.php;
    #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
    #    include        fastcgi_params;
    #}

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    #location ~ /\.ht {
    #    deny  all;
    #}

    # Let's encrypt 
    location ^~ /.well-known/acme-challenge/ {
        root    /usr/share/nginx/html;
    }

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

}

[ghost@instance-20210526-1514 nginx]$ cat data/conf.d/ghost.conf  # 映射的ghost博客代理配置文件
# redirect all http traffic to https
server {
    listen 80;
    server_name ghost.atibm.com atibm.com www.atibm.com;
    # google adsense ads.txt
    location /ads.txt {
        alias /usr/share/nginx/html/ghost/ads.txt;
    }
    return 301 https://$host$request_uri;
}
# redirect some domain https traffic to https://ghost.atibm.com
server {
    listen 443 ssl;
    server_name atibm.com www.atibm.com;    
    ssl_certificate /etc/letsencrypt/live/ghost.atibm.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/ghost.atibm.com/privkey.pem;
    location /ads.txt {
        alias /usr/share/nginx/html/ads.txt;
    }
    return 301 https://ghost.atibm.com$request_uri;
}
# defined ghost.atibm.com 443
server {
    listen 443 ssl;
    server_name ghost.atibm.com;
    ssl_certificate     /etc/letsencrypt/live/ghost.atibm.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/ghost.atibm.com/privkey.pem;
    root /var/lib/ghost/current/core/server/public;
    access_log /var/log/nginx/ghost-access.log main;
    error_log /var/log/nginx/ghost-error.log warn;
    location /ads.txt {
        alias /usr/share/nginx/html/ghost/ads.txt;
    } 
    location / {
        proxy_pass         http://ghost:2368;
        proxy_set_header     Host $host;
        proxy_set_header     X-Real-IP $remote_addr;
        proxy_set_header    X-Forwarded-Proto https;
        proxy_set_header     X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_connect_timeout     150;
        proxy_send_timeout     100;
        proxy_read_timeout    100;
        proxy_buffers        4 32k;
        client_max_body_size    10m;
        client_body_buffer_size    128;    
    }
}

创建运行nginx容器

  • 容器配置文件

[ghost@instance-20210526-1514 nginx]$ cat /www/nginx/docker-compose.yml 
version: '3.8'

services:
  nginx:
    container_name: "nginx"
    image: nginx:1.21.0
    restart: unless-stopped
    #privileged: true
    volumes:
      - ./data/nginx.conf:/etc/nginx/nginx.conf
      - ./data/conf.d:/etc/nginx/conf.d
      - ./data/html:/usr/share/nginx/html
      - ./data/logs:/var/log/nginx
      - /www/certbot/data/letsencrypt:/etc/letsencrypt
    networks: [ghost_net]
    ports:
      - "80:80"
      - "443:443"
    environment:
      - NGINX_HOST=nginx.atibm.com
      - NGINX_PORT=80

networks:
  ghost_net:
    external: true
  • 启动nginx容器
[ghost@instance-20210526-1514 nginx]$ docker-compose up -d
[+] Building 0.0s (0/0)                                                                                                                                    
[+] Running 1/1
 ✔ Container nginx  Started   

创建运行certbot容器,并更新证书

  • 流程说明
    用certbot docker -> 通过certbot certonly命令 -> 用邮箱向letsencrypt.org申请更新 -> 配合域名TXT验证记录 -> 获得证书文件 -> nginx配置读取证书文件 -> 访问https://ghost博客成功
[ghost@instance-20210526-1514 ~]$ cd /www/certbot/
# 容器配置文件
[ghost@instance-20210526-1514 certbot]$ cat /www/certbot/docker-compose.yml 
version: '3.8'

services:
  certbot:
    container_name: "certbot"
    image: certbot/certbot:v1.14.0
    restart: unless-stopped    
    tty: true
    stdin_open: true
    volumes:
      - ./data/letsencrypt:/etc/letsencrypt # 证书持久化
      - ./data/backup:/var/lib/letsencrypt/backup
      - ./data/cron-root:/etc/crontabs/root # 证书更新任务每周
      - ./data/certbot-renew.log:/var/log/certbot-renew.log # 证书更新任务的执行日志
    entrypoint: "/bin/sh" # 必须使用 entrypoint 而不是 command, 以重写 certbot image 的 entrypoint
    
# 创建运行certbot容器
[ghost@instance-20210526-1514 certbot]$ docker-compose up -d

# 进入容器
[ghost@instance-20210526-1514 certbot]$ docker-compose exec certbot sh
/opt/certbot #
# 查看证书有效期
/opt/certbot # certbot certificates
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Found the following certs:
  Certificate Name: ghost.atibm.com
    Serial Number: 336402f715a5e2e8d9a37e60f3ef22bebdc
    Key Type: RSA
    Domains: ghost.atibm.com
    Expiry Date: 2021-08-25 04:34:08+00:00 (VALID: 29 days)
    Certificate Path: /etc/letsencrypt/live/ghost.atibm.com/fullchain.pem
    Private Key Path: /etc/letsencrypt/live/ghost.atibm.com/privkey.pem
  Certificate Name: ghost.atibm.com
    Serial Number: 4dc16882a468e352fe437d1e10c0bae5bf7
    Key Type: RSA
    Domains: ghost.atibm.com
    Expiry Date: 2021-08-25 23:53:11+00:00 (VALID: 29 days)
    Certificate Path: /etc/letsencrypt/live/ghost.atibm.com/fullchain.pem
    Private Key Path: /etc/letsencrypt/live/ghost.atibm.com/privkey.pem
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

  • 更新你的域名证书
[ghost@instance-20210526-1514 certbot]$ docker-compose exec certbot sh
# 这句命令的效果是申请4个域名到一个证书里,按提示输入你的邮箱,能收件就行。
/opt/certbot # certbot certonly --cert-name ghost.atibm.com -d ghost.atibm.com -d atibm.com -d www.atibm.com -d trilium.atibm.com  -d triliumcn.atibm.com --preferred-challenges dns --server https://acme-v02.api.letsencrypt.org/directory --manual

Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator manual, Installer None
Enter email address (used for urgent renewal and security notices)
 (Enter 'c' to cancel): youraccount@mail.com

...
Account registered.
Requesting a certificate for ghost.atibm.com and 4 more domains
Performing the following challenges:
dns-01 challenge for atibm.com
dns-01 challenge for ghost.atibm.com
dns-01 challenge for trilium.atibm.com
dns-01 challenge for triliumcn.atibm.com
dns-01 challenge for www.atibm.com

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please deploy a DNS TXT record under the name
_acme-challenge.atibm.com with the following value:

0j_CAdI8yxRO2yQRmm4pFeyz2bvqdQNJmb4Hc65nAII

Before continuing, verify the record is deployed.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Press Enter to Continue

# 到这一步先别往下,停住,把这串编码,添加到你的域名txt记录里
# txt _acme-challenge.atibm.com 0j_CAdI8yxRO2yQRmm4pFeyz2bvqdQNJmb4Hc65nAII
# 如果登录域名管理后台也能完成操作,但我使用api token调用完成
# 再开一个新的VPS终端连接,进行操作
# 需要用到 dns-lexicon包,容器没销毁之前,安装一次就行
/opt/certbot # pip install dns-lexicon
/opt/certbot # lexicon namecom create atibm.com TXT --name _acme-challenge --content 0j_CAdI8yxRO2yQRmm4pFeyz2bvqdQNJmb4Hc65nAII --auth-username 域名网站的登录帐号 --auth-token 这里是你域名商提供的api_token

# 如果添加成功,会显示以下信息
RESULT
---------
246028402

# 刚才那个证书申请界面,可以继续了,会提示成功如下
Cleaning up challenges
Subscribe to the EFF mailing list (email: xxx@xxx.xxx).

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/ghost.atibm.com/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/ghost.atibm.com/privkey.pem
   Your certificate will expire on 2024-09-10. To obtain a new or
   tweaked version of this certificate in the future, simply run
   certbot again. To non-interactively renew *all* of your
   certificates, run "certbot renew"
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le
   

# dns记录销毁
/opt/certbot # lexicon namecom delete atibm.com TXT --name _acme-challenge --auth-username 域名网站的登录帐号 --auth-token 这里是你域名商提供的api_token
  • 到这一步,nginx已经能访问证书文件,并且也能处理你的博客访问,需要刷新一下配置

/opt/certbot # exit          #从certbot容器退出,回到宿主机
[ghost@instance-20210526-1514 certbot]$ docker exec nginx nginx -s reload
  • 后续证书到期之前,会有邮件通知你,进certbot容器更新一下就行了

/opt/certbot # certbot renew
Saving debug log to /var/log/letsencrypt/letsencrypt.log

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/ghost.atibm.com.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cert not yet due for renewal

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
The following certificates are not due for renewal yet:
  /etc/letsencrypt/live/ghost.atibm.com/fullchain.pem expires on 2024-09-10 (skipped)
No renewals were attempted.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# 定时任务更新证书 - 不支持manual模式,需要standalone或web模式,这个我没弄好

# 增加定时任务,每周尝试更新正式(前提是certbot已经定义了域名证书文件,renew才能有效,证书会在到期30天可以续订更新证书)

/opt/certbot # crontab -e
# do daily/weekly/monthly maintenance
# min   hour    day     month   weekday command
5       2       *       *       0       certbot renew --quiet >> /var/log/certbot-renew.log 2>&1
# 手动更新证书 - 利用域名商的api接口,执行命令
--------同时开3个窗口 之 手动续期1/3 ----------
[ghost@instance-20210526-1514 certbot]$ docker-compose exec certbot sh
# 申请多个域名的新证书
/opt/certbot # certbot certonly --cert-name ghost.atibm.com -d ghost.atibm.com -d atibm.com -d www.atibm.com -d trilium.atibm.com -d test.atibm.com --preferred-challenges dns --server https://acme-v02.api.letsencrypt.org/directory --manual
# 扩展新域名证书
/opt/certbot # certbot certonly --cert-name ghost.atibm.com --expand -d ghost.atibm.com -d atibm.com -d www.atibm.com -d trilium.atibm.com -d test.atibm.com --preferred-challenges dns --server https://acme-v02.api.letsencrypt.org/directory --manual
...
Please deploy a DNS TXT record under the name
_acme-challenge.www.atibm.com with the following value:

dpZTUssWbUF9kg49W9RgHoZxAkm18G_WG_5Byws4ck8
...


-----dns记录销毁
/opt/certbot # lexicon namecom delete atibm.com TXT --name _acme-challenge --auth-username ATdoit --auth-token yourtoken;lexicon namecom delete atibm.com TXT --name _acme-challenge.www --auth-username ATdoit --auth-token yourtoken;lexicon namecom delete atibm.com TXT --name _acme-challenge.ghost --auth-username ATdoit --auth-token yourtoken;lexicon namecom delete atibm.com TXT --name _acme-challenge.trilium --auth-username ATdoit --auth-token yourtoken;lexicon namecom delete atibm.com TXT --name _acme-challenge.test --auth-username ATdoit --auth-token yourtoken;lexicon namecom delete atibm.com TXT --name _acme-challenge.triliumcn --auth-username ATdoit --auth-token yourtoken;


-------- 同时开3个窗口 之 添加dns记录2/3 ----------
/opt/certbot # pip install dns-lexicon
/opt/certbot # lexicon namecom create atibm.com TXT --name _acme-challenge --content sZOrBtQxdp4Mco33jG42F2Tzs4DK7bX5my-xiyITFTs --auth-username ATdoit --auth-token yourtoken

/opt/certbot # lexicon namecom create atibm.com TXT --name _acme-challenge.ghost --content EHreZqYRd2AtIWHFrbZ-lVwfIbtVjiIwKk9-nfW6QGw --auth-username ATdoit --auth-token yourtoken

/opt/certbot # lexicon namecom create atibm.com TXT --name _acme-challenge.trilium --content Z6CfrmTS47RW8EWKgqZzweIjq_Sgh4ehHKj06sM1jkQ --auth-username ATdoit --auth-token yourtoken

/opt/certbot # lexicon namecom create atibm.com TXT --name _acme-challenge.test --content t6R0lsjDpe9sBPFZ1kpMEx593dUozf2EwhTkX1cES4A --auth-username ATdoit --auth-token yourtoken

/opt/certbot # lexicon namecom create atibm.com TXT --name _acme-challenge.www --content _OWfZX5Z8f11TszICy2Ga2IdAKSCJuFsjJrRkgtzxTg --auth-username ATdoit --auth-token yourtoken



-------- 同时开3个窗口 之 nginx重载3/3 ----------
在certbot里确认,并提示通过后,到宿主机重载
[ghost@instance-20210526-1514 certbot]$ docker exec nginx nginx -s reload

部署完成,访问成功

  • 博客地址:现在我们访问【ghost.atibm.com】
  • IP解析:经过【域名 dns】解析到【服务器】
  • 反向代理:由【服务器 nginx服务】做代理处理,访问内部网络【服务器 docker network:ghost_net】
  • 博客服务:找到并访问【服务器 ghost服务】+【服务器 certbot服务生成的证书文件】,博客数据存储到【ghost容器映射宿主机目录】下,
  • 经过一番折腾,我们实现了代理、程序、数据、证书全部分离,并一起工作,并且后续维护简单,比如升级ghost,备份数据等等。

备份:后续还要编写一键备份脚本,免费实现数据安全
扩展性:当然还可以体验别的网站程序,比如wiki、ss、leanote、trilium等
运维:有了vps挺爽的,可以随便玩,加上docker的易维护,不怕服务器搞坏
服务器:同时也可以在linode再次新增一个实例出来调试,不影响现有网站
linode已经闲置了,感谢支持