背景
这个项目其实源自于 2020 年的 CNSS 招新题目,当时要求使用 docker 容器实现 Nginx + PostgreSQL + PHP+ Typecho 的部署,但由于之前我的 VPS 运行蛮正常的,所以做完之后并没有实际应用到生产环境中。
最近发现了 Xray 这个新项目,另外又遇到 Gcorelab 这家 VPS 无法续费的问题,所以干脆在原来的项目中加入Xray,形成一个 Xray + Nginx + PostgreSQL + PHP + Typecho 的 docker-compose 快速部署方案。
原理
Nginx 监听宿主机 80 端口,将流量重定向至 443 端口。而 Xray 监听宿主机 443 端口,识别出 Vless 协议的流量后按照 Xray 设置的规则处理,非 Vless 流量全部转发至 nginx 容器的 8080 端口(即网站)。
类似 TCP + TLS + Typecho 博客 部署 V2RAY - Nativus' Space (naiv.fun) 中的原理图,由于 Xray 加入了回落(fallbacks)机制,只需将 Haproxy 和 V2Ray 替换成 Xray,协议换成 VLESS 即可。
所谓回落,可以类比分流,即 Xray 通过协议特征和路径,将不同的流量回落到不同的端口,从而实现 VLESS 到达 443 端口后被 Xray 处理,而普通的网页访问则被回落到 Nginx 监听的 8080 端口。
容器与镜像
本项目用到了 4 个容器,其中只有 PHP 容器的镜像是我基于 PHP 官方镜像修改而来的,其余均使用的官方镜像。以下是容器和镜像的简介,具体的挂载卷、端口、环境变量请参考 docker-compose.yml
文件和项目仓库中的 Readme。
Xray
感谢来自 teddysun/xray 的镜像。需要注意的是,只有配置文件正确才能启动容器。
- 宿主机
./xray
保存 Xray 的配置文件和日志。 - 宿主机
./cert
保存 Xray 使用的证书。
PHP-FPM
- 原官方镜像文档:https://github.com/docker-library/docs/blob/master/php/README.md
- 为了连接 PgSQL 数据库,在官方镜像基础上使用 docker-php-extension-installer 添加了
pgsql
拓展。 - 另外,PHP 容器需要配置才能使用,所以我参考 README.md#configuration 一节为容器添加了相应配置。
/nginx/www:/var/www
该映射保证了 PHP 可以访问本地的网站文件。
Nginx
直接使用了原版镜像。
- 宿主机
./nginx
保存 Nginx 的配置文件、日志和网页内容;
PostgresSQL
- 文档:https://hub.docker.com/_/postgres
”Environment Variables“ 一节中详细说明了容器运行所需提供的环境变量。
本项目用到了以下环境变量:
POSTGRES_PASSWORD
数据库superuser
密码; (必需)POSTGRES_USER
指定superuser
用户名;(可选,默认值为postgres
)POSTGRES_DB
指定数据库名称;(可选)
- 宿主机
./dbdata
保存pgsql
的数据库配置与文件;(容器初次运行后自动生成)
部署方法
请前往仓库查看 Readme 。
问题
这个部分主要记录我实际操作过程中遇到的一些问题,可供读者参考。
证书申请
为了保证项目的简单,我没有在项目中加入证书管理的脚本,而是要求使用者自行解决证书的问题。此处我是利用 acmesh-official/acme.sh 实现的。
由于容器启动需要证书,而一开始我既没有证书也没有网站来申请证书,所以使用了 acme 的 standalone 模式来申请证书。
sudo apt install setcap -y
sudo setcap 'cap_net_bind_service=+ep' /usr/bin/socat
~/.acme.sh/acme.sh --issue --standalone -d yourdomain.com --keylength ec-256 --force
~/.acme.sh/acme.sh --install-cert -d yourdomain.com --ecc \
--key-file /path/to/cert/xray.key \
--fullchain-file /path/to/cert/xray.crt \
--reloadcmd "chmod +r /path/to/cert/xray.key && docker restart nginx"
这里有几个小坑:
- 如上所示,standalone 模式依赖 socat 实现,但由于用户不是 root,所以 socat 没有操作端口号较低的端口的权限,上述第三行可以解决这个问题(issue #2622)。
- 我们选择
--key-length ec-256
,可以提高效率,但可能导致某些古老的设备无法正常访问网站。 --reloadcmd
控制自动更新用的命令,Xray 支持证书的热更新,并不需要 reload,但 Nginx 可能需要,所以我写了重启容器的命令(我也不确定但这样保险些)。- 第一次申请证书时应该把
reloadcmd
去掉,然后再启动容器。后面再申请的时候请读者自行发挥。
目录权限
./nginx
目录权限需要设定成 777
(贪图方便),否则会出现 Typecho 无法读写本地配置文件的问题。
伪静态与 301 跳转
server {
listen 8080;
server_name yourdomain.com;
root /var/www/typecho/;
index index.html index.htm index.php;
if (!-e $request_filename) {
rewrite ^(.*)$ /index.php$1 last;
}
location ~ .*\.php(\/.*)*$ {
include fastcgi.conf;
fastcgi_split_path_info ^(.+?.php)(/.*)$;
fastcgi_pass php-fpm-pgsql:9000;
}
access_log logs/yourdomain.com.log combined;
}
server {
listen 80;
server_name yourdomain.com;
rewrite ^(.*) https://yourdomain.com$1 permanent;
}
这是参考 Typecho 文档对 Nginx 配置文件 default.conf
做的修改,修改后需要到后台开启永久链接功能(如果提示开启失败请强制启用,应当并无大碍,至于为什么报错尚不明确)。
全站 HTTPS
Typecho 安装后可能需要在程序自动生成的 ./nginx/www/typecho/config.inc.php
中加入一行:
define('__TYPECHO_SECURE__',true);
以启用全站 HTTPS 加密。
关于 Xray 的几点补充
目前 Xray 不会判断访问的域名,即不能实现用户访问 yourdomain.com 和 sub.yourdomain.com 时进入两个不同的站点。貌似有办法解决 SNI 分流,但有些麻烦:integrated-examples/v2ray)- Xray 的日志默认是输出在容器内的控制台中的,可以按照 Xray 的文档要求,将 Xray 配置文件的
log
一节设置为
"log": {
"loglevel": "warning",
"access":"/var/log/xray/access.log",
"error":"/var/log/xray/error.log"
}
这样就可以看到日志文件在挂载的目录下生成了。
- 默认的 Xray 配置不能通过 CDN,但可以自定义 Xray 配置文件来实现这一功能。
参考资料
TCP + TLS + Typecho 博客 部署 V2RAY - Nativus' Space (naiv.fun)
小小白白话文 :: Project X (xtls.github.io)
没看懂 OωO