安装 WordPress 并不难,网上也有很多教程,无非就是以下几步:

  1. 安装 Nginx
  2. 安装 MySQL
  3. 下载 WordPress 并解压到某个文件夹
  4. 配置 Nginx 和证书

事情是这样的,我原本打算将破站升级到 HTTP3,同时由于你懂的原因需要使用 Caddy。这就导致两个问题:Caddy 和 Nginx 都需要占用 443 端口,我需要让 Nginx 和 Caddy 共存;并且我当前使用的 Nginx 版本并不支持 HTTP3。于是我打算自行编译 Nginx,但是腾讯轻量云真的一言难尽,一编译直接卡死,I/O 直接爆表,重装系统后也是那样。遂弃用腾讯云,开始迁移这破站。

编译安装 Nginx

准备工作

1.安装必要软件

apt update
apt install build-essential ca-certificates zlib1g-dev libpcre3 libpcre3-dev tar unzip libssl-dev wget curl git cmake ninja-build mercurial libunwind-dev pkg-config

2.编译 BoringSSL

git clone --depth=1 https://github.com/google/boringssl.git
cd boringssl
mkdir build
cd build
cmake -GNinja ..
ninja
cd ~

3.编译ngx_brotli

git clone https://github.com/google/ngx_brotli.git
cd ngx_brotli
git submodule update --init
cd ~

ngx_brotli 也可以通过 apt 进行安装,之后直接使用 load_module 指令引入 Nginx 就行,所以这一步可以忽略。

4.clone nginx 到本地

hg clone https://hg.nginx.org/nginx
cd nginx

编译

#生成makefile文件
./auto/configure --user=www-data --group=www-data --prefix=/usr/local/nginx \
--add-module=/root/ngx_brotli \
--with-compat \
--with-debug \
--with-file-aio \
--with-http_addition_module \
--with-http_auth_request_module \
--with-http_dav_module \
--with-http_degradation_module \
--with-http_flv_module \
--with-http_gunzip_module \
--with-http_gzip_static_module \
--with-http_mp4_module \
--with-http_perl_module=dynamic \
--with-http_random_index_module \
--with-http_realip_module \
--with-http_secure_link_module \
--with-http_slice_module \
--with-http_ssl_module \
--with-http_stub_status_module \
--with-http_sub_module \
--with-http_v2_module \
--with-http_xslt_module=dynamic \
--with-mail=dynamic \
--with-mail_ssl_module \
--with-pcre --with-pcre-jit \
--with-stream \
--with-stream_ssl_module \
--with-stream_ssl_preread_module \
--with-threads \
--with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -fPIC' \
--with-ld-opt='-Wl,-z,relro -Wl,-z,now -pie' \
--with-cc-opt=-I../boringssl/include \
--with-ld-opt='-L../boringssl/build/ssl -L../boringssl/build/crypto' \
--with-http_v3_module \

自行编译的好处就是可以根据自己的需要添加或者不添加相应的模块。网上找一些模板拼接一下就行,尤其是最后几个模块,是我特别需要的。上一步完成过后,就可以开始编译和安装了。

make 
make install

编译过程可能会碰到些问题,根据报错自行 Google 解决也很快,这就不多赘述了。

make install 完成后,不出意外就可以在 /usr/local/nginx/ 中看到相应文件了。由于编译安装时并未将 Nginx 加入环境变量,因此直接执行 nginx -V 命令是肯定会报错的,不过设置环境变量太麻烦了,使用软链接将可执行文件链接到 /usr/local/bin/ 文件夹就行了。

ln -s /usr/local/nginx/bin /usr/local/bin/nginx

现在就没有问题了。接下来将 Nginx 加入开机自启。

