发布于

Docker 搭建主流博客平台 WordPress

作者
  • 姓名
    Twitter

前言

本文是 Docker 系列的第三篇文章,基于官方镜像快速搭建主流博客平台 WordPress。原本计划将 Ghost 的安装写到同一篇文章,但由于内容过多,故将 Ghost 博客平台的安装放到下一篇文章中,本站目前使用的是 Ghost。

本站最初使用了目前比较流行的轻量级博客系统 Hexo,以基于本地生成静态文件并同步至服务器的方式运行,运行环境只需要一个 Web 服务器,但其功能过于简单,主题的可定制性也较弱,且大量博客采用其最热门的 Next 主题,千篇一律让人难以满意。

相比较而言,WordPress 等动态博客平台在功能上要强大的多,但相应的运行环境也复杂的多,比如 Wordpress 运行于 PHP + MySQL 环境,Ghost 运行于 Node.js 环境,若手工搭建都有一定学习成本。

但 Docker 的出现让事情变得简单,不需要或只需要少量 Linux 知识,便可以快速搭建起属于自己的动态博客系统,通过本文,就可以实现这一目标。

本文测试环境为 Ubuntu 18.04,仅安装了 Docker 及 Docker Compose,容器只运行了容器管理的 Portainer,下文将不再重复 Docker 的安装等内容,可参考本博客的这篇文章

搭建方式概述

同本系列其他文章一样,我们依旧参考 WordPress 官方 Docker Hub 页面指引进行搭建。

官方镜像为我们提供了两种选择,一种是通过 docker-compose 文件安装(整合 MySQL ),另一种则是连接其他 MySQL,其实本质上这两种方法差异不大,但本文仍然将分成两部分进行解释,读者可自行选择一种跟随安装即可。

为了简化本文内容,对于部分操作可能不会详细描述,推荐读者结合阅读本博客的这篇文章,并使用Portainer或者其他图形化容器管理工具进行容器管理,对于新手而言,部分操作建议直接使用图形化操作,本文会出现很多次容器的删除操作,为简化内容,不再重复 docker stop CONTAINER命令和docker rm CONTAINER命令,用户可自行输入相关命令或者使用图形化管理工具删除。

使用 Docker Compose 搭建

个人比较推荐这种方法,虽然 Docker Compose 看似复杂,但如果对 Docker 有更多了解会发现其实很清晰,而且方便重复使用。

根据官方示例创建 Docker Compose文件

官方提供了 docker-compose.yml 文件示例, 我们只需要将其提供的示例稍作修改即可,如下是 WordPress 官方 Docker Hub 页面所提供的示例:

docker-wordpress-compose-example.png

我们稍作修改即可:

version: '3.1'

services:

  wordpress:
    image: wordpress
    restart: always
    ports:
      - 8080:80
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: mypassword
      WORDPRESS_DB_NAME: wordpress

  db:
    image: mysql:5.7
    restart: always
    environment:
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: mypassword
      MYSQL_RANDOM_ROOT_PASSWORD: '1'

我们需要将以上内容保存为 docker-compose.yml 文件,我习惯于在home文件夹下新建一个docker文件夹,存放各个应用的相关文件:

mkdir -p ~/docker/wordpress
cd ~/docker/wordpress

之后通过 Vim 来创建 docker-compose.yml 文件并将上面的内容复制进去。

vim docker-compose.yml

运行 Docker Compose 文件

在完成上述工作后,启动docker-compose.yml文件:

docker-compose up -d

如果没有报错,就可以正常启动,可通过docker ps查看各容器的运行情况:

docker-wordpress-compose-up.png

完成 WordPress 的安装

容器正常运行后,在浏览器中输入http://服务器IP:8080即可打开 WordPress 主页,第一次打开需要进行安装:

docker-wordpress-installx1.png

docker-wordpress-installx2.png

docker-wordpress-installx3.png

可以看到,通过这种方法安装,并不需要我们再手动配置数据库相关信息。

至此,我们已经完成了 WordPress 的搭建,但是这还不够,我们还有下面这三个任务:

  • 通过文件绑定或 Volume 来持久化存储容器中用户数据
  • 配置端口转发
  • 配置 SSL 证书实现 HTTPS 访问

在本部分内容中,我们只完成第一个任务,至于配置端口转发以及 SSL 证书这个工作,我们将在完成下一部分另一种 WordPress 搭建方式之后统一进行。

持久化存储用户数据

官方所提供的 docker-compose 文件示例是非常基础的,虽然我们的应用已经正常运行,但应用运行过程中的用户数据我们并未使用 Volume 或者文件绑定的方式存储,所以我们需要对 docker-compose.yml 文件进行完善,我们需要存储的数据包括:

