sagezhong

V2Ray+WebSocket+TLS+Nginx+CDN配置与学习
V2Ray+WebSocket+TSL+Nginx+CDN配置与学习最近发现最近SSR越来越慢,而且我的博客有时打...
扫描右侧二维码阅读全文
30
2019/11

V2Ray+WebSocket+TLS+Nginx+CDN配置与学习

V2Ray+WebSocket+TSL+Nginx+CDN配置与学习

最近发现最近SSR越来越慢,而且我的博客有时打得开有时打不开,用端口测试工具之后发现,是GFW会间隔性的封杀我的服务器IP,原来的VPS在日本,然后开始了漫长的更换尝试。。。发现Vutrl的大部分45段和108段的IP基本都不能用了。最后换到了荷兰阿姆斯特丹可以用,然后开始着手准备换成新的工具。

V2Ray

V2Ray是Project V的核心工具,Project V 是一个工具集合,它可以帮助你打造专属的基础通信网络。V2Ray主要负责网络功能其网络协议和功能的实现。具体的可以去看它的官网,介绍的很详细,而且还有开发手册,让你知道它的整个设计以及架构。

V2Ray安装

V2Ray的安装方法官网介绍的很详细,Linux操作系统用官方的安装脚本即可顺利安装,不过目前自动运行脚本只支持带有 Systemd 的系统,以及 Debian / Ubuntu 全系列。而我的VPS系统是Centos6.9,所以无法顺利的用这个安装脚本。但是Google了一下解决办法也很简单。

# 执行安装脚本
curl -L -s https://install.direct/go.sh

如果你也是像我一样是不支持Systemmd的系统,执行完会报错,直接无视就好了(更高级的版本应该可以直接安装完成)。然后我们需要在/etc/init.d目录下建立一个V2Ray的脚本,这样就可以用Service启动和关闭了。Centos7之后支持强大的Systemctl所以服务脚本放在不一样的目录下,所以安装脚本不支持没有Systemmd的系统。

现在先在/etc/init.d建立一个v2ray脚本(非centos6.x系统可以跳过这一步)

vim /etc/init.d/v2ray

#把以下脚本代码复制进去

#!/bin/sh
#
# v2ray        Startup script for v2ray
#
# chkconfig: - 24 76
# processname: v2ray
# pidfile: /var/run/v2ray.pid
# description: V2Ray proxy services
#

### BEGIN INIT INFO
# Provides:          v2ray
# Required-Start:    $network $local_fs $remote_fs
# Required-Stop:     $remote_fs
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: V2Ray proxy services
# Description:       V2Ray proxy services
### END INIT INFO

DESC=v2ray
NAME=v2ray
DAEMON=/usr/bin/v2ray/v2ray
PIDFILE=/var/run/$NAME.pid
LOCKFILE=/var/lock/subsys/$NAME
SCRIPTNAME=/etc/init.d/$NAME
RETVAL=0

DAEMON_OPTS="-config /etc/v2ray/config.json"

# Exit if the package is not installed
[ -x $DAEMON ] || exit 0

# Read configuration variable file if it is present
[ -r /etc/default/$NAME ] && . /etc/default/$NAME

# Source function library.
. /etc/rc.d/init.d/functions

start() {
  local pids=$(pgrep -f $DAEMON)
  if [ -n "$pids" ]; then
    echo "$NAME (pid $pids) is already running"
    RETVAL=0
    return 0
  fi

  echo -n $"Starting $NAME: "

  mkdir -p /var/log/v2ray
  $DAEMON $DAEMON_OPTS 1>/dev/null 2>&1 &
  echo $! > $PIDFILE

  sleep 2
  pgrep -f $DAEMON >/dev/null 2>&1
  RETVAL=$?
  if [ $RETVAL -eq 0 ]; then
    success; echo
    touch $LOCKFILE
  else
    failure; echo
  fi
  return $RETVAL
}

