解决因为 SSL 导致的 WordPress 后台无限 Redirect 的问题

silver mercedes benz emblem on blue surface

在使用 CapRover 并配置域名为 HTTPs 域名时,在你访问管理后台时,可能会导致触发Chrome 自己的无限 Redirect 的问题。

之所以出现这个问题,是因为 CapRover 的架构导致的:CapRover 在最外层是一个 Nginx,SSL 证书也是在这一层完成的。而 CapRover 的默认配置,在将请求向后转发时,透传的域名会是不含 HTTPs 的协议标识的,导致 WordPress 认为发来的请求是非加密的。

d2b5ca33bd970f64a6301fa75ae2eb22 18

而 WordPress 识别到你的请求未加密,就会返回 302 让你进入 HTTPS的链接。但新的请求并不会带上 HTTPs 的标识,导致进入无限循环。

解决这个问题的一个简单处理的方式是 — 在你的 wp-config.php 中加入如下代码,来告诉 WordPress,这个请求已经是 HTTPs 保护的了,你直接处理就好。

/* for ssl in docker */

define('FORCE_SSL_LOGIN',true);

define('FORCE_SSL_ADMIN',true);

$_SERVER['HTTPS'] = 'on';
Code language: PHP (php)

CapRover 如何停止服务,并进行硬盘扩容/维护

34456427bc43e44f517b4eece861c6f5

在一开始使用 CapRover 时,我使用的是一个 10 GB 的数据盘,但在部署了诸多应用后,10GB 的数据盘已经无法满足我的需求,于是我就对其进行了扩容,扩容至 20GB。在完成扩容 & 重启后,仍需要执行 Linux 的扩容命令 resize2fs 来扩容硬盘。

但由于 CapRover 中运行的服务跑在这个数据盘上,并没有办法直接在这个数据盘上进行扩容(进程会持续读取文件),因此,需要先将 CapRover 上的服务暂停,暂停后进行扩容,并重新启动服务。

CapRover 底层是使用 Docker Swarm + Nginx 来进行的,因此,我们只需要使用 Docker Swarm 的命令,来停止服务运行即可。

1. 获取服务名称

首先,你需要先获取到当前所有在跑的服务,以便于稍后去暂停。执行 docker service ls 来获取到具体的服务名称。

d2b5ca33bd970f64a6301fa75ae2eb22 13

2. 拼接所需的命令

在 Docker Swarm 当中,并没有直接的 Start or Stop 概念,而是通过将 Replica 设置为 0 来实现关闭的能力。这个命令可以通过 docker service scale 服务名=服务数 来实现。因此,你需要将对应的服务设置为 0 来解决这个问题。你可以先行把开启和停止的命令拼接好,从而实现快速的启动和关闭,尽可能的减少宕机时间。

如果是有多个服务,可以直接拼接在后面,从而实现一次关闭 / 开启多个服务。

# docker service scale service_name=1 service_name_2=0
# 停止命令
docker service scale srv-captain--blog-ixiqin-com=0 srv-captain--mysql-8-production-db=0 srv-captain--pgsql-16-production=0 srv-captain--redis-server-production=0
# 启动命令
docker service scale srv-captain--blog-ixiqin-com=1 srv-captain--mysql-8-production-db=1 srv-captain--pgsql-16-production=1 srv-captain--redis-server-production=1
Code language: Bash (bash)

3. 执行命令,扩容硬盘

你可以先执行停止命令,然后执行扩容命令。完成扩容后,重新启动,即可完成整体的扩容。

使用 CapRover WebHook 获得类 Vercel 部署体验

34456427bc43e44f517b4eece861c6f5

我在开发前端应用的时候,基本上使用的都是 Vercel ,究其原因,主要是以下几个点:

  1. Vercel 可以方便的与 Github 整合,提供简单易用的部署方式:写完代码,测试完成后推送到 Github ,就会自动部署到线上。对于小型项目来说,可以简化部署的流程。
  2. Vercel 提供了自定义域名和自动配置的 SSL,提供了简单的配置方式:在现在 SSL 成为标配的模式下,在 Vercel 你只需要把域名解析到 Vercel ,并在你的 Project 当中绑定域名,就会自动完成域名绑定和 SSL 申请和续期。
  3. Vercel 提供了 FaaS 环境:写应用的时候,很多时候不只有前端的需求,这个时候, Vercel 自身的提供的 FaaS 环境可以帮助你完成基本逻辑的编写。

但 Vercel 毕竟是以前端为主,且函数运行时长也有限制,对于一些比较重的场景下,Vercel 还是不太够用。刚好最近我把服务部署从传统的 LAMP 换成了 Docker Based PaaS,我使用的 CapRover 提供了类似的体验。