容器需持久化存储内容容器内文件路经宿主机文件路经绑定方式
wordpress应用网页目录/var/www/html~/docker/wordpress/htmlVolume或文件
mysql数据库/var/lib/mysql-Volume

如果有需要持久化存储其他数据,可根据下面的内容自行修改 docker-compose.yml 文件添加。

本人是推荐直接使用 Volume 方式的,但考虑到可能有朋友需要方便修改 WordPress 主题部分文件之类的需求,同时也考虑到示例因素,本部分将为 wordpress 的网页目录提供两种存储方式,供各位参考,以下两种方式仍然是选择其中一种。

只使用 Volume

修改 docker-compose.yml 文件

使用vim修改docker-compose.yml内容,添加Volume相关信息,下面是示例,可自行与前文内容比较。

version: '3.1'

services:

  wordpress:
    image: wordpress
    restart: always
    ports:
      - 8080:80
    volumes:
      - html:/var/www/html  
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: mypassword
      WORDPRESS_DB_NAME: wordpress

  db:
    image: mysql:5.7
    restart: always
    volumes:
      - db:/var/lib/mysql
    environment:
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: mypassword
      MYSQL_RANDOM_ROOT_PASSWORD: '1'
volumes:
  html:
  db:      

需要特别注意内容对齐

重新运行 docker-compose.yml 文件

之后删除之前的容器后,重新运行 docker-compose.yml文件:

docker-compose up -d

如果没有报错就说明一切正常,访问http://服务器IP:8080即可开始安装 WordPress,由于数据已经通过Volume持久存储,现在可以在安装完成 WordPress 后,将容器全部删除,之后再次重新运行docker-compose.yml文件,你会发现之前所设置的一切都还在。

同时使用 Volume 和文件绑定

使用文件绑定的方式是将宿主机中已存在的文件内容挂载到容器中,文件映射的方向是由宿主机到容器,为了保证容器能够正常运行,我们需要将容器中要绑定的文件内容复制到宿主机中。

运行临时 WordPress 容器以复制网页目录内容

由于之前的容器已经进行了安装,我们删除之前的容器,并重新运行 docker-compose.yml 文件

docker-compose up -d

之后我们通过docker cp命令将容器内的/var/www/html复制为宿主机的~/docker/wordpress/html

cd ~/docker/wordpress  #如果未建立该文件夹自行mkdir创建
docker cp  wordpress_wordpress_1:/var/www/html .   #注意最后的.表示当前目录

命令完成后可通过ls命令确认已经复制成功。

修改 docker-compose.yml 文件

同样使用vim修改docker-compose.yml内容,添加卷和文件绑定相关信息,下面是示例,可自行与前文内容比较。

version: '3.1'

services:

  wordpress:
    image: wordpress
    restart: always
    ports:
      - 8080:80
    volumes:
      - ~/docker/wordpress/html:/var/www/html  
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: mypassword
      WORDPRESS_DB_NAME: wordpress

  db:
    image: mysql:5.7
    restart: always
    volumes:
      - db:/var/lib/mysql
    environment:
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: mypassword
      MYSQL_RANDOM_ROOT_PASSWORD: '1'
volumes:
  html:
  db:      
重新运行 docker-compose.yml 文件

之后删除之前的容器后,重新运行 docker-compose.yml文件:

docker-compose up -d

如果没有报错就说明一切正常,访问http://服务器IP:8080即可开始安装 WordPress,由于数据已经持久存储,现在可以在安装完成 WordPress 后,将容器全部删除,之后再次重新运行docker-compose.yml文件,你会发现之前所设置的一切都还在。


分别运行 WordPress 和 MySQL 方式

这种方法的优点就是直观,三行代码运行三个容器后进行简单配置就可以完成安装,而且将数据库独立出来也符合很多场景,这种方式的基本流程如下:

  • 运行 MySQL 容器
  • 运行 phpMyAdmin 容器
  • 运行 WordPress 容器
  • 创建子网并将三个容器加入子网(实现容器名通信)
  • 使用 phpMyAdmin 连接 MySQL 并创建 wordpress 数据库
  • 运行 WordPress 安装程序完成安装

下面是具体步骤。

运行 MySQL 容器

注意:这里并不一定需要使用容器,用户可以使用宿主机已经存在的 MySQL 甚至外部 MySQL 服务器,只要能够连接即可。

docker run --name mysql -e MYSQL_ROOT_PASSWORD=root -d -p 3306:3306  mysql:5.7

请自行修改 root 密码,根据需要选择 MySQL 版本,这里使用的是5.7版本。

运行 phpMyAdmin 容器

phpMyAdmin 是专业的 MySQL 图形化管理程序,同样是基于 PHP,其官方提供的容器非常方便易用,我们搭建一个 phpMyAdmin 用于管理 MySQL 数据库,在后续的步骤中我们需要使用 phpMyAdmin 来为 WordPress 创建数据库。