stop() {
  local pids=$(pgrep -f $DAEMON)
  if [ -z "$pids" ]; then
    echo "$NAME is not running"
    RETVAL=0
    return 0
  fi

  echo -n $"Stopping $NAME: "
  killproc -p ${PIDFILE} ${NAME}
  RETVAL=$?
  echo
  [ $RETVAL = 0 ] && rm -f ${LOCKFILE} ${PIDFILE}
}

reload() {
  echo -n $"Reloading $NAME: "
  killproc -p ${PIDFILE} ${NAME} -HUP
  RETVAL=$?
  echo
}

rh_status() {
  status -p ${PIDFILE} ${DAEMON}
}

# See how we were called.
case "$1" in
  start)
    rh_status >/dev/null 2>&1 && exit 0
    start
    ;;
  stop)
    stop
    ;;
  status)
    rh_status
    RETVAL=$?
    ;;
  restart)
    stop
    start
    ;;
  reload)
    reload
  ;;
  *)
    echo "Usage: $SCRIPTNAME {start|stop|status|reload|restart}" >&2
    RETVAL=2
  ;;
esac
exit $RETVAL

然后再执行

chmod a+x /etc/init.d/v2ray
chkconfig v2ray on
service v2ray start

现在v2ray服务就启动了。

V2Ray配置

接着我们要开始在服务器上配置v2ray,v2ray的配置脚本在/etc/v2ray/config.json,配置脚本的每个字段的含义在官方文档里都有说明。

出站和入站协议

先看一下v2ray的架构(图片来自官方)

v2ray并没有分为客户端和服务端,每一个v2ray程序可以配置多个inboundoutbound,然后我们可以选择不同的Transport protocol作为载体将数据发送出去。而我们需要做的就是将服务器的inbound和客户端的outbound配置成能够互相收发数据。

v2ray支持多种inbound和outbound协议:例如Socks,HTTP,Shadowsocks,Vmess,所以如果之前VPS有跑SSR的话可以给服务器的inbound配置一个SSR就能够继续用SSR了。

HTTP,Socks大部分都很熟悉了,重点是这个Vmess,这个是v2ray的原创的一种加密传输协议。这一次我们要配置的是就是vmess+websocket+tls+cdn,先贴上我的服务器端的配置。

{
  "inbounds": [
    {
      "port": 10000,
      "listen": "127.0.0.1",
      "protocol": "vmess",
      "settings": {
        "clients": [
          {
            "id": "a2851a86-0352-49f7-9a82-bbb2a5fb407e",
            "alterId": 64
          }
        ]
      },
      "streamSettings": {
        "network": "ws",
        "wsSettings":{
           "path": "/flutter"
         }
        }
    }
  ],
  "outbounds": [{
    "protocol": "freedom",
    "settings": {}
  },{
    "protocol": "blackhole",
    "settings": {},
    "tag": "blocked"
  }],
  "routing": {
    "rules": [
      {
        "type": "field",
        "ip": ["geoip:private"],
        "outboundTag": "blocked"
      }
    ]
  }
}

id是UUID,它是一个 16 字节长的随机数,它的作用相当于一个令牌(Token)。 一个 ID 形如:a2851a86-0352-49f7-9a82-bbb2a5fb407e,几乎完全随机,可以使用任何的 UUID 生成器来生成,比如这个。这是作为客服端和服务器端认证连接的一个标志,所以客服端outbound和服务器端inbound需要配置成相同的id。配置中还有一个 alterId 参数,这个参数主要是为了加强防探测能力。理论上 alterId 越大越好,但越大就约占内存(只针对服务器,客户端不占内存),所以折中之下设一个中间值才是最好的,alterId 的大小要保证客户端的小于等于服务器的。

还有一点需要注意的是Vmess协议会检测两端的时间,时间差在90秒之内才能够通过校验,所以我们需要确保服务器的时间和客服端的时候同步。

底层传输的配置