使用 Cap Rover 你能获得的体验:

  • 上传代码后,自动部署到 Production
  • 绑定域名后,自动配置 SSL 证书,且可以配置其他域名转发到主域名

具体操作步骤见下:

安装 CapRover

CapRover 的安装我就不再赘述,跟随官方的说明安装即可。

绑定根域名

当你登录 CapRover 时,CapRover 会让你绑定一个泛域名解析,你可以根据自己的需要,绑定一个二级或者三级域名,然后在 DNS 解析一个 * 到这个服务器上。这样后续部署的服务就会自动解析一个 服务名.你的域名 ,用于服务的初步访问(类似于 xxx.vercel.app)。

d2b5ca33bd970f64a6301fa75ae2eb22 6

上传代码至 GitHub

在 Github 上创建一个代码仓库,并把你自己的项目部署上去。如果你有已经写好的 Dockerfile,可以一并上传上去。如果没有的话,则可以选择参考 CapRover 提供的 Sample App ,里面提供了常见语言的部署参考。

创建容器并配置环境

完成代码上传后,你可以进入到 CapRover 后台,创建一个新的 App。这里可以输入你喜欢的名字,方便后续查找即可。

d2b5ca33bd970f64a6301fa75ae2eb22 7

创建完成后,点击下方列表中的应用名称,进入应用的配置页面,并切换至 Deployment 页面。

d2b5ca33bd970f64a6301fa75ae2eb22 8

在这个页面,可以找到 Method 3 : Deploy From GitHub/ Bitbucket/Gitlab,填写你的仓库信息、分支名、用户名。密码你可以选择直接使用你的密码,也可以选择创建一个 Personal Access Token ,或者是在仓库里配置一个 Deploy SSH key 均可。

d2b5ca33bd970f64a6301fa75ae2eb22 9

配置完成后,会自动给你生成一个 Webhook 地址,复制这个 Webhook 地址。

d2b5ca33bd970f64a6301fa75ae2eb22 10

配置 Github 上的 WebHook

复制上方的 Webhook 地址,并进入到 Github 你的仓库 – Settings – webhooks 页面,新增一个 Webhook。

d2b5ca33bd970f64a6301fa75ae2eb22 11

粘贴你刚刚复制的 URL,Content Type 选择 application JSON,并在下方选择触发部署的时机。

d2b5ca33bd970f64a6301fa75ae2eb22 12

点击报错。

等待自动部署

接下来你就可以通过提交代码,来让其自动完成部署,从而享受类似于 Vercel 的推送即部署的体验~。

在你的 Github Actions 中添加一个 PostgreSQL 用于测试

black and white penguin toy

在开发应用的时候,我们会选择使用 PostgreSQL 作为数据库进行开发,但在 Github Actions 环境下,默认是没有 PostgreSQL 作为数据库后端的,这个时候如果你想要测试一些和数据库相关的逻辑,就不得不面临两个选择:

  1. 使用一个和生产环境无关的数据库,比如 SQLite。
  2. 在 Github Actions 当中添加一个 PostgreSQL。

前者是大多数常规的做法,大概率也不会出现什么问题(毕竟作为 CURD 仔,我们用的大部分时候都是一些 ORM,很少裸写 SQL),不过依然存在一些概率是你写了一些 PostgreSQL Only 的 Query 无法覆盖到测试。

另外就是本文的核心了:在你的 Github Actions 当中添加一个 PostgreSQL

Github Actions Service

想要实现这个效果,我们依赖了 Github Actions Service Containers 这个能力。

服务容器是 Docker 容器,以简便、可携带的方式托管您可能需要在工作流程中测试或操作应用程序的服务。 例如,您的工作流程可能必须运行需要访问数据库和内存缓存的集成测试。

您可以为工作流程中的每个作业配置服务容器。 GitHub 为工作流中配置的每个服务创建一个新的 Docker 容器,并在作业完成后销毁该服务容器。 作业中的步骤可与属于同一作业的所有服务容器通信。 但是,你不能在组合操作中创建和使用服务容器。

GitHub

你可以选择你需要运行测试的环境中,找到对应的 Job,并在 Job 下新增一个 services ,即可为你的 job 设定一个依赖的服务容器,它可能是数据库 、 缓存之类的。比如我这里用的就是 PostgreSQL。

我的 Github Actions 完整参考:

  • services 是我运行的服务容器。
  • steps 是我的真正的测试流程。
name: Django CI

