部署HTTPS+Websocket的v2ray服务

说明

  • 仅简单记录部署过程
  • v2ray版本号4.26.0,更新的版本可能不适用
  • 配置参数请自行斟酌!
  • 此教程使用的域名为nginx.example.com,请使用自己的域名进行替换!
  • 不保证ctrl+cctrl+v可以直接跑起来!
  • 操作系统Debian 10

服务器环境初始化

更新系统版本

1
2
apt-get update
apt-get upgrade

安装软件包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
apt-get install -qyy \
git \
tree \
software-properties-common \
dirmngr \
apt-transport-https \
vim \
socat \
conntrack \
chrony \
gawk \
ca-certificates \
curl \
gnupg2 \
sudo \
unzip \
uuid

配置默认编辑器

1
update-alternatives --set editor /usr/bin/vim.basic

配置sysctl参数

1
2
3
4
5
6
7
8
9
10
11
cat > /etc/sysctl.d/99-debian.conf <<EOF 
# 最大文件句柄数
fs.file-max=1048576
# 最大文件打开数
fs.nr_open=1048576
# 端口最大的监听队列的长度
net.core.somaxconn=2048
# TCP拥塞算法
net.core.default_qdisc=fq
net.ipv4.tcp_congestion_control=bbr
EOF

修改limits参数

1
2
3
4
5
6
7
8
9
10
cat > /etc/security/limits.d/99-debian.conf <<EOF
* soft nproc 1048576
* hard nproc 1048576
* soft nofile 1048576
* hard nofile 1048576
root soft nproc 1048576
root hard nproc 1048576
root soft nofile 1048576
root hard nofile 1048576
EOF

修改时区

1
timedatectl set-timezone Asia/Shanghai

启动NTP网络对时

  • v2ray会校验服务器时间和客户端时间
1
systemctl enable chrony.service

修改LANG默认值

1
2
3
localectl set-locale LANG=en_US.UTF-8
localectl set-keymap us
localectl set-x11-keymap us

禁用系统服务

1
systemctl disable ufw.service

重启服务器

1
reboot

配置HTTPS证书

可以参考此教程或者这个教程

安装acme.sh

1
curl  https://get.acme.sh | sh

生成证书

可以手动生成,或者调用云服务厂商API去生成

使用acme.sh生成证书

1
~/.acme.sh/acme.sh --issue -d nginx.example.com --standalone --httpport 80 -k ec-256

调用CloudflareAPI制作通配证书

1
2
3
4
5
6
7
8
9
10
export CF_Key="Your_CloudFlare_API_Key"
export CF_Email="Your_CloudFlare_Account@example.com"

~/.acme.sh/acme.sh --issue \
-d "*.example.com" \
-d "nginx.example.com" \
--dns dns_cf \
--standalone \
--httpport 80 \
-k ec-256

调用阿里云API制作证书

1
2
3
4
5
6
7
8
9
10
export Ali_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
export Ali_Secret="jlsdflanljkljlfdsaklkjflsa"

~/.acme.sh/acme.sh --issue \
-d "*.example.com" \
-d "nginx.example.com" \
--dns dns_ali \
--standalone \
--httpport 80 \
-k ec-256

配置acme.sh自动更新

由于 acme 协议和 Let’sEncrypt CA 都在频繁的更新, 因此 acme.sh 也经常更新以保持同步!

1
~/.acme.sh/acme.sh --upgrade --auto-upgrade

部署Nginx

安装Nginx

1
apt-get install -y nginx

切换目录

1
cd /etc/nginx/conf.d/

清空default配置

1
> /etc/nginx/sites-available/default

修改默认配置

  • /etc/nginx/nginx.conf

  • 修改一下默认的woker_connections

1
2
3
4
5
6
events {
accept_mutex on;
worker_connections 4096;
multi_accept off;
use epoll;
}

创建配置文件

  • 用于反代v2ray的配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;

server_name nginx.example.com;
ssl_certificate conf.d/nginx.example.com.crt;
ssl_certificate_key conf.d/nginx.example.com.key;

