如何使用 Docker 在同一服务器上自托管多个 WordPress 站点

安装 WordPress 没什么大不了的。 您可以使用 LAMP 服务器安装它以进行本地开发。 您还可以在面向公众的适当 Linux 服务器上为现实世界部署它。

Cloud 服务器像 锂节点, 数字海洋 etc 还提供了部署预配置了 WordPress 的全新 Linux 服务器的选项。 更容易,对吧?

但是,如果您想在一台服务器上安装多个 WordPress 怎么办?

一种简单的方法是使用类似的服务 服务器飞行员. 它不仅会自动更新您的服务器,还可以让您轻松地在同一台服务器上部署多个 WordPress 实例。

这将花费你更多的钱,如果你不想要,你可以使用 Docker 来部署多个 WordPress 实例。

通过本指南,您将了解如何轻松设置从各自容器运行的双 WordPress 设置并添加更多实例!

先决条件

这不是强制性的,但如果您具备以下条件,本教程将更容易理解:

  • 基本的Linux命令知识
  • Docker的一些知识
  • 对 Docker Compose 的理解

您将在反向代理容器后面部署 WordPress,并带有启用 SSL 的域和子域。

除了上述主题知识外,您还需要以下基础架构要求:

  • 面向公众 Ubuntu Linux 服务器. 您可以使用云服务提供商,例如 锂节点. 具有 1 GB RAM 的 Nano 服务器足以进行此部署。 但如果您计划自托管更多 WordPress 实例,请考虑升级它。
  • 访问您的域/子域及其 DNS 设置
  • Docker 和 Docker Compose 安装在您的 Linux 服务器上。

如果您需要帮助,可以按照我们的指南进行操作:

  • 在 Ubuntu 上安装 Docker
  • 在 Ubuntu 上安装 Docker compose
  • 反向代理 docker 设置

在我们基于使用 Docker 的自托管 Web 应用程序的所有其他教程中,我已经讨论了分别部署 Nginx 容器和 Web 应用程序容器。 然而,这一次,我将使用 Docker Compose 来设置多个 WordPress 容器,所有这些都基于一个 yml 文件。

所以这也是一个 example 向您展示如何通过单个 Docker Compose 文件将 Nginx 配置与您考虑部署的 Web 应用程序集成。

我会用 domain.com 作为一个 example 对于第一个 WordPress 博客和 wordpress.domain.com 作为第二个自托管博客。 最后,我还将描述如何根据我将在此处讨论的配置添加更多 WordPress 实例。

创建一个目录并使其处于活动状态。 让我们称之为 multi-wordpress.

mkdir multi-wordpress

然后使用 cd 命令切换到这个新创建的目录:

cd multi-wordpress

将 WordPress 文件上传限制设置为 512 MB

在这个目录中,我们将存储我们的 uploads.ini 具有必要上传配置的文件,用于上传最大为 512 MB 的文件。 Enter 终端上的以下命令:

[email protected]:~/multi-wordpress$ printf "file_uploads = Onnmemory_limit = 512Mnupload_max_filesize = 512Mnpost_max_size = 512Mnmax_execution_time = 600" > uploads.ini

为 Nginx 设置文件上传限制

作为附加措施,还创建一个名为 client_max_upload_size.conf 并将其保存在同一目录中以挂载到 Nginx 容器。 为此,我将其设置为 1 GB。 这有助于将来配置其他应用程序。

[email protected]:~/multi-wordpress$ printf "client_max_body_size 1G;" > client_max_upload_size.conf

通过 Nginx 进行 WWW 重定向(不需要更新 CNAME)

如果您想在 WordPress 中使用非 www 到 www 重定向,可以在 Linux 服务器上使用 cat 命令设置重定向器:

[email protected]:~/multi-wordpress$ cat >> domain.com
rewrite ^/(.*)$ https://www.domain.com/$1 permanent;

按回车键,然后按 Ctrl+D 保存。 我们没有使用 printf 这里是因为 $1 如上所示,不会保存在文件中。 这可能会导致未来的 URL 问题,因为我们希望重定向在所有情况下都有效。 为了 example, domain.com/test 应始终重定向到 www.domain.com/test.

通过 Nginx 进行非 WWW 重定向(不需要更新 CNAME)

如果您想使用 www 到非 www 重定向,请重复类似的步骤以执行相反的操作:

[email protected]:~/multi-wordpress$ cat >> www.domain.com
rewrite ^/(.*)$ https://domain.com/$1 permanent;

创建外部 Docker 网络

我将使用一个名为 net 对于本教程。 因此,我使用以下命令创建它:

docker network create net

准备单个 Docker Compose 文件以进行部署

具有以下配置的单个内 docker-compose.yml 文件,您可以使用所有六个容器一次性设置所有内容,从反向代理到最后一个 WordPress 容器。 让我们逐个查看它们,然后最终将它们合并到一个文件中:

Nginx 反向代理容器

挂载这两个文件 client_max_upload_size.confwww.domain.com 在只读模式下并指定网络 net 这是手动创建的。

  nginx-proxy:
    image: jwilder/nginx-proxy
    container_name: nginx-proxy
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - html:/usr/share/nginx/html
      - dhparam:/etc/nginx/dhparam
      - vhost:/etc/nginx/vhost.d
      - certs:/etc/nginx/certs:ro
      - /var/run/docker.sock:/tmp/docker.sock:ro
      - ./client_max_upload_size.conf:/etc/nginx/conf.d/client_max_upload_size.conf:ro
      - ./www.domain.com:/etc/nginx/vhost.d/www.domain.com:ro
    labels:
      - "com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy"
    restart: always
    networks:
      - net

Let’s Encrypt SSL 证书的容器

请注意,我使用 rw 为了 certs 体积,不像 ro 在上一节中。 这对于创建 SSL 证书并在生成卷时相应地更新卷至关重要。 此外,为来自 Let’s Encrypt 的通知设置默认电子邮件,并指定相同的“net“ 网络。

  letsencrypt:
    image: jrcs/letsencrypt-nginx-proxy-companion
    container_name: lets-encrypt-proxy-companion
    depends_on:
      - "nginx-proxy"
    volumes:
      - certs:/etc/nginx/certs:rw
      - vhost:/etc/nginx/vhost.d
      - html:/usr/share/nginx/html
      - /var/run/docker.sock:/var/run/docker.sock:ro
    environment:
      DEFAULT_EMAIL: [email protected]
    restart: always
    networks:
      - net

第一个 WordPress 网站的数据库容器

根据官方 WordPress Docker Compose 配置,如下图设置必要的环境变量并指定内部网络(见 mysqldb0 在这里,也用于服务名称和卷名称)。

此网络仅对数据库容器及其对应的 WordPress 容器可见。 当你部署它时,一个 MySQL 将使用如下所示的凭据创建数据库:

  mysqldb0:
    image: mysql:5.7
    environment:
      MYSQL_DATABASE: db0
      MYSQL_USER: db0user
      MYSQL_PASSWORD: secret
      MYSQL_RANDOM_ROOT_PASSWORD: '1'
    volumes:
      - 'mysqldb0:/var/lib/mysql'
    restart: always
    networks:
      - mysqldb0

第一个 WordPress 容器

当您部署 WordPress 容器时,它将使用上一节中指定的数据库配置。 请注意,除了数据库看到的相同内部网络(mysqldb0),这个 WordPress 服务还必须看到 Nginx 网络调用 net 因为它是外部世界的前端应用程序。

  wordpress0:
    image: wordpress:5.8.0-php8.0-apache
    environment:
      WORDPRESS_DB_HOST: mysqldb0
      WORDPRESS_DB_USER: db0user
      WORDPRESS_DB_PASSWORD: secret
      WORDPRESS_DB_NAME: db0
      WORDPRESS_CONFIG_EXTRA: |
        define('AUTOMATIC_UPDATER_DISABLED', true);
      VIRTUAL_HOST: domain.com,www.domain.com
      LETSENCRYPT_HOST: domain.com,www.domain.com
    volumes:
      - 'wordpress0:/var/www/html/wp-content'
      - './uploads.ini:/usr/local/etc/php/conf.d/uploads.ini'
    restart: always
    depends_on:
      - mysqldb0
    networks:
      - mysqldb0
      - net

此时,您已具备设置单个 WordPress 实例的配置。 要进行更多设置,请使用新名称复制步骤 3 和 4。

干得好:

第二个 WordPress 站点的数据库容器

  mysqldb1:
    image: mysql:5.7
    environment:
      MYSQL_DATABASE: db1
      MYSQL_USER: db1user
      MYSQL_PASSWORD: secret
      MYSQL_RANDOM_ROOT_PASSWORD: '1'
    volumes:
      - 'mysqldb1:/var/lib/mysql'
    restart: always
    networks:
      - mysqldb1

第二个 WordPress 容器

  wordpress1:
    image: wordpress:5.8.0-php8.0-apache
    environment:
      WORDPRESS_DB_HOST: mysqldb1
      WORDPRESS_DB_USER: db1user
      WORDPRESS_DB_PASSWORD: secret
      WORDPRESS_DB_NAME: db1
      WORDPRESS_CONFIG_EXTRA: |
        define('AUTOMATIC_UPDATER_DISABLED', true);
      VIRTUAL_HOST: wordpress.domain.com
      LETSENCRYPT_HOST: wordpress.domain.com
    volumes:
      - 'wordpress1:/var/www/html/wp-content'
      - './uploads.ini:/usr/local/etc/php/conf.d/uploads.ini'
    restart: always
    depends_on:
      - mysqldb1
    networks:
      - mysqldb1
      - net

使用您最喜欢的编辑器,创建一个 docker-compose.yml 包含到目前为止讨论的所有内容的文件(附加参数已包含在下面)。 您需要相应地编辑域名和其他凭证数据。 在这里,我使用了 Nano。

nano docker-compose.yml
version: '3.7'
services:
  nginx-proxy:
    image: jwilder/nginx-proxy
    container_name: nginx-proxy
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - html:/usr/share/nginx/html
      - dhparam:/etc/nginx/dhparam
      - vhost:/etc/nginx/vhost.d
      - certs:/etc/nginx/certs:ro
      - /var/run/docker.sock:/tmp/docker.sock:ro
      - ./client_max_upload_size.conf:/etc/nginx/conf.d/client_max_upload_size.conf
      - ./www.domain.com:/etc/nginx/vhost.d/www.domain.com
    labels:
      - "com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy"
    restart: always
    networks:
      - net

  letsencrypt:
    image: jrcs/letsencrypt-nginx-proxy-companion
    container_name: lets-encrypt-proxy-companion
    depends_on:
      - "nginx-proxy"
    volumes:
      - certs:/etc/nginx/certs:rw
      - vhost:/etc/nginx/vhost.d
      - html:/usr/share/nginx/html
      - /var/run/docker.sock:/var/run/docker.sock:ro
    environment:
      DEFAULT_EMAIL: [email protected]
    restart: always
    networks:
      - net

  mysqldb0:
    image: mysql:5.7
    environment:
      MYSQL_DATABASE: db0
      MYSQL_USER: db0user
      MYSQL_PASSWORD: secret
      MYSQL_RANDOM_ROOT_PASSWORD: '1'
    volumes:
      - 'mysqldb0:/var/lib/mysql'
    restart: always
    networks:
      - mysqldb0


  wordpress0:
    image: wordpress:5.8.0-php8.0-apache
    environment:
      WORDPRESS_DB_HOST: mysqldb0
      WORDPRESS_DB_USER: db0user
      WORDPRESS_DB_PASSWORD: secret
      WORDPRESS_DB_NAME: db0
      WORDPRESS_CONFIG_EXTRA: |
        define('AUTOMATIC_UPDATER_DISABLED', true);
      VIRTUAL_HOST: domain.com,www.domain.com
      LETSENCRYPT_HOST: domain.com,www.domain.com
    volumes:
      - 'wordpress0:/var/www/html/wp-content'
      - './uploads.ini:/usr/local/etc/php/conf.d/uploads.ini'
    restart: always
    depends_on:
      - mysqldb0
    networks:
      - mysqldb0
      - net

  mysqldb1:
    image: mysql:5.7
    environment:
      MYSQL_DATABASE: db1
      MYSQL_USER: db1user
      MYSQL_PASSWORD: secret
      MYSQL_RANDOM_ROOT_PASSWORD: '1'
    volumes:
      - 'mysqldb1:/var/lib/mysql'
    restart: always
    networks:
      - mysqldb1


  wordpress1:
    image: wordpress:5.8.0-php8.0-apache
    environment:
      WORDPRESS_DB_HOST: mariadb1
      WORDPRESS_DB_USER: db1user   
      WORDPRESS_DB_PASSWORD: secret
      WORDPRESS_DB_NAME: db1
      WORDPRESS_CONFIG_EXTRA: |
        define('AUTOMATIC_UPDATER_DISABLED', true);
      VIRTUAL_HOST: wordpress.linuxhindi.com
      LETSENCRYPT_HOST: wordpress.linuxhindi.com
    volumes:
      - 'wordpress1:/var/www/html/wp-content'
      - './uploads.ini:/usr/local/etc/php/conf.d/uploads.ini'
    restart: always
    depends_on:
      - mysqldb1
    networks:
      - mysqldb1
      - net