on:
  push:
    branches: [ "main" ]
  pull_request:
    branches: [ "main" ]

env:
  DEBUG: true
  SECRET_KEY: django-insecure-github-actions
  DB_NAME: postgres
  DB_USER: postgres
  DB_PASSWORD: postgres
  DB_HOST: localhost
  DB_PORT: 5432

jobs:
  build:
    runs-on: ubuntu-latest
    services:
      postgres:
        image: postgres
        env:
          POSTGRES_PASSWORD: postgres
        # Set health checks to wait until postgres has started
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
        ports:
          - 5432:5432

    strategy:
      max-parallel: 4
      matrix:
        python-version: [3.12]

    steps:
    - uses: actions/checkout@v3
    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@v3
      with:
        python-version: ${{ matrix.python-version }}
    - name: Install Dependencies
      run: |
        python -m pip install --upgrade pip
        pip install -r requirements.txt
    - name: Run Tests
      run: |
        python manage.py test
Code language: PHP (php)

在 WordPress 的 Docker 镜像上加装 Redis 拓展,以支持 Redis 缓存

docker

从 LAMP 到 Docker based PaaS 工具 当中,我提到我现在使用的是 Docker Based PaaS 产品来托管站点。本站目前其实就是跑在 Docker 上的。

使用默认的 WordPress 镜像时,我发现一个问题:没有支持 Redis 拓展!我使用 Redis 来缓存 Query,提升访问的性能。如果缺失了 Redis 拓展,就会减少一部分缓存的能力。于是开始研究如何在官方的 WordPress 镜像上加入 Redis 拓展。

根据 WordPress 镜像的官方说明,我们可以 docker-php-ext-* 命令来配置镜像,安装必要的拓展,来满足我们日常使用的需求,并给出了官方的参考。

不过,我在验证 Redis 拓展时,使用 docker-php-ext-* 命令没有配置成功,好在可以使用 pecl 来安装。于是,我便将 Dockerfile 修改成如下内容,来完成对于 Redis 拓展的安装。

FROM wordpress:latest
RUN pecl install -o -f redis && rm -rf /tmp/pear && docker-php-ext-enable redis

修改好 Dockerfile ,然后重新启动,一切都好了~

d2b5ca33bd970f64a6301fa75ae2eb22 4

从 LAMP 到 Docker based PaaS 工具

docker

白宦成简史 当中,我写到过,我从 2013 年就开始写博客,至今已经 11 年有余。而我和互联网、编程的缘分,也从 2013 年开始。

在 2013 年的时候,我主要是使用 WordPress 建站(现在也还在用,比如本站)。所以,从哪个时候开始,我开始接触 LAMP、LNMP 这些个概念,并在过去的若干年里,使用了不少「一键安装包」来部署我的网站。

我用的一键安装包 / 控制面板不算少:LNMP.orgOneInStack(从它还是 LinuxEye 的时候开始用),LAMP.sh等一键配置包,AMHWDCPAppNodeWebminBTVestaCPVirtualmin等等一系列控制面板。

如果说这些工具有什么相同点,那便是都提供了十分方便的 LAMP / LNMP 的配置方式,让彼时不够专业的我、主要是用别人开发好的应用的我能够快速部署一个基于 MySQL + PHP 的应用,让它 Run 起来。

而随着时间的流逝,我已经不再是曾经的我了。我不再局限于使用别人写好的程序,我开始自己写;我不再局限于使用 PHP 来编写程序,我同样会使用 Python、Ruby、Golang 、Node.js 来编写应用程序;所有的这些,都告诉我,我需要在现有的框架和程序上去做很多额外的配置,比如,我需要在 LNMP 的基础之上,配置 NPM,以完成 Node.js 的构建;我需要在系统上配置 Docker ,以便于去运行某些需要复杂配置的环境。

曾经那些可以帮到我的程序已经不再能帮到我了,如今的他们,成了我的累赘。我开始需要为了他们去多做一些事情了。

如今的我,更需要的是一个能够基于 Docker 来运行的管理工具,能够帮助我完成不同环境的配置、管理的能力。我需要的是一个类似于 Heroku 的管理工具,能够让我把更多的精力放在把事做好上。

我试用了

