本文最后更新于 2024 年 2 月 25 日
本文以 Debian 12 为例,介绍如何搭建 VLESS + WebSocket + TLS 服务端,使用 Nginx 建立 Web,并利用 CloudFlare 隐藏源站 IP,最后说明对应的客户端配置文件的格式。本文同样完全适用于 Ubuntu 22.04 系统。
注:请先参照 Debian & Ubuntu 服务器的初始化配置 一文对服务器进行各种必要的配置。本文以 sammy
用户为例,进行 V2Ray 的部署,并默认已按初始化配置文章对服务器进行了配置。
准备工作
服务器与域名
- 可用的公网 IP 服务器(例如在 BandwagonHost、Vultr 等处购买的 VPS)
- 注册一个域名,本文以
example.com
为例
内容准备
- 起一个随机的路径名,本文使用
/random
- 在 Online UUID Generator Tool 上生成一个 UUID,并记录之
- 准备自定义的 Web 页面,用于浏览器正常访问
example.com
显示的网页 - 准备自定义的 404 页面(可选)
- 起一个文件夹路径(可选),本文使用
/files
,用于存放一些客户端软件包以供有限的授权人员下载
CloudFlare 设置
- 将域名的 Namesever 指向 CloudFlare 所提供的地址,等待生效
- NS 记录更新后,将 CloudFlare 中域名的 A 记录指向服务器 IP,确保云朵为橙色(Proxied)
- 在
SSL/TLS
版块中的 Overview
里,将加密模式调整为 Full (strict)
- 在
SSL/TLS
版块中的 Edge Certificates
里,将 Minimum TLS Version
调整为 TLS 1.3
,并在下方确保开启对 TLS 1.3 的支持 - 在
Firewall
版块中的 Firewall Rules
里,添加一个规则,允许 /random
路径的访问(Allow URI path) - 在 CloudFlare 上获取域名的
Zone ID
,记录之 - 在 CloudFlare 的
My Profile
中生成一个 API Token
,权限为 Zone DNS Edit
,Zone Resources
特指区域为 example.com
,完成后记下 Token
- 如果像本文一样准备了一个文件夹路径
/files
,则需在 Access
版块中添加 Access Policy
,只允许授权的用户访问该路径的资源 - 根据自己的需要在 CloudFlare 上进行其他设置(可选),例如配置
Always Use HTTPS
、HSTS
、Automatic HTTPS Rewrites
、Auto Minify
等等,主要影响浏览器访问网站的效果
安装所需基本工具
1
| sudo apt update && sudo apt install curl unzip vim wget -y
|
服务器防火墙配置
此处限制服务器只允许 CloudFlare 的 IP 访问 443
端口。
1 2
| sudo mkdir -p /root/scripts/ufw sudo vim /root/scripts/ufw/add.sh
|
/root/scripts/ufw/add.sh1 2 3 4 5 6 7 8 9 10 11 12 13
| #!/bin/bash
cd /root/scripts/ufw
for ipv4 in `curl -sL https://www.cloudflare.com/ips-v4/ | tee ips-v4` do ufw allow from $ipv4 to any port 443 done
for ipv6 in `curl -sL https://www.cloudflare.com/ips-v4/ | tee ips-v6` do ufw allow from $ipv6 to any port 443 done
|
1
| sudo vim /root/scripts/ufw/remove.sh
|
/root/scripts/ufw/remove.sh1 2 3 4 5 6 7 8 9 10 11 12 13
| #!/bin/bash
cd /root/scripts/ufw
for ipv4 in `cat ips-v4` do ufw delete allow from $ipv4 to any port 443 done
for ipv6 in `cat ips-v6` do ufw delete allow from $ipv6 to any port 443 done
|
1
| sudo vim /root/scripts/ufw/update.sh
|
/root/scripts/ufw/update.sh1 2 3 4 5 6 7 8 9 10 11 12 13
| #!/bin/bash
cd /root/scripts/ufw
curl -sL https://www.cloudflare.com/ips-v4/ -o ips-v4.new curl -sL https://www.cloudflare.com/ips-v6/ -o ips-v6.new
if ! cmp -s ips-v4 ips-v4.new || ! cmp -s ips-v6 ips-v6.new || [ ! -f ips-v4 ] || [ ! -f ips-v6 ]; then bash remove.sh bash add.sh fi
rm -f ips-v4.new ips-v6.new
|
添加规则:
1
| sudo bash /root/scripts/ufw/add.sh
|
设置 cron 定时任务:
首行开始,添加如下内容,代表每日服务器时间 03:05
自动更新 ip 列表:
1 2
| MAILTO="" 5 3 * * * /bin/bash /root/scripts/ufw/update.sh
|
查看 nobody 的用户组
执行命令:
输出的结果可能是:
1
| uid=65534(nobody) gid=65534(nogroup) groups=65534(nogroup)
|
输出的结果也可能是:
1
| uid=65534(nobody) gid=65534(nobody) groups=65534(nobody)
|
请记住输出的用户组是 nobody
还是 nogroup
,接下来会用到这个信息,这决定了我们是使用 nobody:nogroup
还是 nobody:nobody
。
添加用户脚本
执行以下命令:
1 2
| mkdir -p ~/scripts vim ~/scripts/acme.sh
|
添加如下内容,注意替换其中的 sammy
和 nobody:nogroup
(如有必要):
~/scripts/acme.sh1 2 3 4 5 6
| #!/bin/bash
sudo chown -R sammy:sammy ~/certs "/home/sammy/.acme.sh"/acme.sh --cron --home "/home/sammy/.acme.sh" > /dev/null sudo chown -R nobody:nogroup ~/certs sudo systemctl restart v2ray
|
执行以下命令:
添加如下内容:
~/scripts/cert.sh1 2 3
| #!/bin/bash
/usr/bin/openssl req -newkey rsa:4096 -nodes -keyout ~/certs/default.key -x509 -days 365 -out ~/certs/default.crt -subj "/C=US"
|
至此,准备工作已完成。
安装并配置 V2Ray
安装
设置一个本地的安装脚本:
1 2
| mkdir -p ~/scripts vim ~/scripts/v2ray.sh
|
添加如下内容:
~/scripts/v2ray.sh1 2 3 4 5 6
| #!/bin/bash
cd ~/scripts wget https://raw.githubusercontent.com/v2fly/fhs-install-v2ray/master/install-release.sh sudo bash install-release.sh rm -f install-release.sh*
|
1 2
| sudo chmod -R 400 ~/scripts && chmod 700 ~/scripts bash ~/scripts/v2ray.sh
|
配置
编辑配置文件,此处示例额外配置了禁止 BT 流量,注意替换其中的 自定义端口号
、生成的 UUID
、/random
:
1 2
| sudo mkdir -p /usr/local/etc/v2ray sudo vim /usr/local/etc/v2ray/config.json
|
/usr/local/etc/v2ray/config.json1 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
| { "log":{ "loglevel": "warning" }, "inbounds": [ { "port": 自定义端口号, "listen":"127.0.0.1", "protocol": "vless", "settings": { "clients": [ { "id": "生成的 UUID" } ], "decryption": "none" }, "streamSettings": { "network": "ws", "wsSettings": { "path": "/random" } }, "sniffing": { "enabled": true, "destOverride": ["http", "tls"] } } ], "outbounds": [ { "protocol": "freedom", "settings": {} }, { "protocol": "blackhole", "settings": {}, "tag": "blocked" } ], "routing": { "domainStrategy": "IPOnDemand", "rules": [ { "type": "field", "ip": ["geoip:private"], "outboundTag": "blocked" }, { "type": "field", "protocol": ["bittorrent"], "outboundTag": "blocked" } ] } }
|
注:关于禁止 BT 或 P2P 流量的讨论,请详见 利用 iptables 或 UFW 禁止 BT 流量 一文。
安装并配置 Nginx
安装 nginx
1
| sudo apt update && sudo apt install nginx -y
|
配置
生成一个默认自签证书:
1 2 3
| sudo apt update && sudo apt install openssl -y mkdir -p ~/certs bash ~/scripts/cert.sh
|
配置 ngnix,设置默认的 catch-all:
1 2 3
| cd /etc/nginx/sites-enabled sudo rm -f default sudo vim default
|
添加如下内容,注意替换其中的 sammy
为当前用户名:
/etc/nginx/sites-enabled/default1 2 3 4 5 6 7 8 9 10 11
| server { listen 443 ssl default_server; listen [::]:443 ssl default_server; server_name _; ssl_certificate /home/sammy/certs/default.crt; ssl_certificate_key /home/sammy/certs/default.key; return 400; }
|
创建文件夹,注意提供换其中的 example.com
:
1 2 3
| sudo mkdir -p /var/www/example.com/html sudo chown -R $USER:$USER /var/www/example.com/html sudo chmod -R 755 /var/www/example.com/html
|
编辑 example.com
站点配置文件:
1
| sudo vim /etc/nginx/sites-available/example.com
|
注意替换其中的 sammy
为当前用户名,替换其中的 example.com
为实际域名,替换其中的 /random
、自定义端口
(V2Ray 中设置的)、/files
:
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
| server { listen 443 ssl http2; listen [::]:443 ssl http2; ssl_certificate /home/sammy/certs/example.com.crt; ssl_certificate_key /home/sammy/certs/example.com.key; ssl_session_timeout 1d; ssl_session_cache shared:MozSSL:10m; ssl_session_tickets off; ssl_protocols TLSv1.3; 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_prefer_server_ciphers off; root /var/www/example.com/html; index index.html index.htm index.nginx-debian.html; error_page 404 /404/index.html;
server_name example.com; location /random { if ($http_upgrade != "websocket") { return 404; } proxy_redirect off; proxy_pass http://127.0.0.1:自定义端口; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; }
location /files { autoindex on; autoindex_exact_size off; autoindex_localtime on; } }
|
注意,如果不需要设置自定义 404 页面,则删去:
1
| error_page 404 /404/index.html;
|
注意,如果不需要设置自定义的文件资源共享目录,则删去:
1 2 3 4 5
| location /files { autoindex on; autoindex_exact_size off; autoindex_localtime on; }
|
接着,通过 scp
或 rsync
上传之前在本地准备好的 Web 页面文件、资源文件夹到 /var/www/example.com/html
中去。例如:
1
| rsync -ruhP --delete public/ sammy_host:/var/www/example.com/html/
|
其中,网页文件和 files
文件夹都存放在本地 public
文件夹中,服务器别名为 sammy_host
。public
文件夹结构为:
启用配置
1
| sudo ln -s /etc/nginx/sites-available/exmaple.com /etc/nginx/sites-enabled/
|
至此,Nginx 部分已经配置完毕。
准备工作
安装依赖:
1
| sudo apt update && sudo apt install socat -y
|
安装 acme.sh:
1
| wget -O - https://get.acme.sh | sh
|
修改 sudoer
文件:
最后一行新增,注意替换其中的 sammy
为当前的真实用户名:
1 2 3 4
| sammy ALL=(ALL) NOPASSWD: /usr/sbin/service nginx force-reload sammy ALL=(ALL) NOPASSWD: /bin/systemctl restart v2ray sammy ALL=(ALL) NOPASSWD: /bin/chown -R sammy\:sammy /home/sammy/certs sammy ALL=(ALL) NOPASSWD: /bin/chown -R nobody\:nogroup /home/sammy/certs
|
生成证书
设置环境变量:
1 2
| export CF_Token="此处填写之前创建的 CloudFlare API Token" export CF_Zone_ID="此处填写 CloudFlare 中域名的 Zone ID"
|
生成证书:
1
| acme.sh --issue --dns dns_cf -d example.com
|
安装证书
注意替换其中的 example.com
为实际域名:
1 2 3 4
| acme.sh --install-cert -d example.com \ --key-file ~/certs/example.com.key \ --fullchain-file ~/certs/example.com.crt \ --reloadcmd "sudo service nginx force-reload"
|
设置定时任务
编辑定时任务:
删除掉其中 acme.sh
自动生成的定时任务行。
添加如下内容,保存并退出:
1
| 9 0 * * * /bin/bash ~/scripts/acme.sh
|
启动服务
1
| sudo systemctl restart v2ray
|
至此,服务端已部署完成。
客户端配置文件
注意替换下方的 example.com
、生成的 UUID
、/random
:
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
| { "log": { "loglevel": "warning" }, "inbounds": [ { "tag": "socks", "port": 10808, "listen": "127.0.0.1", "protocol": "socks", "settings": { "udp": true }, "sniffing": { "enabled": true, "destOverride": [ "http", "tls" ] } }, { "tag": "http", "listen": "127.0.0.1", "port": 10809, "protocol": "http", "settings": {} } ], "outbounds": [ { "protocol": "vless", "settings": { "vnext": [ { "address": "example.com", "port": 443, "users": [ { "id": "生成的 UUID", "encryption": "none" } ] } ] }, "streamSettings": { "network": "ws", "security": "tls", "wsSettings": { "path": "/random" } } }, { "protocol": "freedom", "tag": "direct", "settings": {} } ], "routing": { "domainStrategy": "IPOnDemand", "rules": [ { "type": "field", "ip": [ "geoip:private" ], "outboundTag": "direct" } ] } }
|
设置的代理监听在 socks5://127.0.0.1:10808
上,此设置同样可导入 v2rayNG
的 Android 客户端中。
而如果是利用了 socat 来中转流量,那么客户端的配置则可见下方,注意替换下方的 中转服务器 IP
、中转服务器端口
、example.com
、生成的 UUID
、/random
:
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
| { "log": { "loglevel": "warning" }, "inbounds": [ { "tag": "socks", "port": 10808, "listen": "127.0.0.1", "protocol": "socks", "settings": { "udp": true }, "sniffing": { "enabled": true, "destOverride": [ "http", "tls" ] } }, { "tag": "http", "listen": "127.0.0.1", "port": 10809, "protocol": "http", "settings": {} } ], "outbounds": [ { "protocol": "vless", "settings": { "vnext": [ { "address": "中转服务器 IP", "port": 中转服务器端口, "users": [ { "id": "生成的 UUID", "encryption": "none" } ] } ] }, "streamSettings": { "network": "ws", "security": "tls", "tlsSettings": { "serverName": "example.com" }, "wsSettings": { "path": "/random", "headers": { "Host": "example.com" } } } }, { "protocol": "freedom", "tag": "direct", "settings": {} } ], "routing": { "domainStrategy": "IPOnDemand", "rules": [ { "type": "field", "ip": [ "geoip:private" ], "outboundTag": "direct" } ] } }
|
设置的代理监听在 socks5://127.0.0.1:10808
上,此设置同样可导入 v2rayNG
的 Android 客户端中。
References
VLESS
v2fly / fhs-install-v2ray
Migrate from the old script to this
Access (Setup & Usage)
CDN | 新 V2Ray 白话文指南
websocket + tls + nginx + cdn 断流严重
“(CRON) info (No MTA installed, discarding output)” error in the syslog
How do I make cron create cron.log and monitor it in real time?
Project V · Project V 官方网站
搭建备用梯子:V2Ray + WebSocket + TLS + CloudFlare
V2ray + WebSocket + Nginx + TLS 纯手工配置极简教程
V2RAY + Nginx + Ws + Tls + Host + Path,HTTPS/HTTP2 协议伪装,可选开启 CDN
V2Ray + WebSocket + TLS + Nginx 配置与使用教程
v2ray +tls + websocket + nginx 配置与使用
shuanghua / ss v2ray-plugin.md
禁用 BT | 新 V2Ray 白话文指南
233boy-v2ray/config/server/ws.json
WebSocket + TLS + Web | 新 V2Ray 白话文指南
How to Install Nginx on Debian 10
Install Nginx with Server Blocks (Virtual Hosts) on Debian 10
Enabling the Nginx Directory Index Listing
Redirect HTTP to HTTPS in Nginx
Nginx block for multiple domains to redirect all traffic to https?
nginx: How to prevent an exactly named SSL server block from acting as the catchall for all SSL
Why is nginx responding to any domain name?
Setting Nginx to catch all unhandled vhosts
Generating a self-signed certificate using OpenSSL
How to create a self-signed certificate with OpenSSL
HowTo: Create CSR using OpenSSL Without Prompt (Non-Interactive)
OpenSSL Essentials: Working with SSL Certificates, Private Keys and CSRs
crontab guru
acmesh-official / acme.sh
DNS manual mode
How to use DNS API
[DNS mode] CloudFlare New API Tokens
TLS | 新 V2Ray 白话文指南
acme 工具的使用与 cloudflare
使用 acme.sh 给 Nginx 安装 Let’ s Encrypt 提供的免费 SSL 证书
Get started with V2Ray