volumes:
  certs:
  html:
  vhost:
  dhparam:
  mysqldb0:
  wordpress0:
  mysqldb1:
  wordpress1:

networks:
  mysqldb0:
    internal: true
  mysqldb1:
    internal: true
  net:
    external: true

请注意,我只为每个数据库及其对应的 WordPress 容器分配了特定的内部网络。 数据库容器不需要看到 Nginx net 网络。 net 仅前端 WordPress 容器需要。

在我们之前关于 Discourse 的文章中,我使用了 --volumes-from 使用的标志 nginx-proxy 容器的体积与 letsencrypt. 以同样的方式,相同标志的等价物是 volumes_from, 移除 Docker 很久以前。 因此,我明确指定了 Nginx 和 Let’s Encrypt 容器内的公共卷 docker-compose.yml 文件——即, 证书, html, 虚拟主机/var/run/docker.sock.

现在,使用以下内容部署设置 docker-compose 来自同一个命令 multi-wordpress 我们一开始创建的目录:

docker-compose up -d

您将得到以下确认:

Creating network "multi-wordpress_mysqldb0" with the default driver
Creating network "multi-wordpress_mysqldb1" with the default driver
Creating volume "multi-wordpress_certs" with default driver
Creating volume "multi-wordpress_html" with default driver
Creating volume "multi-wordpress_vhost" with default driver
Creating volume "multi-wordpress_dhparam" with default driver
Creating volume "multi-wordpress_mysqldb0" with default driver
Creating volume "multi-wordpress_wordpress0" with default driver
Creating volume "multi-wordpress_mysqldb1" with default driver
Creating volume "multi-wordpress_wordpress1" with default driver
Creating multi-wordpress_mysqldb0_1   ... done
Creating nginx-proxy                  ... done
Creating multi-wordpress_mysqldb1_1 ... done
Creating multi-wordpress_wordpress1_1 ... done
Creating multi-wordpress_wordpress0_1 ... done
Creating lets-encrypt-proxy-companion ... done

前两个是内部网络,其次是卷,最后是容器。 我们的外部网络 net 已经存在,因为我在本教程开始时手动创建了它。

稍等片刻。 打开您的 Internet 浏览器并输入 www.domain.com. 它将重定向到 domain.com 你会看到 WordPress 设置向导在等着你:

选择您的首选语言,单击继续并继续声明您的站点管理。

为了 wordpress.domain.com,你会得到同样的结果。 根据现有容器所示的类似语法,您可以通过重复步骤 5(数据库服务)和 6(WordPress 服务)来添加更多 WordPress 站点。 另外,请不要忘记修改 volumesnetworks YAML 文件中的相应部分。

对于每个新站点,都会创建一个新的 WordPress 容器及其对应的 MySQL 数据库容器。 如果您想知道上述 docker-compose.yml 文件的命令行等价物,您可以探索 这里.

维护自托管 WordPress 实例的提示

这里有一些技巧可以帮助您长期维护您的 WordPress 实例:

实时监控 WordPress 日志

如果您想在实时部署时检查 WordPress 容器的日志(比如本教程中描述的第一个),您可以运行:

docker logs -f multi-wordpress_wordpress0_1

如果您想对此部署进行故障排除或了解每个其他相关容器内发生的情况,有效地使用 Docker Logs 可能至关重要:

无需停机即可备份和恢复 WordPress 卷

使用云 + 本地方法,您可以在不停机的情况下备份和恢复 WordPress 卷。

无需停机即可更新 WordPress 容器

随着 --scale 在 Docker Compose 上标记,您可以基于最新版本的 WordPress 创建一个新容器。 完成后,您可以删除旧的。 这导致零停机时间。

希望您发现这篇文章很有用。 如果您有任何想法、反馈或建议要分享,请在下面的评论中告诉我们。