add_header Strict-Transport-Security "max-age=63072000" always;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_ecdh_curve prime256v1:secp384r1;
ssl_prefer_server_ciphers off;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_session_cache shared:MozSSL:10m; # about 40000 sessions
ssl_session_tickets off;
ssl_session_timeout 1d;
ssl_stapling on;
ssl_stapling_verify on;

autoindex off;

location / {
root html;
index index.html index.htm;
}
location /ws {
proxy_redirect off;
proxy_read_timeout 600s;
proxy_send_timeout 600s;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_intercept_errors on;
if ($http_upgrade = "websocket" ){
proxy_pass http://127.0.0.1:9091;
}
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}

安装证书

  • 证书拷贝到对应路径
  • 这里把证书安装到nginx配置文件中定义的路径!
  • renew证书之后需要reload Nginx服务才能重新加载证书文件
1
2
3
4
5
6
~/.acme.sh/acme.sh --installcert \
-d nginx.example.com \
--fullchainpath /etc/nginx/conf.d/nginx.example.com.crt \
--keypath /etc/nginx/conf.d/nginx.example.com.key \
--ecc \
--renew-hook "systemctl reload nginx.service"

检查nginx配置是否正确

1
nginx -t

启动nginx

1
systemctl start nginx.service

配置开机自启动

1
systemctl enable nginx.service

部署v2ray

下载v2ray

官方提供最新版本的v2ray安装脚本

1
bash <(curl -L -s https://install.direct/go.sh)

生成UUID

  • 用v2ctl生成UUID
1
/usr/bin/v2ray/v2ctl uuid

UUID示例

09541c2b-134b-4eba-a38a-ff8963682ae3

配置v2ray服务端

修改/etc/v2ray/config.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
{
"policy": {
"levels": {
"0": {
"handshake": 4,
"connIdle": 300,
"statsUserUplink": true,
"statsUserDownlink": true,
"bufferSize": 10240
}
},
"system": {
"statsInboundUplink": true,
"statsInboundDownlink": true
}
},
"stats": {},
"api": {
"tag": "api",
"services": [
"HandlerService",
"LoggerService",
"StatsService"
]
},
"log": {
"loglevel": "info"
},
"dns": {
"network": "tcp",
"address": "8.8.8.8",
"port": 53
},
"inbounds": [
{
"port": 9091,
"listen": "127.0.0.1",
"protocol": "vmess",
"settings": {
"clients": [
{
"id": "7f9533e8-d0c6-11ea-9bc5-00163e020225",
"level": 0,
"alterId": 4,
"email": "user1@v2ray.com"
},
{
"id": "605e1ae8-d333-11ea-8745-00163e020225",
"level": 0,
"alterId": 4,
"email": "user2@v2ray.com"
}
]
},
"streamSettings": {
"network": "ws",
"wsSettings": {
"path": "/ws"
}
}
},
{
"tag": "api",
"port": 10008,
"listen": "127.0.0.1",
"protocol": "dokodemo-door",
"settings": {
"address": "127.0.0.1"
}
}
],
"outbounds": [
{
"tag": "direct",
"protocol": "freedom"
},
{
"protocol": "blackhole",
"settings": {},
"tag": "blocked"
}
],
"routing": {
"strategy": "rules",
"settings": {
"rules": [
{
"type": "field",
"outboundTag": "blocked",
"protocol": [
"bittorrent"
]
},
{
"type": "field",
"outboundTag": "blocked",
"domain": [
"domain:netflix.com",
"domain:netflix.net",
"domain:nflximg.net",
"domain:nflxvideo.net",
"domain:nflxso.net",
"domain:nflxext.com"
]
},
{
"type": "field",
"inboundTag": [
"api"
],
"outboundTag": "api"
}
]
}
}
}

检查配置文件

1
/usr/bin/v2ray/v2ray -test /etc/v2ray/config.json

启动v2ray

1
2
systemctl daemon-reload
systemctl start v2ray.service

配置开机自启动

1
systemctl enable v2ray.service

附systemd配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# /etc/systemd/system/v2ray.service
[Unit]
Description=V2Ray Service
Documentation=https://www.v2ray.com/ https://www.v2fly.org/
After=network.target nss-lookup.target

[Service]
# If the version of systemd is 240 or above, then uncommenting Type=exec and commenting out Type=simple
#Type=exec
Type=simple
Environment=V2RAY_RAY_BUFFER_SIZE=1
# This service runs as root. You may consider to run it as another user for security concerns.
# By uncommenting User=nobody and commenting out User=root, the service will run as user nobody.
# More discussion at https://github.com/v2ray/v2ray-core/issues/1011
#User=root
User=nobody
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
NoNewPrivileges=true
ExecStart=/usr/bin/v2ray/v2ray -config /etc/v2ray/config.json
Restart=on-failure

[Install]
WantedBy=multi-user.target

配置统计脚本

调用API统计

  • V2Ray 内包含了流量记录器功能
  • 查看流量信息是 v2ctl 的其中一个功能
  • 可以用简单的 shell 脚本 awk 工具来处理,生成足够可读的报表
  • 创建shell脚本,通过添加reset参数清零
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#!/bin/bash

_APISERVER=127.0.0.1:10008
_V2CTL=/usr/bin/v2ray/v2ctl

apidata () {
local ARGS=
if [[ $1 == "reset" ]]; then
ARGS="reset: true"
fi
$_V2CTL api --server=$_APISERVER StatsService.QueryStats "${ARGS}" \
| awk '{
if (match($1, /name:/)) {
f=1; gsub(/^"|link"$/, "", $2);
split($2, p, ">>>");
printf "%s:%s->%s\t", p[1],p[2],p[4];
}
else if (match($1, /value:/) && f){ f = 0; printf "%.0f\n", $2; }
else if (match($0, /^>$/) && f) { f = 0; print 0; }
}'
}