最终,选择了 CapRover ,主要原因有几个:

  1. 支持基础的 Docker 管理功能:这样意味着我其实可以在网页端管理这些资源。
  2. 使用 Nginx ,并集成了 Let’s Encrypt:我的应用都希望有 HTTPs 的能力,所以默认集成了 Let’s Encrypt 可以帮助我解决不少的问题。我也不需要自己去维护一个 Traefik 来解决请求转发的问题(我没有使用 Rancher / Kubesphere 之类的容器管理平台也是这个原因)
  3. 提供了一些一键配置的 Sample:这意味着我把一些我常用的应用迁移过去的时候,可以抄袭一下其官方推荐的配置,可以降低我的使用门槛。
  4. 足够久远:CapRover 作为一个从 2017 年就开始运作的工具,代表着有足够多的 issue 可以供我参考 / 使用,可以减少我踩坑的概率。
  5. 提供了 CLI 来进行部署:对于一个经常需要部署的人来说,提供 CLI / Github Action 可以帮助我快速实现多种不同需求下的部署,帮助我来提升效率。

种种的这些,让我最终从过去的 LNMP,跳船到了 Docker Base PaaS 工具上。

使用 Docked Rails CLI 简化 Rails 的开发

a golden docker logo on a black background

在开发 RoR 的时候,经常需要配置本地的开发环境。但如果你需要在一些云端开发环境(比如 Github Codespaces)中配置你的开发环境时,就会变得比较麻烦。

但得益于 Docker,我们可以直接使用 Docker 镜像来完成我们的开发环境。

Ruby 官方提供了 Docked 来帮助我们完成这个环境的构建。

配置

假设你已经完成了 Docker 的安装,接下来你只需要做如下操作,来配置 Docked Rails Cli

docker volume create ruby-bundle-cache
alias docked='docker run --rm -it -v ${PWD}:/rails -v ruby-bundle-cache:/bundle -p 3000:3000 ghcr.io/rails/cli'
Code language: JavaScript (javascript)

为了方便你的使用,你还可以将上述的输入放在 .bash_rc.bash_profile 当中。

使用

接下来,你只需要使用 docked 你要执行的命令 来执行各种命令,比如官方给出的这样的 Sample。

docked rails new weblog
cd weblog
docked rails generate scaffold post title:string body:text
docked rails db:migrate
docked rails server
Code language: CSS (css)

updates in 2023.12.19

由于官方默认的 docked 没有 PGSQL 的支持,所以我自己 Fork 了一个版本,做了一些更新。

具体可以见 https://github.com/bestony/runs

在 macOS 上使用 Podman 来运行 Docker 环境

docker

Podman 是由 Redhat 开源的 Docker 替代品。在绝大多数场景下, Podman 可以直接替代 Docker来执行(比如 alias docker=podman)。

如果你的 mac 上安装了 homebrew ,你使用 podman 会非常简单。

安装 Podman

使用 homebrew 即可安装 Podman,执行 brew install podman ,即可完成 podman 的安装。

初始化 VM

由于 macOS 并不是一个标准的 Linux Kernel(底层其实是 Unix),因此,你需要单独跑一个 VM 来完成容器环境的创建。和 Docker 不同的是,Podman 使用的是 qemu 来创建一个 VM,而不是依赖 VirtualBox。

执行 podman machine init,即可初始化一个 VM 环境。

d2b5ca33bd970f64a6301fa75ae2eb22 25

初始化完成后,执行 podman machine start 启动 VM,即可使用 Podman 命令来操作容器环境了。

(支线任务)使用 Docker cli 来操作 Podman 环境

由于 Podman 提供了兼容的实现,因此,你甚至可以使用 docker 的cli 来控制 Podman 创建的 VM 。在你执行 podman machine start 之后,在输出的 Log 当中会提示你,你可以将环境变量配置好,就可以实现让 Docker 也能识别到你的 Podman VM。

d2b5ca33bd970f64a6301fa75ae2eb22 26

这样你就可以使用原生的 docker cli 来控制 podman 的 VM。

不过,我想绝大多数的人可能不会既安装 Podman,又安装 Docker,那你可以选择配置一下 alias,直接使用 docker 命令来操作 Podman

alias docker=podman
d2b5ca33bd970f64a6301fa75ae2eb22 27

Tencent OS 3.1 如何安装 Docker 并开启信息隔离

6f55d09cbd449555c7bb3cd371925e7a

我最近在将主机从阿里云迁移到我的老东家腾讯云。

由于对于 Ubuntu/Debian/CentOS 用烦了,想试点新东西,就使用了腾讯云自带的 Tencent OS Linux 3.1 来配置环境。

和标准的发行版相比,Tencent OS Linux 针对 Docker 进行了定向的优化,因此,便刚好试一试腾讯的优化。

d2b5ca33bd970f64a6301fa75ae2eb22 4
腾讯针对标准版 Docker 优化,来源

如果你想要享受对应的优化,则需要定向安装腾讯云提供的 Docker 软件,具体安装方法也很简单,执行如下两行代码即可。