当我们的inbound的配置Vmess协议之后,我们还需要配置底层的传输方式(协议),客户端的outbound和服务端的inbound需要使用相同的传输方式。可以选择TCP、mKCP、WebSocket等。我主要试过的是mKCP,和Websocket。

mKCP是v2ray的开发人员根据KCP协议改进的,KCPGitHub地址。KCP是一个快速可靠协议,能以比 TCP浪费10%-20%的带宽的代价,换取平均延迟降低 30%-40%,且最大延迟降低三倍的传输效果。学过计算机网络的都知道,TCP/IP协议族里常用的传输协议是TCP和UDP,两者最大的区别就是一个是可靠的传输协议,一个是不可靠。因为TCP是需要两端经过三次握手建立起连接的,依靠可靠的自动选择重传算法,保证接受的一方能够有序的收到数据。而KCP只是作为一个快速的可靠重传协议,它主要是对选择重传做了优化。例如TCP丢包时会全部重传从丢的那个包开始以后的数据,KCP是选择性重传,只重传真正丢失的数据包。所以KCP提供了向上和向下的接口,向上我们可以把上层的协议装进KCP的数据部,向下我们可以选择UDP作为载体传输数据,这样即使是不可靠的UDP也能保证接受的一方能够有序的接受到数据,因为KCP会对每一个分片的数据包进行编号,就像TCP一样。

说了这么多,要配置底层的传输既可以全局配置就是每一个bound统一或者为单独的一个bound进行配置,在单独的bound里面有一个streamSettings就是单独的底层传输配置。

      "streamSettings": {
        "network": "mkcp",
        "kcpSettings": {
          "uplinkCapacity": 100,
          "downlinkCapacity": 100,
          "readBufferSize": 5,
          "writeBufferSize": 5,
          "congestion": false,
          "header": {
            "type": "wechat-video"
          }
        }
      }

这是一份KCP的配置,里面各个字段的详细解释官网都有,就不展开了。经过我的实测,kcp的延迟确实低很多,而且速度也特别快,但是最终我还是选择了Websocket作为常用的配置。

WebSocket

KCP的流量特征还是比较明显的,也有很多人说开了几个小时后VPS就被封掉了。所以我在VPS上配置的是现在很多人选择的配置V2Ray+WebSocket+TLS+CDN,当然,只要在inbounds配置两个inbound就能同时跑两个协议了,在看视频的时候切换mKCP就好了。所以我的整个配置文件是这样的

{
  "inbounds": [
    {
      "port": 10000,
      "listen": "127.0.0.1",
      "protocol": "vmess",
      "settings": {
        "clients": [
          {
            "id": "你的id",
            "alterId": 50
          }
        ]
      },
      "streamSettings": {
        "network": "ws",
        "wsSettings":{
           "path": "/flutter"
         }
        }
    },
    {
      "port": 8000,
      "protocol": "vmess",
      "settings": {
        "clients": [
          {
            "id": "你的id",
            "alterId": 50
          }
        ]
      },
      "streamSettings": {
        "network": "mkcp",
        "kcpSettings": {
          "uplinkCapacity": 100,
          "downlinkCapacity": 100,
          "readBufferSize": 5,
          "writeBufferSize": 5,
          "congestion": false,
          "header": {
            "type": "wechat-video"
          }
        }
      }
    }
  ],
  "outbounds": [{
    "protocol": "freedom",
    "settings": {}
  },{
    "protocol": "blackhole",
    "settings": {},
    "tag": "blocked"
  }],
  "routing": {
    "rules": [
      {
        "type": "field",
        "ip": ["geoip:private"],
        "outboundTag": "blocked"
      }
    ]
  }
}

配置WebSocket

服务器端的inbound的WebSocke的配置在上面已经贴出来了,当这样配置完成后,我们就可以通过ws://你的ip或者域名:10000这个url访问了。接下来我们需要进行一步的伪装。

一般Web服务的端口是80和443,两者的区别是一个是http一个是https(http+tls),关于这个我之前有写过博客。所以为了伪装访问普通网站的流量,我们可以配置一下tls然后让websocket服务走443端口。