print_sum() {
local DATA="$1"
local PREFIX="$2"
local SORTED=$(echo "$DATA" | grep "^${PREFIX}" | sort -r)
local SUM=$(echo "$SORTED" | awk '
/->up/{us+=$2}
/->down/{ds+=$2}
END{
printf "SUM->up:\t%.0f\nSUM->down:\t%.0f\nSUM->TOTAL:\t%.0f\n", us, ds, us+ds;
}')
echo -e "${SORTED}\n${SUM}" \
| numfmt --field=2 --suffix=B --to=iec \
| column -t
}

DATA=$(apidata $1)
echo "------------Inbound----------"
print_sum "$DATA" "inbound"
echo "-----------------------------"
echo
echo "-------------User------------"
print_sum "$DATA" "user"
echo "-----------------------------"
  • 执行效果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$ ./traffic.sh
------------Inbound----------
inbound:ws->up 0B
inbound:ws->down 0B
inbound:tcp->up 47B
inbound:tcp->down 0B
inbound:kcp->up 259MB
inbound:kcp->down 2.4GB
inbound:api->up 2.0KB
inbound:api->down 6.6KB
SUM->up: 259MB
SUM->down: 2.4GB
SUM->TOTAL: 2.6GB
-----------------------------

-------------User------------
user:me@kcp->up 240MB
user:me@kcp->down 2.3GB
SUM->up: 240MB
SUM->down: 2.3GB
SUM->TOTAL: 2.5GB
-----------------------------

修改统计脚本

  • 参考上面的脚本修改一下

记录用户流量

/usr/local/bin/v2ray-traffic-usage.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#!/bin/bash
#set -x
_APISERVER=127.0.0.1:10008
_V2CTL=/usr/bin/v2ray/v2ctl
MONTH=$(date '+%Y-%m')
DATETIME=$(date '+%Y-%m-%dT%H:%M:%S')
LOG_DIR="/opt/v2ray-usage"
LOG_NAME="v2ray-traffic-usage.log"
mkdir -p "${LOG_DIR}/${MONTH}"

apidata () {
local ARGS=
if [[ $1 == "reset" ]]; then
ARGS="reset: true"
fi
$_V2CTL api --server=$_APISERVER StatsService.QueryStats "${ARGS}" \
| awk '{
if (match($1, /name:/)) {
f=1; gsub(/^"|link"$/, "", $2);
split($2, p, ">>>");
printf "%s:%s->%s\t", p[1],p[2],p[4];
}
else if (match($1, /value:/) && f){ f = 0; printf "%.0f\n", $2; }
else if (match($0, /^>$/) && f) { f = 0; print 0; }
}'
}