:~# nginx -V
nginx version: nginx/1.25.2
built by gcc 11.3.0 (Ubuntu 11.3.0-1ubuntu1~22.04.1)
built with OpenSSL 1.1.1 (compatible; BoringSSL) (running with BoringSSL)
TLS SNI support enabled
configure arguments: --user=www-data --group=www-data --prefix=/usr/local/nginx --add-module=/root/ngx_brotli --with-compat --with-debug --with-file-aio --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_degradation_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_perl_module=dynamic --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-http_xslt_module=dynamic --with-mail=dynamic --with-mail_ssl_module --with-pcre --with-pcre-jit --with-stream --with-stream_ssl_module --with-stream_ssl_preread_module --with-threads --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -fPIC' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -pie' --with-cc-opt=-I../boringssl/include --with-ld-opt='-L../boringssl/build/ssl -L../boringssl/build/crypto' --with-http_v3_module

配置 service 实现自启动

cd ~
vim /usr/lib/systemd/system/nginx.service

写入如下配置

[Unit]
Description=Nginx complied with http3 module
After=network.target

[Service]
Type=forking
ExecStart=/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
ExecStop=/usr/local/nginx/sbin/nginx -s stop
ExecReload=/usr/local/nginx/sbin/nginx -s reload
KillMode=process
Restart=on-failure

[Install]
WantedBy=multi-user.target

添加到自启动

systemctl-reload
systemctl start nginx.service

#查看一下状态
systemctl status nginx.service

#如果启动成功了,没有任何报错,就可以 enable 了
systemctl enable nginx.service

安装 MySQL

鉴于自己对后端存在巨大知识盲区,数据库我选择用 Docker 进行安装,毕竟能不在命令行用 MySQL 就不用。关于安装 Docker 可以参考官方文档:https://docs.docker.com/engine/install/ubuntu/

编辑 docker-compose 配置文件

cd ~
mkdir compose
cd compose
mkdir mysql
cd mysql
vim docker-compose-mysql.yml

写入如下配置:

services:
  mysql:
    command:
      - --default-authentication-plugin=mysql_native_password
    container_name: "mysql"
    deploy:
      resources:
        limits:
          cpus: "0.5"
    environment:
      MYSQL_ROOT_PASSWORD: your password
      MYSQL_DATABASE: your wordpress database name
      MYSQL_USER: your customized database user
      MYSQL_PASSWORD: your customized user password
    image: mysql:8.0.33
    ports:
      - 127.0.0.1:3306:3306
    restart: always
    volumes:
      - ./data/:/var/lib/mysql
      #- ./conf/my.cnf:/etc/my.cnf
      - ./log:/var/log/mysql
      #- /etc/timezone:/etc/timezone:ro
      #- /etc/localtime:/etc/localtime:ro

将上面 your password 换成自己的 mysql root 密码,将 your wordpress database name 换成你自己定义的数据库名称,比如 mywordpress。将 your customized database user 换成你自己的的名称,密码换成自己的密码即可。

这里将端口映射到 127.0.0.1:3306 可以避免将数据库直接暴露在公网,而 - --default-authentication-plugin=mysql_native_password 可以解决 WordPress 连接高版本 MySQL 的认证问题。

安装 WordPress

第一步,从创建文件夹开始,有了就不用创建了。

cd ~
mkdir /www/wwwroot/ -p
cd /www/wwwroot/

下载和 cp WordPress 文件

wget https://wordpress.org/latest.tar.gz
tar -zxvf latest.tar.gz

解压过后就可以看到 wordpress 文件夹了。

:/www/wwwroot# ls
latest.tar.gz  wordpress

当然这时候还不能访问 WordPress,因为没有配置 Nginx。接下来就需要配置 Nginx 了。

配置 Nginx

在配置 Nginx 之前还需要申请 SSL 证书,不然无法实现 HTTPS,更别说 HTTP3 了。建议使用 acme.sh 开源程序,这里就不展开了。