ssl的证书申请可以参考我的这篇博客免费ssl证书申请

接下来因为v2ray自身就支持tls协议,所以我们即可以使用文件来配置也可以使用web服务器配置tls然后代理WebSocket来实现。因为我的博客网站本身就配置在上面,而且我也配置好了tls,所以选择web服务器来配置会比较快。web服务器使用apache或者nginx都可以,但是我的apache是2.12版本要升级到2.14才支持WebSocket,所以我想了想停掉了apache全部都用nginx跑,接下来又是一顿折腾......

Nginx安装与配置

安装

直接去nginx官网看了一眼在Centos上安装

首先确保安装了yum-utils

sudo yum install yum-utils

然后建立yum的库,在/etc/yum.repos.d这个目录建立nginx.repo这个文件

vim etc/yum.repos.d/nginx.repo

#文件内容如下
[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true

[nginx-mainline]
name=nginx mainline repo
baseurl=http://nginx.org/packages/mainline/centos/$releasever/$basearch/
gpgcheck=1
enabled=0
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true

接着执行

sudo yum install nginx

配置

接着开始配置,我配置的是完整的多虚拟主机以及支持PHP的nginx服务器

nginx的配置在/etc/nginx/conf.d/这个目录下,只要在这个目录下建立.conf文件就行了,因为在主配置文件里面已经引入了这个目录下所有.conf的文件。整个配置如下:

# /etc/nginx/conf.d/sagezhong.top.conf
#设定虚拟主机配置
server {
  #侦听443端口,这个是ssl访问端口
  listen    443 ssl;
  #定义使用 访问域名
  server_name  sagezhong.top;
  #定义服务器的默认网站根目录位置
  root /var/www/html;

  #设定本虚拟主机的访问日志
  access_log  /var/log/nginx/sagezhong.access.log main;

 
  ssl_certificate /etc/ssl/sagezhong.top.crt;
  ssl_certificate_key /etc/ssl/sagezhong.top.key;
  ssl_session_timeout 5m;
  ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #按照这个协议配置
  ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;#按照这个套件配置
  ssl_prefer_server_ciphers on;

  #静态文件,nginx自己处理
  location ~ ^/(images|javascript|js|css|flash|media|static)/ {
      #过期30天,静态文件不怎么更新,过期可以设大一点,
      #如果频繁更新,则可以设置得小一点。
      expires 30d;
  }
     location / {
        root /var/www/html;
        index index.php;
        if (-f $request_filename/index.html){
            rewrite (.*) $1/index.html break;
        }
        if (-f $request_filename/index.php){
            rewrite (.*) $1/index.php;
        }
        if (!-f $request_filename){
            rewrite (.*) /index.php;
        }
        if ($request_uri = / ){
            rewrite (.*) /index.php;
        }
    }
    location = / {
        rewrite (.*) /index.php;
    }
        location ~ \.php$ {
            # 设置监听端口
            fastcgi_pass   127.0.0.1:9000;
            # 设置nginx的默认首页文件(上面已经设置过了,可以删除)
            fastcgi_index  index.php;
            # 设置脚本文件请求的路径
            fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
            # 引入fastcgi的配置文件
            include        fastcgi_params;
        }

  #禁止访问 .htxxx 文件
      location ~ /.ht {
      deny all;
  }


}
server
{
  # 80端口是http正常访问的接口
  listen 80;
  server_name sagezhong.top;
  # 重定向到https
  rewrite ^(.*) https://$host$1 permanent;
}
# /etc/nginx/conf.d/files.sagezhong.top.conf
#设定虚拟主机配置
server {
  #侦听443端口,这个是ssl访问端口
  listen    443 ssl;
  #定义使用 访问域名
  server_name  files.sagezhong.top;
  #定义服务器的默认网站根目录位置
  root /var/www/html/files;  

  #设定本虚拟主机的访问日志
  access_log  /var/log/nginx/files.sagezhong.access.log main;

  ssl_certificate /etc/ssl/sagezhong.top.crt;
  ssl_certificate_key /etc/ssl/sagezhong.top.key;
  ssl_session_timeout 5m;
  ssl_protocols TLSv1 TLSv1.1 TLSv1.2; #按照这个协议配置
  ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;#按照这个套件配置
  ssl_prefer_server_ciphers on;

  #默认请求

  #静态文件,nginx自己处理
  location ~ ^/(images|javascript|js|css|flash|media|static)/ {
      #过期30天,静态文件不怎么更新,过期可以设大一点,
      #如果频繁更新,则可以设置得小一点。
     expires 30d;
  }
     location / {
        root /var/www/html/files;
        index index.php;
        if (-f $request_filename/index.html){
            rewrite (.*) $1/index.html break;
        }
        if (-f $request_filename/index.php){
            rewrite (.*) $1/index.php;
        }
        if (!-f $request_filename){
            rewrite (.*) /index.php;
        }
        if ($request_uri = / ){
            rewrite (.*) /index.php;
        }
    }
    location = / {
        rewrite (.*) /index.php;
    }
        location ~ \.php$ {
            # 设置监听端口
            fastcgi_pass   127.0.0.1:9000;
            # 设置nginx的默认首页文件(上面已经设置过了,可以删除)
            fastcgi_index  index.php;
            # 设置脚本文件请求的路径
            fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
            # 引入fastcgi的配置文件
            include        fastcgi_params;
        }
}
server
{
  # 80端口是http正常访问的接口
  listen 80;
  server_name files.sagezhong.top;
  rewrite ^(.*) https://$host$1 permanent;
}

就是两个文件对应两个虚拟主机,通过不同的域名指向不同的文件目录。接下来这个配置比较重要,让nginx代理一下v2ray的WebSocket

# /etc/nginx/conf.d/ray.conf
server {
  listen  443 ssl;
  ssl_certificate       /etc/ssl/sagezhong.top.crt;
  ssl_certificate_key   /etc/ssl/sagezhong.top.key;
  ssl_protocols         TLSv1 TLSv1.1 TLSv1.2;
  ssl_ciphers           HIGH:!aNULL:!MD5;
  server_name           flutter.sagezhong.top;
        location /flutter { # 与 V2Ray 配置中的 path 保持一致
        proxy_redirect off;
        proxy_pass http://127.0.0.1:10000;#假设WebSocket监听在环回地址的10000端口上
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $http_host;

        # Show realip in v2ray access.log
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
}

配置到这里我们已经可以通过wss://flutter.sagezhong.top/flutter这个url来代理了,客户端的这样配置即可。

CDN

如果你的VPS的IP已经被封杀,那么可以用CDN绕开GFW,当然关键是你的CDN服务商也没有被封杀。免费的CDN服务商大家推荐的都是CloudFlare。不过它的节点大部分都是美国的,当然也有它现在也跟百度合作有国内的节点了,但是在国内用CDN服务的话首先需要保证的是你的域名已经备案了,因为我一直没有备案,所以就没有考虑用国内的节点了。最后我用的是阿里云的CDN,一般都是香港的节点。CDN的配置挺简单,像阿里云的话开通CDN后你只需要去你的域名服务商那里修改域名解析,将你的域名解析改为CNAME指向阿里云给你提供的域名就行了。

客户端下载

神一样的工具这个链接有所有常见客户端的下载,不过这个网站已经被墙掉了。

Last modification:November 30th, 2019 at 05:37 pm
请随意赞赏

4 comments

  1. bulczyolhw

    多语种文献的引用彰显学术包容性。

  2. vijohooojh

    哈哈哈,写的太好了https://www.lawjida.com/

  3. oyacccpwjr

    文章的确不错啊https://www.cscnn.com/

  4. euakedloiq

    博主真是太厉害了!!!

Leave a Comment Cancel reply