print_sum() {
local DATA="$1"
local PREFIX="$2"
local SORTED=$(echo "$DATA" | grep "^${PREFIX}" | sort -r| sed -e "s,^,${DATETIME} &,g" -e "s,$, Bytes,g")
echo -e "${SORTED}" | column -t
}
DATA=$(apidata $1)
print_sum "$DATA" "user" | tee -a "${LOG_DIR}/${MONTH}/${LOG_NAME}"
  • 输出结果
1
2
3
4
5
日期_时间            用户名                            字节数   单位
2020-09-01_08:45:0 user:user1@v2ray.com->up 2893 Bytes
2020-09-01_08:45:0 user:user1@v2ray.com->down 11302 Bytes
2020-09-01_08:45:0 user:user2@v2ray.com->up 4218 Bytes
2020-09-01_08:45:0 user:user2@v2ray.com->down 139049 Bytes

配置systemd服务

  • 每次执行时重置统计数据
1
2
3
4
5
[Unit]
Description=collect v2ray-traffic-usage data
[Service]
Type=oneshot
ExecStart=/usr/local/bin/v2ray-traffic-usage.sh reset

配置systemd定时器

  • 每分钟触发一次systemd服务
1
2
3
4
5
6
7
8
[Unit]
Description=cronjob for collect v2ray-traffic-usage data
[Timer]
Persistent=true
OnCalendar=*:0/1
Unit=v2ray-traffic-usage.service
[Install]
WantedBy=timers.target
  • 启动systemd定时器
1
2
systemctl daemon-reload
systemctl enable --now v2ray-traffic-usage.timer

解析流量日志

/usr/local/bin/v2ray-sum.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#!/bin/bash
MONTH=$(date '+%Y-%m')
LOG_DIR="/opt/v2ray-usage"
LOG_FILE="${LOG_PATH}/${MONTH}/v2ray-traffic-usage.log"
shell_color() {
export COLOR_WHITE='\e[1;37m' \
COLOR_BLACK='\e[0;30m' \
COLOR_BLUE='\e[0;34m' \
COLOR_LIGHT_BLUE='\e[1;34m' \
COLOR_GREEN='\e[0;32m' \
COLOR_LIGHT_GREEN='\e[1;32m' \
COLOR_CYAN='\e[0;36m' \
COLOR_LIGHT_CYAN='\e[1;36m' \
COLOR_RED='\e[0;31m' \
COLOR_LIGHT_RED='\e[1;31m' \
COLOR_PURPLE='\e[0;35m' \
COLOR_LIGHT_PURPLE='\e[1;35m' \
COLOR_BROWN='\e[0;33m' \
COLOR_YELLOW='\e[1;33m' \
COLOR_GRAY='\e[0;30m' \
COLOR_LIGHT_GRAY='\e[0;37m' \
COLOR_DEFAULT='\033[0m'
}
main() {
echo -e "${COLOR_YELLOW}============${MONTH}当月统计============${COLOR_DEFAULT}"
awk '{print$2,$3}' "${LOG_FILE}" | \
awk '{sum[$1]+=$2} END{for(c in sum){printf "%s %d\n", c, sum[c]}}' | \
numfmt --field=2 --suffix=B --to=iec --format %.3f | \
sort | \
column -t
}
shell_color
main
  • 执行结果
1
2
3
4
5
============2020-09当月统计============
user:user1@v2ray.com->down 26.123MB
user:user1@v2ray.com->up 5.804MB
user:user2@v2ray.com->down 728.231MB
user:user2@v2ray.com->up 777.113MB