yum -y install tencentos-release-docker-ce
yum -y install docker-ce

如何开启信息隔离

根据官方文档说明,只需要执行如下代码即可完成信息隔离的开启:

sysctl -w kernel.stats_isolated=1

配置腾讯云 Docker 镜像

Docker 官方镜像在海外,在国内下载的速度体验一直不佳,在这种情况下,可以考虑配置腾讯云官方的内网镜像,提升镜像下载速度。

cat << EOF > /etc/docker/daemon.json
{
    "registry-mirrors": [
        "https://mirror.ccs.tencentyun.com"
    ]
}
EOF
Code language: JavaScript (javascript)

执行完成后,再执行 systemctl restart docker 来重启 docker 即可使用镜像。

用 Docker 解决端口错误的问题

green and black digital device

在进行嵌入式设备的编写的时候,一个很大的问题是重新刷写应用程序的成本较高,因此,在一些场景下, 我们尽可能通过修改服务端的应用,来解决嵌入式端的错误问题,而尽可能避免对嵌入式设备重新刷写。

我是在处理 Awtrix 2.0 的时候想到这个办法的。

Docker 在启动应用的时候,可以设置端口监听,通过 docker -p host_port:container_port 来创建容器,可以指定容器内部端口和主机监听端口的映射。

假设业务监听的是 80 端口,你可以通过 -p 81:80 将容器的 80 转发到宿主机的 81 端口上。同样的,你可以在遇见端口问题的时候,通过修改相应的宿主机端口,在外层加一层转发,从而解决掉端口编写错误的问题。

不过,需要注意的是,毕竟是加了一层应用程序的转发,相应的,性能会有所损耗,如果可以的话,尽可能还是修改嵌入式设备,减少性能损耗的点。

用 Docker 调试 Nginx

blue and red cargo ship on sea during daytime

容器技术被广泛应用在各种场景,在实际的应用过程中,我们也可以根据自己的需要,进行各种配置。我最近因为在调试 Nginx ,因此,也使用 Docker 来调试 Nginx。

Requirements

  • 已经安装 Docker
  • 安装了 docker-compose

实现思路

docker-compose 可以帮助我们把一些 Docker 启动的配置给简化,通过编写配置文件,简化启动容器的命令。

具体操作

创建一个项目,并在项目的根目录中放置 docker-compose.yml 以及 nginx.conf。其中,nginx.conf 是你需要测试的 nginx 文件,docker-compose.yml 则是用来记录你的 Docker 容器启动配置。

文件结构

启动容器并测试效果

将你需要测试的配置文件内容放置在 nginx.conf 中,并在dockcer-compose.yml 中添加如下内容

web:
  image: nginx
  ports:
    - "8080:80"
  volumes:
    - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
  command: [nginx-debug, '-g', 'daemon off;']
Code language: JavaScript (javascript)

随后,执行 docker-compose up 就可以启动容器,并展示出容器的运行效果

执行效果

此时,你就可以访问 localhost:8080 来查看你自己的配置了。

如何 Docker 化一个 Cli 工具

需求

我在看 Hexo 的 issue 时,看到了一个需求

Docker image to avoid the environment setting issue.

刚好,我自己有 Docker 的基础,就决定提交一个 PR ,解决这个问题。

核心实现

在开发这一部分的时候,一个最核心的问题是,你需要准备 2 个文件,一个是 DockerFile ,另一个是对应的 Bash Script。

原因在于

  • Docker File 用于打包基础环境,比如全局安装 Hexo
  • Bash Script 则是为了方便挂载本地的文件系统,开辟端口等(端口可以放在 Docker file 中,文件系统必须要现场挂载,因为你的目的是使用 Cli 管理本地文件,就一定要把文件挂载过去)

具体实现的思路是,Docker 镜像本身提供的是基础环境,将 CMD 设置为 Bash ,方便执行具体的命令。

而 Bash Script 则将需要执行的命令整体传递过去。

代码

Docker File

FROM node:10
RUN npm install -g hexo-cli
CMD ["/bin/bash"]
Code language: CSS (css)

Bash Script

#!/bin/sh
docker run \
  --interactive --tty --rm \
  --volume "$PWD":/hexosite \
  --workdir /hexosite \
  -p 4000:4000 \
  bestony/hexojs:latest "$@"

Code language: JavaScript (javascript)

总结

Docker 化 Cli 命令其实并不复杂,核心在于 CMD 与你的 Bash Script 的配合。

其他

你可以查看 https://github.com/hexojs/hexo/pull/3891 来学习到更多的内容。