仓库地址:Nativu5/docker-xray-web

背景

这个项目其实源自于 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

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)

回落 (fallbacks) 功能简析 :: Project X (xtls.github.io)

acme.sh使用standalone模式流程记录及报错解决方法_weixin_46518915的博客-CSDN博客