docker run --name phpmyadmin -d -e PMA_ARBITRARY=1 -p 8081:80 phpmyadmin/phpmyadmin

这里使用了宿主机的8081端口,可以根据自己喜好修改。

我们使用了参数 PMA_ARBITRARY=1, 这将在 phpMyAdmin 登录界面上提供单独的服务器地址栏。各参数作用可以参考其官方 Docker Hub 页面

待容器启动后,访问 http://服务器IP:8081 即可进入 phpMyAdmin 登录界面,如下图:

docker-wordpress-phpmyadmin1.png

运行 WordPress 容器

官方针对不同需求提供了很多镜像,我们直接使用最新镜像latest(实际上下面的:latest可以省略),从 Dockerfile 说明上我们可以了解到这一镜像使用的是PHP7.2以及 Apache ,具体可以查看官方 Docker Hub 页面Tags 说明。

docker run --name wordpress -p 8080:80 -d wordpress:latest

这里我们映射了宿主机的8080端口,可以自行修改。

创建自定义子网并加入

增加这一步骤是为了方便各容器之间直接使用容器名通信,官方 Docker Hub 页面中使用了 --link,而 Docker 官方不推荐使用这一功能,因此我们采用官方推荐的自定义子网来实现。

步骤如下:

  • 创建自定义子网 wordpress
docker network create wordpress 

这里的 wordpress 可以根据喜好修改

  • 将各容器加入子网 wordpress
docker network connect wordpress mysql
docker network connect wordpress phpmyadmin
docker network connect wordpress wordpress

使用 phpMyAdmin 创建数据库

完成了上面的所有工作后,下一步需要我们手动为 WordPress 创建一个数据库,我们通过 phpMyAdmin 连接 MySQL 并创建一个名为 wordpress 的数据库:

在浏览器中打开 phpMyAdmin 地址,如上文,地址为 http://服务器IP:8081:

docker-wordpress-phpmyadmin2.png

需要注意的是,因为我们在前面将各容器加入了同一自定义子网,因此可以直接通过容器名进行通信,如果你省略了上面步骤,需要在这里填写 MySQL 服务器的 IP 地址,这一地址可以通过 docker inspect mysql 获得。可以参考本博客的这篇文章中的前置知识。

docker-wordpress-phpmyadmin3.png

如上图,创建一个名为 wordpress 的数据库,请注意选择右则的排序规则为utf8_general_ci

在完成了这一步之后,就可以开始 WordPress 的安装过程了。

运行 WordPress 安装程序

如上文示,我们映射了宿主机的8080端口,所以我们访问 http://服务器IP:8080 即可访问 WordPress 网站,第一次访问时自动开始安装过程:

docker-wordpress-install1.png

docker-wordpress-install2.png

docker-wordpress-install3.png

请注意上图我们填写的内容,数据库名即为我们通过 phpMyAdmin 创建的数据库名,用户名和密码则为 MySQL 的用户名和密码(这里是测试环境,故密码直接使用的 root,切勿模仿),数据库主机同样是由于我们已经将各容器加入了同一自定义子网故直接填写了 mysql 。

之后点击提交即可,后面就是配置网站名称,管理员用户名密码等,自行设置即可。

docker-wordpress-install4.png

docker-wordpress-install5.png

docker-wordpress-install6.png

到这里我们便完成了 WordPress的安装,但尽管如此,我们并未将用户数据进行持久存储,参考第一种方法,我们将 WordPress 网站目录和 MySQL 数据库进行持久化存储。

持久化存储用户数据

简单起见,我们使用volume来进行数据持久化存储,如果想要通过文件绑定的方式,可以参考本文第一部分中的此部分内容。

要实现用户数据的持久化存储,只需要在运行容器时,使用-v命令即可,我们需要删除前文所创建的wordpress容器和mysql容器,并使用卷wordpress_htmlmysql_db来分别存储wordpress网站目录和mysql数据库。

卷的名称可以自行修改,根据自己的喜好和方便修改即可,这里采用这两个名字仅仅是因为已经使用太多wordpress和mysql了,担心读者搞混

重新运行 MySQL 容器

和本文的其他部分一样,删除容器自行通过 Portainer 或命令行操作,不再重复命令

删除原 mysql 容器后使用以下命令运行容器:

docker run --name mysql -v mysql_db:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=root -d -p 3306:3306  mysql:5.7

可以通过\来多行输入,比较直观,但要注意不要在行尾添加多余空格:

docker run -d --name mysql \
-v mysql_db:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=root \
-p 3306:3306 \
mysql:5.7

重新运行 WordPress 容器

删除原 wordpress 容器后使用以下命令运行容器:

docker run --name wordpress -v wordpress_html:/var/www/html -p 8080:80 -d wordpress:latest

或者:

