Hotaru's Notebook

用 Nginx 转发 V2Ray 的 WebSocket 连接

Preface

有些地方网络环境很糟糕,比如:

既然这样,我就使用 80 或者 443 端口进行通信就是了。于是我看了下 v2ray 官方文档,提供了以下跟 HTTP/HTTPS 有关的选项:

因为我已经用 Nginx 监听 80 口了,所以新的连接必须通过 Nginx 分流到主机内的其他端口。这个 Issue 内提到了 “http 伪装没有完全遵守 http 协议,无法被常见的 http server 分流。如果你需要分流,可以使用 websocket 传输方式。",那我就用 WebSocket 吧。
哦对还有,有的更奇葩网络环境连 WebSocket 都不支持,具体可以到 websocketstest.com 测试一下。

弄个子域名

Nginx 支持使用域名来分流,也可以使用 URL 路径来分流,本节将使用域名来进行分流。

方法很简单:直接在域名提供商提供的DNS管理页面里 添加一个 CNAME 到自己的域名即可,本文将以 ws.example.com 为例。

配置 v2ray

客户端配置文件示例:

{
  "log": {
    "loglevel": "info"
  },
  "inbound": {
    // 在 0.0.0.0:1080 上监听 SOCKS5 的入站连接
    "protocol": "socks",
    "listen": "0.0.0.0",
    "port": 1080,
    "settings": {
      "auth": "noauth",
      "udp": true,
      "timeout": 30
    }
  },
  "inboundDetour": [],
  "outbound": {
    "protocol": "vmess",
    "settings": {
      "vnext": [
        {
          "address": "ws.example.com", // 服务器的域名
          "port": 80, // 访问服务器上监听在 80 端口的 Nginx
          "users": [
            {
              "id": "00000000-0000-0000-0000-000000000000",
              "alterId": 64,
              "security": "aes-128-cfb"
            }
          ]
        }
      ]
    },
    "streamSettings": {
      "network": "ws", // 使用 WebSocket 通信协议
      "wsSettings": {
        "connectionReuse": false,
        "path": "/" // 路径。如果想让 Nginx 使用 URL 来分流的话,就来配置这个
      }
    }
  },
  "outboundDetour": [
    {
      "protocol": "freedom",
      "settings": {},
      "tag": "direct"
    }
  ],
  "dns": {
    "servers": [
      "8.8.8.8",
      "8.8.4.4"
    ]
  },
  "routing": {
    "strategy": "rules",
    "settings": {
      "domainStrategy": "IPIfNonMatch",
      "rules": [
        {
          "type": "field",
          "ip": [
            "0.0.0.0/8",
            "10.0.0.0/8",
            "100.64.0.0/10",
            "127.0.0.0/8",
            "169.254.0.0/16",
            "172.16.0.0/12",
            "192.0.0.0/24",
            "192.0.2.0/24",
            "192.168.0.0/16",
            "198.18.0.0/15",
            "198.51.100.0/24",
            "203.0.113.0/24",
            "::1/128",
            "fc00::/7",
            "fe80::/10"
          ],
          "outboundTag": "direct"
        }
      ]
    }
  }
}

服务器配置文件示例:

{
  "log": {
    "loglevel": "info"
  },
  "inbound": {
    "protocol": "vmess",
     "listen": "127.0.0.1", // 这里要改成 loopback 地址,因为下面将配置 Nginx 把连接转发到 loopback
    "port": 12345, // 监听端口号
    "allocate": {
      "strategy": "always"
    },
    // 下面的 settings 和 streamSettings 都要和客户端配置相同
    "settings": {
      "clients": [
        {
          "id": "00000000-0000-0000-0000-000000000000",
          "alterId": 64,
          "security": "aes-128-cfb"
        }
      ]
    },
    "streamSettings": {
      "network": "ws",
      "wsSettings": {
        "connectionReuse": false,
        "path": "/"
      }
    }
  },
  "inboundDetour": [],
  "outbound": {
    "protocol": "freedom",
    "settings": {
      "timeout": 30
    }
  },
  "outboundDetour": [
    {
      "protocol": "blackhole",
      "settings": {},
      "tag": "blocked"
    }
  ],
  "routing": {
    "strategy": "rules",
    "settings": {
      "rules": [
        {
          "type": "field",
          "ip": [
            "0.0.0.0/8",
            "10.0.0.0/8",
            "100.64.0.0/10",
            "127.0.0.0/8",
            "169.254.0.0/16",
            "172.16.0.0/12",
            "192.0.0.0/24",
            "192.0.2.0/24",
            "192.168.0.0/16",
            "198.18.0.0/15",
            "198.51.100.0/24",
            "203.0.113.0/24",
            "::1/128",
            "fc00::/7",
            "fe80::/10"
          ],
          "outboundTag": "blocked"
        }
      ]
    }
  }
}

配置 Nginx

  1. /etc/nginx/sites-available/ 下创建文件 ws.example.com,文件内容如下:

    # V2Ray as WebSocket on "ws.excamle.com"
    server {
        server_name ws.example.com;
        listen 80;
        location / {
            proxy_redirect off;
            # 下面的 <端口号> 要和 v2ray 服务器端配置的 入站监听端口号 一致。
            proxy_pass http://127.0.0.1:<端口号>;
            proxy_http_version 1.1;
            # Upgrade 和 Connection 都是必须的,这将告诉 Nginx 以 WebSocket 的形式对待入站连接
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            # 下面这行可有可无
            proxy_set_header Host $http_host;
        }
    }
    
  2. 将文件 ws.example.com 软链接到 /etc/nginx/sites-enabled/ 下:

    ln -s /etc/nginx/sites-available/ws.example.com /etc/nginx/sites-enabled/ws.example.com
    
  3. 测试配置文件语法是否正确 并 重新载入配置文件

    nginx -t
    systemctl reload nginx
    systemctl restart v2ray
    

启动客户端并测试

像下面这样执行命令即可:

./v2ray -config ./config.json

然后配置网页浏览器等软件使用 V2Ray 提供的 SOCKS5 代理即可。

References

  1. 问题:关于HTTP伪装(非issue) #386
  2. REAL-TIME WEB TEST – DOES HTML5 WEBSOCKETS WORK FOR YOU?
  3. 底层传输配置 - v2ray.com

更新历史

11 Mar 2017:首次发布 11 Apr 2017:

#Linux #v2ray #Nginx #WebSocket #shadowsocks