Nginx 的配置文件真的及其复杂,相信有很多人都和我一样,被各种一键面板惯坏了,基本上对 Nginx 的配置就是 Ctrl + C, Ctrl + V 的程度。为了更好的复制粘贴,当然要祭出 DigitalOcean 的在线可视化配置工具了,该工具还支持中文 👏:https://www.digitalocean.com/community/tools/nginx

Nginx 可视化配置工具

配置完成后根据官方指引,将下载好的压缩包直接解压到 Nginx 的配置文件路径就行了。

Nginx 可视化配置安装指引

官方的指引是将文件直接解压到 /etc/nginx 目录,然而我是自己编译安装的,Nginx 的一切配置文件都在 /usr/local/nginx/conf/ 目录下。因此我需要 cd 到 /usr/local/nginx/conf/ 目录进行图上的操作,而不是 /etc/nginx 。如果执行 nginx -t 测试没有问题,就可以启动 Nginx 了。

当然生成的 Nginx 配置文件不一定完美适合自己的需求,可能需要小修小改。

我的需求就两个:

  1. 我要用 Caddy,因此需要使用 Nginx 转发 Caddy 的流量
  2. 我需要开启 HTTP3,配置工具的 HTTP3 配置好像有问题

Nginx 和 Caddy 共存

首先,将 Caddy 切换到别的端口,比如说 12345。比如下面的配置(这配置一看就知道是干嘛的 🤐

{
  order forward_proxy before route
  admin off
  auto_https off
  https_port 12345 #端口
}

:12345{ #端口
    tls /cert directory/fullchain.cer /cert directory/example.com.key { #证书位置
        ciphers TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
        alpn h2 http/1.1
    }
  forward_proxy {
    basic_auth user password #用户名 密码
    hide_ip
    hide_via
    probe_resistance
  }
  @host {
    host example.com #域名
  }
  route @host {
    header {
        Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
    }
    reverse_proxy https://example.com { #伪装网站,自己更换
        header_up Host {upstream_hostport}
        header_up X-Forwarded-Host {host}
    }
  }
}

然后编辑 Nginx 的主配置文件,加入 stream 块的配置。因为需要使用 Nginx的 SNI 识别,并通过 stream 将 Caddy 的流量在第四层进行转发。这里 stream 模块和 stream_ssl_preread_module 模块就有作用了。有关 stream 模块和 stream_ssl_preread_module 可以参考:

http://nginx.org/en/docs/stream/ngx_stream_core_module.html

http://nginx.org/en/docs/stream/ngx_stream_ssl_preread_module.html

接下来开始配置

vim /usr/local/nginx/conf/nginx.conf

添加如下配置:

stream {
  map $ssl_preread_server_name $backend_name {
      example.com caddy;
      your-web-domain.com web;
      default web;
  }
  upstream web{
      server 127.0.0.1:54321; #注意这个端口号不能用443了,443已经给stream用了
  }
  upstream caddy{
      server 127.0.0.1:12345;
  }
  server {
      listen 443 reuseport;
      listen 443 udp;
      proxy_pass $backend_name;
      ssl_preread on;
     # proxy_ssl_session_reuse off;
      #proxy_protocol on;
  }
}

注意: stream 块不能包含在 http 块里面;一定要添加 listen 443 udp ,因为 HTTP3 是基于 QUIC 协议,而 QUIC 是基于 UDP 的。

为网站添加 HTTP3 支持

vim /usr/local/nginx/conf/sites-enabled/your-web-domain.com.conf

为自己的站点添加如下配置:

server {
    listen                  80;
    listen                  54321 quic reuseport; #注意这个端口号不能用443了,443已经给stream用了
    listen                  54321 ssl http2; #注意这个端口号不能用443了,443已经给stream用了

        ...
    ...

        add_header Alt-Svc 'h3=":443"; ma=86400';
    ssl_early_data on;

    ...
    ...
}

为什么是listen 54321 quic 而不是 listen 54321 http3?

这个问题我也很疑惑…

齐活!

https://http3check.net 测试一下吧~

http3check