docker run -d --name wordpress \
-v wordpress_html:/var/www/html \
-p 8080:80 \
wordpress:latest

将重新创建的容器加入自定义子网

这也提示了一个问题,重新创建容器后需要手动将其添加到自定义子网,除下面提供的命令行外,也可直接使用 Portainer 操作

docker network connect wordpress mysql
docker network connect wordpress wordpress

到此为止,数据持久化存储的工作已经完成,有其他数据需要存储的可以自行根据上面内容添加,另外,由于我们删除并重新创建了 MySQL 容器和 WordPress 容器,之前未对用户数据进行持久化存储,因此我们现在需要重新回到前面使用 phpMyAdmin 创建数据库部分开始重新创建数据库并安装 WordPress,不再重复。

后续我们将简单的说明一下端口转发以及 SSL 证书配置。


SSL 证书以及端口转发配置

无论是使用的是本文所提供的第一种方式还是第二种方式,看到这里的朋友应该都已经完成了搭建,目前我们已经可以通过http://服务器IP:8080这一地址访问网站了,但这显然无法满足真正的需求,我们要实现的是通过https://www.yourdomain.com之类的域名进行访问,本部分将简单说明实现方法。

在本系列文章的上一篇《Docker 搭建私有云 Nextcloud》中,已经比较详细的说明了 SSL 证书的申请配置以及端口转发设置,本部分将不再重复相关内容。

SSL 证书申请

可直接访问本博客的上一篇文章,若有不明白的地方可以通过评论的方式提问即可。

Web服务器安装

进行端口转发需要安装 Web 服务器,这里我们使用 Nginx,如果你未安装,我推荐你使用 Docker 快速搭建一个,推荐参考本博客的相关文章搭建,请参考这篇文章

需要注意的是我们需要增加 SSL 证书文件夹的绑定:

docker run -d --name nginx \
-v /root/docker/nginx:/etc/nginx \
-v /root/wwwroot:/usr/share/nginx/html \
-v /etc/letsencrypt:/etc/letsencrypt \
-p 80:80 \
-p 443:443 \
nginx

配置 SSL 证书和端口转发

配置 Nginx

在这里我们假设你使用了Certbot来申请证书,证书位置为默认的/etc/letsencrypt/下,并将其与 Nginx 容器相同目录进行了绑定(即完全参考了本博客提供的方法)

在 Nginx 配置目录下添加 yourdomain.com.conf文件,参考配置如下:

server {
       listen 443 ssl http2;
       server_name www.yourdomain.com;
       ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
       ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
       ssl_trusted_certificate  /etc/letsencrypt/live/yourdomain.com/chain.pem;
       ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
       ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4:!DH:!DHE;
                ssl_prefer_server_ciphers on;
                ssl_session_cache shared:SSL:10m;
                ssl_session_timeout 30m;
       add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";

    location / {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_pass http://服务器IP:8080;
    }
}

需要注意的是,其中proxy_set_header X-Forwarded-Proto $scheme很关键,这是避免内部apache和外部nginx之间通信导致异常。

保存文件后,重启 Nginx 容器即可。

docker restart nginx

以上内容在第一种方法中测试通过,但在第二种方法中会出现问题,无法读取HTTPS链接下的资源导致混合内容报错,使页面显示不正常,下面进行解决。

解决第二种方法会出现的问题

如果你使用 Docker Compose 的方式,按照前面的步骤将已经可以通过https://www.yourdomain.com访问网站,不需要再阅读本部分内容

我们需要先通过访问http://服务器IP:8080完成安装后进入管理后台,修改WordPress站点地址:

docker-wordpress-https.png

之后,我们还需要修改wp-config.php,在文件中添加以下内容:

if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https') {
        $_SERVER['HTTPS'] = 'on';
}

保存退出即可,再次通过https://www.yourdomain.com访问网站就已经能够正常访问了。

至于修改wp-config.php文件的方式,这里还是啰嗦一下:

该文件位于 WordPress 网站目录根目录下,如果是采用文件夹绑定的方式,直接在宿主机找 WordPress 的网站目录就可以,如果是通过 volume 卷保存的,则在宿主机中访问该 volume 保存的位置,所有容器卷的默认存储位置为var/lib/docker/volumes,比如我们之前创建了一个 wordpress_html 的卷,其文件位置则为var/lib/docker/volumes/wordpress_html/_data,可以通过 Portainer 管理界面查看,或者通过 docker inspect命令来查看,如:

docker inspect wordpress | grep 'Source'

根据最新的安装体验来看,这一步可能已经不再需要了。


进阶内容

这部分内容主要解决使用过程中可能会出现的问题,目前已知问题包括:

  • 部分配置下可能无法通过后台管理界面自动升级
  • 部分 WordPress 插件可能会提示缺少 PHP 插件

该部分内容待后续补充。

脱水版本

待补充。