选购VPS
- 这里选择尝试使用Linode来做VPS,如果预算购的可以选择高配,一般可以选择
Standard Linode plan10刀一月,我只选了Nanodes5刀一月,具体参数请查看它的官网,注册时可以提供这个推荐码ad40d846b4e9fcb9cec7a0f3e47fe553e8c2a27d有优惠. - 这里选择安装
Debian 10,区域就选择SG或JP,勾选Private IP还会有一个v4的IP,现在能供IPv4的厂商很少了,像Vultr最便宜的VPS是2.5刀一月,只提供IPv6.完成之后,控制台如下图:
- 就上面区域选择,理论上离自己近的访问会最快,但是我在实际应用中选择了一个
SG很慢,这里在创建前可以使用https://www.linode.com/speed-test/测试一下,自己本地到Linode全球各机房的速度,选最快的.安装完成可以把VPS里的IP地址使用https://tools.ipip.net/traceroute.php检查一下路由,会在下方有直观的线路地图显示,如果发现IP的线路不满意删除重建一个新的VPS. - 登录它有两种SSH方式,一是直接SSH访问:
ssh root@xxx.xxx.xxx.xxx,这里可以使用在布署时添加RSA证书验证免密访问.二是通过Lish访问,估计它像是一个串口重定向一样的:ssh -t <username>@lish-singapore.linode.com <host-tags>,这里要用[Linode](https://www.linode.com/?
r=ad40d846b4e9fcb9cec7a0f3e47fe553e8c2a27d)的用户名与密码登录,后面再输入VPS的用户名与密码登入VPS.
开启SSH动态转发
- How To Route Web Traffic Securely Without a VPN Using a SOCKS Tunnel
- SSH Local, Remote and Dynamic Port Forwarding - Explain it like I am five!
1 | ~$ ssh -D 1088 -f -C -q -N user@<vps-ip> |
- 开启
ssh反向代理, 把本地的22端口反向映射到vps-ip:9980,这样访问9980就是访问到目标机的22端口。
1 | ~$ ssh -R 9980:localhost:22 -f -C -q -N user@<vps-ip> |
- 这里一般建议修改SSH服务器的默认端22为其它数字.,参数说明:
- -D [bind_address:]port 监听本地端口与SSH服务器创建一条Socks5通道.
- -C 开启数据压缩功能.
- -f
fork一个进程到后台模式,不会出现Shell. - -N 保持连接,端口转发中有用.
- -q 安静模式,屏蔽一些警告与错误信息.
使用ngrok隧道
- 去到ngrok官网下载一个二进制的客户端,使用
ngrok有两个场景使用,一是可以在内网把本机的某一个端口通过ngrok服务映射出去,二是可以把你的VPS服务隐藏在ngrok服务后面,再用SSH去动态转发,每次运行ngrok都会得到一个动态域名与端口,相对来说,中动态安全。下面示例是把本机的22通过ngrok。
1 | ~$ ngrok tcp 22 |
- 再用
ssh动态转发,这样就把自已的vps隐藏,并且还加速了,有很多直接SSH到VPS速度比较慢的。
1 | ~$ ssh -D 1080 user@8.tcp.ngrok.io -p 19192 |
申请Let's Ecrypt证书
lego Let’s Encrypt client and ACME library written in Go
这里会使用
lego工具通过DNS认证申请一个安全证书。
创建Access Token
- 进入到
Cloud Manager -> My Profile -> API Tokens创建,具体可以参照这里
使用LEGO申请
1 | ~$ git clone https://github.com/go-acme/lego |
- 使用
dns方式,申请成功后,默认会在~/.lego/certificates有相关域名的证书文件。
1 | ~$ LINODE_TOKEN=<your token api> lego --email <your email>@mail.com --dns linode --domains <linode name>.members.linode.com --tls run |
通过acme.sh申请
客户在申请
Let’s Encrypt证书的时候,需要校验域名的所有权,证明操作者有权利为该域名申请证书,目前支持三种验证方式:dns-01:给域名添加一个DNS TXT记录。http-01:在域名对应的Web服务器下放置一个HTTP well-known URL资源文件。tls-sni-01:在域名对应的Web服务器下放置一个HTTPS well-known URL资源文件。
而申请通配符证书,只能使用
dns-01的方式.acme.sh是一个纯粹用Shell(Unix shell)语言编写的ACME协议客户端。完整的ACME协议实施。支持 ACME v1和ACME v2,ACME v2支持通配符证书。并且无需root/sudoer的访问权限 。支持在Docker内使用,支持IPv6
1 | ~$ curl https://get.acme.sh | sh |
申请证书
- 使用
dns的验证方式,如果提示要一个email,需要加上--register-account -m <you email>@mail.com
1 | ~$ export LINODE_V4_API_KEY="<you linode api token >" |
使用
http的验证方式,这里没有安装任何web服务器,使用了socat工具与--standalone方式。申请成功后,会在~/.wwwroot/<linode-name>.members.linode.com目录下有相关的证书文件。1
2
3
4
5~$ apt-get install socat
~$ ETH0_IPv4=`ip addr show dev eth0 | grep "inet" | head -n1 | awk '{print $2}' | awk -F '/' '{print $1}'`
~$ DOMAIN=`dig -x ${ETH0_IPv4} | grep "PTR" | grep -v '^;' | awk '{print $5}'`
~$ DOMAIN=`echo ${DOMAIN%?}`
~$ acme.sh --issue --standalone -d ${DOMAIN} --webroot ~/.wwwroot/${DOMAIN}安装自动刷新证书脚本定时任务
1 | root@localhost:~# acme.sh --upgrade --auto-upgrade |
安装证书,以
Nginx的证书加载位置为例。它会通过脚本复制证书文件到指定的目录下。1
2
3
4
5
6
7
8
9
10
11
12~$ cat >install_nginx_ssl.sh<<EOF
#!/bin/bash
domain=exmaple.com
headscale_dir=/etc/nginx/ssl/${domain}_ecc
[[ ! -d ${headscale_dir} ]] && mkdir -pv ${headscale_dir}
/root/.acme.sh/acme.sh --install-cert -d ${domain} \
--key-file ${headscale_dir}/${domain}.key \
--fullchain-file ${headscale_dir}/fullchain.cer \
--reloadcmd "service nginx force-reload"
EOF如果上述出现任何错误,无法申请到证书,需要先确定是否本机的防火墙阻止了
80,443的端口,或者指定一个其它的端口。
安装HeadScale
- Links:
headscale-ui相关
headscale-ui的Traefik的配置可以参考这里,Nginx的配置在本文中有配置示例。
源码安装
1 | ~$ git clone https://github.com/juanfont/headscale |
Docker运行
1 | ~$ ~/headscale$ tree |
- 为
headscale-ui创建一个可以访问的Api Key. 打开https://headscale.example.com/web输入下面的值串。
1 | ~$ docker exec headscale-<docker> headscale apikeys create |
config.yaml模版来自与这里
1 | vpsuser@localhost:~/headscale$ grep -v '^#\|^ #\|^ #\|^$' config/config.yaml |
- 创建用户
1 | ~$ headscale users create vps1 |
- 查看
1 | ~$ docker exec headscale-headscale-1 headscale users list |
- 查看路由
1 | ~$ docker exec headscale-headscale-1 headscale routes list |
- 查看要结点列表。
1 | ~$ docker exec headscale-headscale-1 headscale nodes list |
安装Tailscale
- Links:
源码编译Linux
Linux amd64
1
2
3
4
5~$ git clone https://github.com/tailscale/tailscale
~$ cd tailscale
~$ GOOS=linux GOARCH=amd64 ./tool/go install tailscale.com/cmd/tailscale tailscale.com/cmd/tailscaled
~$ GOOS=linux GOARCH=amd64 ./tool/go build -o ./dist tailscale.com/cmd/tailscale tailscale.com/cmd/tailscaledLinux arm32
1 | ~$ GOOS=linux GOARCH=arm GOARM=7 ./tool/go build -o ./dist tailscale.com/cmd/tailscale tailscale.com/cmd/tailscaled |
运行
- 直接命令行运行,先要让
tailscaled进程运行起来。
1 | ~$ sudo tailscaled --state=/var/lib/tailscale/tailscaled.state --socket=/run/tailscale/tailscaled.sock --port=41641 -no-logs-no-support |
也可以使用
systemd服务,在tailscale/cmd/tailscaled目录下有各种服务的模版文件,如:tailscaled.openrc,tailscaled.service,tailscaled.defaults等。复制
tailscaled默认参数配置
1 | ~$ grep -v '^#\|^$' /etc/default/tailscaled |
- 具体的进程服务的配置文件如下:
1 | ~$ cat /etc/systemd/system/tailscaled.service |
登录服务器
- 这里运行登录,会在终端输出一行参数的提示,或者会自动打开本地浏览器,输出一段参数,需要在
headscale上去运行。
1 | ~$ sudo tailscale up --login-server <your server url or ip:port> |
- 上面运行输出的参数,需要在
headscale的服务器上运行。
1 | ~$ sudo headscale --user vps1 nodes register --key nodekey:ee91f2883a532cff2ea63991cfxxxxx |
- 如果
headscale是运行在docker里的,需要把命令传入到docker.
1 | ~$ docker exec headscale-<docker> headscale nodes register --user vps1 --key nodekey:ee91f2883a532cff2ea63991cfxxxxx |
- 重新登录
1 | ~$ sudo tailscale logout |
- 另一种登录方式,先在
headscale上,为一个用户生成preauthkeys,再拿这一串key到客户端进行登录
1 | ~$ docker exec headscale-headscale-1 headscale --user vps2 preauthkeys create --reusable --expiration 24h |
- 去某一个客户端机器登录认证。
1 | ~$ sudo tailscale up --login-server https://headscale.example.com --authkey e770e03d374e667134de22b8ccxxxxxx |
- 测试与对端是否是
p2p直连
1 | ~$ tailscale ping 100.64.0.1 |
- 检测网络状态
1 | ~$ tailscale netcheck |
- 不修改本地
/etc/resolv.conf.
1 | ~$ tailscale set --accept-dns=false |
- 查看本地路由
1 | ~$ ip route show table 52 |
打通局域网访问
- 首先需要在开放访问的局域网的机器上开启内核路由转发
1 | echo 'net.ipv4.ip_forward = 1' | tee /etc/sysctl.conf |
- 在注册启动节点时加入
--advertise-routes=xxx.xx.xx.x/xx通告声明本局域网的路由
1 | ~$ tailscale up --login-server=https://headscale.example.com --accept-dns=false --advertise-routes=10.0.1.0/24 --reset |
在
headscale查看并开启相应的路由1
2
3
4
5
6
7
8
9
10~$ docker exec headscale-headscale-1 headscale routes list
An updated version of Headscale has been found (0.22.0-alpha2 vs. your current 0.21.0). Check it out https://github.com/juanfont/headscale/releases
ID | Machine | Prefix | Advertised | Enabled | Primary
1 | | 192.168.10.0/24 | false | false | false
2 | | 10.0.0.0/24 | false | false | false
3 | debian-xyz97cy4 | 192.168.1.0/24 | false | false | false
4 | debian | 10.0.1.0/24 | true | false | true
5 | xx-debian | 10.0.1.0/24 | false | false | false
6 | xx-debian | 0.0.0.0/0 | true | false | -
7 | xx-debian | ::/0 | true | false | -如上图所示,第4行
Enabled显示是false,这里需要开启它。
1 | ~$ docker exec headscale-headscale-1 headscale routes enable -r 4 |
- 去其它节点本看路由结果,节点启时需要加入
--accept-routes=true才能。
1 | ~$ sudo tailscale up --login-server https://headscale.example.com --accept-routes=true |
- 上面的节点启动连接成功后,就可以直接在本地访问对端
10.0.1.0/24网络。如下面,则时两个子局域通过各自网络的一台机器,把两个局域网连通起来。
1 | # A局域网的一台机器。 |
设置exit-node.
首先需要一台机器在注册启动节点时加入
--advertise-exit-node声明它提供节点出口服务。已经注册的可以命名用下面命令:1
~$ sudo tailscale set --advertise-exit-node
需要在
headscale中开启0.0.0.0/0,::/0路由,
1 | ~$ docker exec headscale-headscale-1 headscale routes enable -r 6 |
- 查看路由
1 | ~$ docker exec headscale-headscale-1 headscale routes list |
- 其它节点,设置使用
exit-node做为出口路由
1 | ~$ sudo tailscale up --login-server https://headscale.example.com --exit-node=100.64.0.8 |
- 或者
1 | ~$ sudo tailscale set --exit-node xx-debian |
- 退出使用
exit-node出口路由
1 | ~$ sudo tailscale set --exit-node "" |
Windows客户端
先从这里下载安装,如果需要连接自建的
headscale服务器,[参考这里](https://github.com/juanfont/headscale/blob/main/docs/windows-client.md),修改注册表值。找到
HKLM:\SOFTWARE\Tailscale IPN\在其下面,新建UnattendedMode字符串,值为always.再新建LoginURL,值为headscale的服务器的地址。注销或者重启电脑。点击登录后会与其它端一样,用本地浏览器打开一串参数,需要在
headscale加入它。
Android客户端
tailscale-android的安卓端,可以从源码编译,可以从F-Droid或者从Google Play两个市场上安装。
从
1.29.1开始可以支持custom server,它的入口比较了隐蔽,需点击右上角的三的个点,查看三次about,第四次才会出现这更改服务器的菜单。登录注册流程与Linux类似。
安装Trojan
网络性能优化
1 | ~$ vi /etc/security/limits.conf |
申请证书Let's Encrypt
这里使用一个简单脚本获取
1
2
3
4
5
6~$ sudo apt-get install certbot dnsutils python-certbot-nginx -y
~$ ETH0_IPv4=`ip addr show dev eth0 | grep "inet" | head -n1 | awk '{print $2}' | awk -F '/' '{print $1}'`
~$ DOMAIN=`dig -x ${ETH0_IPv4} | grep "PTR" | grep -v '^;' | awk '{print $5}'`
~$ DOMAIN=`echo ${DOMAIN%?}`
~$ certbot certonly --nginx --agree-tos --email yjdwbj@gmail.com -d $DOMAIN
~$ apt-get autoremove nginx-full -y # 这里没有用到nginx,删除它.申请成功后,查看证书.
1
2~# ls/etc/letsencrypt/live/<xxxxx>.members.linode.com
cert.pem chain.pem fullchain.pem privkey.pem README
部署Trojan
这里就直接下载一个最新的Release解压使使用,解压后如下:
1
2
3
4
5
6
7
8
9
10
11
12
13~# tree trojan
trojan
├── config.json
├── CONTRIBUTORS.md
├── examples
│ ├── client.json-example
│ ├── forward.json-example
│ ├── nat.json-example
│ ├── server.json-example
│ └── trojan.service-example
├── LICENSE
├── README.md
└── trojan这里直接从
examples/server.json-example复制一个改名成server.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# cat server.json
{
"run_type": "server", # 如果是用客户端,改成client
"local_addr": "0.0.0.0",
"local_port": 443,
"remote_addr": "127.0.0.1",
"remote_port": 80,
"password": [
"passwd1", # 可以设置多个密码,可以使用任意一个访问该服务.
"passwd2"
],
"log_level": 1,
"ssl": {
# 下面这两行,就是使用从letsencrypt申请到的证书的完全路径.
"cert": "/etc/letsencrypt/live/<xxxxxx>.members.linode.com/fullchain.pem",
"key":"/etc/letsencrypt/live/<xxxxx>.members.linode.com/privkey.pem",
"key_password": "",
"cipher": "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",
"cipher_tls13": "TLS_AES_128_GCM_SHA256:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_256_GCM_SHA384",
"prefer_server_cipher": true,
# "sni": "yourdomain", //如果客户端,会有这一行,就是服务器的域名.
"alpn": [
"h2",
"http/1.1"
],
"reuse_session": true,
"session_ticket": false,
"session_timeout": 600,
"plain_http_response": "",
"curves": "",
"dhparam": ""
},
"tcp": {
"prefer_ipv4": false,
"no_delay": true,
"keep_alive": true,
"reuse_port": true,
"fast_open": true, // 要使用 sysctl -w net.ipv4.tcp_fastopen=4
"fast_open_qlen": 20
},
"mysql": {
"enabled": false,
"server_addr": "127.0.0.1",
"server_port": 3306,
"database": "trojan",
"username": "trojan",
"password": ""
}
}
配置systemd启动与运行权限
使用一个非特权用户运行
1
2
3~# useradd -s /usr/sbin/nologin trojan
~# chown -R trojan:trojan /path/to/trojan
~# chmod u+x /path/to/trojan或者使用Capabilities来管理根限.如果不是特权用户是不绑定
1024以下的端口的.1
~# setcap 'cap_net_bind_service=+eip' /path/to/trojan
创建文件,
/etc/systemd/system/trojan.service或者/lib/systemd/system/trojan.service
1 | ~$ cat /etc/systemd/system/trojan.service |
- 上面启动如果有错,使用
systemctl status trojan再用journalctl -x | grep "trojan" -A +10查看具体错误原因.
##TLS1.3支持
- 如果系统的
openssl版本是在1.1.1以上的可以开启TLS1.3,加密可以改成如下:1
TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-128-GCM-SHA256:TLS13-AES-128-CCM-8-SHA256:TLS13-AES-128-CCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256
使用Docker安装
- 主机上获取证书
1
2~$ certbot certonly --nginx --agree-tos --email yjdwbj@gmail.com -d proxy.yjdwbj.cloudns.org --force-interactive
~$ chmod 644 /etc/letsencrypt/archive/proxy.yjdwbj.cloudns.org/privkey.pem
安装dnsmasq来加速解析(非必需)
1 | ~$ sudo apt-get install dnsmasq -y |
使用Dokku安装
1 | docker images |
1 | ~$ dokku apps:create trojan |
安装WireGuard
- 现在WireGuard还没有进入
Debian的稳定版本分支,需要使用下面命令安装.
1 | ~# echo "deb http://deb.debian.org/debian/ unstable main" > /etc/apt/sources.list.d/unstable-wireguard.list |
- 如果安装了
WireGuard dkms模块了,但是又更新内核,这是是需要用重新编译并安装到新的内核里,如下:
1 | ~$ dkms status |
配置服务器
1 | ~$ cd /etc/wireguard/ |
安装防火墙
1 | ~$ sudo apt-get install ufw |
启动WireGuard
1 | ~$ sudo wg-quick up wg0 |
客户端
- 客户端的安装方式如同服务端,VPN的配置都是对等配置,就是都要知道对方的公共密钥.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16~$ cd /etc/wireguard/
~$ sudo wg genkey | tee privatekey | wg pubkey > publickey
~$ sudo cat > '/etc/wireguard/wg0.conf' << EOF
[Interface]
PrivateKey = <Private Key>
Address = 172.18.0.2/24, fd86:ea04:1115::5/64
[Peer]
PublicKey= <Server Public Key>
Endpoint = <Server IpAddress>:51820
AllowedIPs = 172.18.0.2/24,fd86:ea04:1115::0/64
EOF
~$ sudo wg-quick up wg0
interface: wg0
public key: <Public Key>
private key: (hidden)
listening port: 41743
服务端添加Peer
- 上面就是配置好的客户端,但是还不能连接到上述的服务器去,现在还要在服务端里加上对等的
Peer项,可以直接编辑服务端的/etc/wireguard/wg0.conf,也可以使用下面命令.
1 | ~$ sudo wg set wg0 peer <Client Public Key> allowed-ips 172.18.0.2/32 |
- 如果无错连接成功后,就可以从
172.18.0.1去ping 172.18.0.2. - 下面是一个服务器连接两个端点的配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18~$ wg show
interface: wg0
public key: <server >
private key: (hidden)
listening port: 51820
peer: <public key of Bob>
endpoint: <Bob>:33506
allowed ips: 172.18.0.3/32
latest handshake: 50 seconds ago
transfer: 35.55 KiB received, 36.31 KiB sent
peer: <public key of Alice>
endpoint: <Alice>:23637
allowed ips: 172.18.0.2/32
latest handshake: 2 minutes, 51 seconds ago
transfer: 15.53 KiB received, 14.59 KiB sent
手机端通过QR加入服务器
这里可以完全在服务端完成,现生成一组服务器的密钥对, 再建一个名为
clients目录,在下面生成各个客户端的密钥与配置文件再把配置文件转成终端的QR图,供手机端扫码加入.1
~$ sudo mkdir -p /etc/wireguard/clients; wg genkey | sudo tee /etc/wireguard/clients/mobile.key | wg pubkey | sudo tee /etc/wireguard/clients/mobile.key.pub
生成配置文件
1
2
3
4
5
6
7
8
9
10
11
12~$ cat > /etc/wireguard/clients/mobile.conf <<EOF
[Interface]
PrivateKey = <mobile.key>
Address = 10.0.0.10/24
DNS = 1.1.1.1, 1.0.0.1
[Peer]
PublicKey = YOUR_SERVER_PUBLIC_KEY
AllowedIPs = 0.0.0.0/0
Endpoint = YOUR_SERVER_WAN_IP:51820
EOF转换成QR图
1 | ~$ qrencode -t ansiutf8 < /etc/wireguard/clients/mobile.conf |
- 服务端加入该客户端并保存.
1
2~$ sudo wg set wg0 peer <mobile.key.pub> allowed-ips 0.0.0.0/0
~$ sudo wg-quick save wg0
安装Polipo做HTTP Proxy
- Polipo
1
2
3
4
5
6
7~# cat > /etc/polipo/config <<EOF
proxyAddress = "0.0.0.0"
allowedClients=172.18.0.0/24,127.0.0.1,192.168.1.0/24
socksParentProxy = "127.0.0.1:1080"
EOF
~$ sudo systemctl restart polipo
安装V2Ray
简单脚本安装
- 参照这里直接下载解压二进制的安装,不知会不会夹带私货.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19~$ bash <(curl -L -s https://install.direct/go.sh)
Installing V2Ray v4.22.1 on x86_64
Downloading V2Ray: https://github.com/v2ray/v2ray-core/releases/download/v4.22.1/v2ray-linux-64.zip
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 608 100 608 0 0 9212 0 --:--:-- --:--:-- --:--:-- 9212
100 11.6M 100 11.6M 0 0 24.3M 0 --:--:-- --:--:-- --:--:-- 24.3M
awk: not an option: -e
Archive: /tmp/v2ray/v2ray.zip
inflating: /usr/bin/v2ray/geoip.dat
inflating: /usr/bin/v2ray/geosite.dat
inflating: /usr/bin/v2ray/v2ctl
inflating: /usr/bin/v2ray/v2ray
PORT:42747
UUID:x009c053-xxxx-4420-xxxx-33b2fa35209x
Archive: /tmp/v2ray/v2ray.zip
inflating: /etc/systemd/system/v2ray.service
Created symlink /etc/systemd/system/multi-user.target.wants/v2ray.service → /etc/systemd/system/v2ray.service.
V2Ray v4.22.1 is installed.
源码编译安装
安装合适的
golang版本,具体可以查源码内的go.mod文件第一行。1
2
3
4
5~$ sudo apt-get install golang-1.19 golang-1.19-go -y
~$ sudo update-alternatives --install /usr/lib/go/bin/go go /usr/lib/go-1.19/bin/go 80
~$ ln -svf /usr/lib/go/bin/go /usr/bin/go
~$ sudo update-alternatives --config go
~$ git clone https://github.com/v2fly/v2ray-corev2ray-core编译安装方法可以使用它源码里的脚本v2ray-core/user-package.sh来运行即可,也可以直接运行v2ray-core/install-release.sh安装官方编译的版本。使用
v2ray-core/user-package.sh编译的默认会生成一个如下的zip文件。
1 | unzip ../v2ray-custom-amd64-linux-20220902-230653.zip |
- 需要系统控制服务,把
v2ray.serveice复制到相应的系统目录下。
编译windows的客户端
1 | ~$ git clone https://github.com/v2fly/v2ray-core |
Websockets+TLS+Nginx配置
v2ray-core服务端配置
1 | { |
v2ray-core客户端配置
1 | { |
Nginx配置
Nginx主要是用于websockets的反向代理。
1 | root@localhost:~# cat /etc/nginx/sites-available/ssl |
Http2+TLS配置
- 注意,这里并没有使用
nginx来做前置代理,因为nginx现在还不能代理http2的请求,网上有所以这里是直接把v2ray-core的服务暴露出来。这里涉及到一些内外网分流,要用到geoip的数据做为判断,这里主要是使用geoip.dat与geosite.dat,如果要更极致一点, 可以参考使用V2Ray 路由规则文件加强版
服务端
1 | { |
客户端
1 | { |
搭建一个中继
这里中继是解决我一个手机使用的场景,手机的移动网络无法直连
VPS的服务,地址的都ping不通,但是家里的宽带网络可以正常访问。所以在家里搭一个中继,使用IPv6+DDNS直接访问, 它是一个服务端又是一个客户端。可以使用一个如树莓派的单板机来足够担挡。server.bridge.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{
"log": {
"loglevel": "none"
},
"inbounds": [
{
"tag": "rpi",
"port": 1443,
"protocol": "vmess",
"settings": {
"clients": [
{
"id": "your-bridge-uuid" // 连接本机的客户端的uuid要与这里是一致的。
}
]
}
}
],
"outbounds": [
{
"tag": "vps",
"protocol": "vmess",
"settings": {
"vnext": [
{
"port": 1443,
"address": "your-server-address", // linode上VPS的uuid,它才是正真提供上网出口的服务
"users": [
{
"id": "your-uuid"
}
]
}
]
},
"streamSettings": {
"network": "http",
"security": "tls",
"tag": "proxy",
"httpSettings": {
"path": "/ray"
},
"tlsSettings": {
"allowInsecure": false
}
}
}
],
"routing":{
"rules":[
{
"type":"field",
"inboundTag":[
"rpi"
],
"outboundTag":"vps" // 路由很重要,把rpi入站的全部转到vps出站
}
]
}
}客户端的配置与上面其它方案类似
1 | { |
v2ray搭配shadowsocks
- 服务端
1 | { |
- 客户端
1 | { |
- 使用
systemd管理v2ray服务
1 | ~$ cat /etc/systemd/system/v2ray.service |
- 最终可以把两个配置合并成一个配置文件如下:
1 | ~$ cat /etc/v2ray/config.json |
- 使用
geoip文件的需要复制到/usr/share/v2ray目录下
1 | ~$ ls /usr/share/v2ray/geo* |
Android手机客户端
- SagerNet/SagerNet,可以从源码编译,也可以从F-Droid下载。另一个同类型的客户端2dust/v2rayNG,安装后,无法边接到服务器,但是
SagerNet是可以的。具体编译安装参照本文的shadowsocks-android.
shadowsocks-libev
- 编译安装
1
2
3
4
5
6
7
8~$ apt-get install libsodium-dev libmbedtls-dev libev-dev libpcre3-dev libc-ares-dev cmake \
libbloom-dev libcork-dev libc-ares2 libipset-dev -y
~$ git clone https://github.com/shadowsocks/shadowsocks-libev
~$ cd shadowsocks-libev/
~$ git submodule update --init --recursive
~$ cd build/
~$ cmake ../
~$ make && make install
配置ss-server
1 | ~$ sudo mkdir /etc/shadowsocks-libev/ |
配置ss-local
1 | { |
- 在本地运行一个
ss-local -c ./config.json实例,成功连接后,可以使用127.0.0.1:1088的去做Socks5代理了.
SargerNet客户端
1 | ~$ git clone https://github.com/SagerNet/SagerNet |
- maybe should set proxy
1 | ~$ cat ~/.gradle/gradle.properties |
- 更换国内的
maven仓库,参考这里:aliyun
1 | ~$ cat ~/.gradle/init.gradle |
- 使用如下
patch,修改repositories.gradle.kts.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~$ cat ~/aliyun_repo_kts.patch
diff --git a/repositories.gradle.kts b/repositories.gradle.kts
index 39e08561..5a14205f 100644
--- a/repositories.gradle.kts
+++ b/repositories.gradle.kts
@@ -5,8 +5,25 @@ rootProject.extra.apply {
}
repositories {
+ maven {
+ url = uri("https://maven.aliyun.com/repository/apache-snapshots")
+ }
+ maven {
+ url = uri("https://maven.aliyun.com/repository/public")
+ }
+ maven {
+ url = uri("https://maven.aliyun.com/repository/central")
+ }
+ maven {
+ url = uri("https://maven.aliyun.com/repository/google")
+ }
+ maven {
~ SagerNet$ patch -p1 < ~/aliyun_repo_kts.patch
~$ cat ~/aliyun_repo_gradle.patch
diff --git a/build.gradle b/build.gradle
index 585475bd..c7224bd5 100644
--- a/build.gradle
+++ b/build.gradle
@@ -17,6 +17,21 @@
buildscript {
apply from: rootProject.file("gradle/versions.gradle")
repositories {
+ maven {
+ url "https://maven.aliyun.com/repository/apache-snapshots"
+ }
+ maven {
+ url "https://maven.aliyun.com/repository/public"
+ }
+ maven {
+ url "https://maven.aliyun.com/repository/central"
+ }
+ maven {
+ url "https://maven.aliyun.com/repository/google"
+ }
+ maven {
+ url "https://maven.aliyun.com/repository/jcenter"
+ }
google()
mavenCentral()
}
@@ -31,6 +46,22 @@ buildscript {
allprojects {
apply from: rootProject.file("gradle/ktlint.gradle")
repositories {
+ maven {
+ url "https://maven.aliyun.com/repository/apache-snapshots"
+ }
+ maven {
+ url "https://maven.aliyun.com/repository/public"
+ }
+ maven {
+ url "https://maven.aliyun.com/repository/central"
+ }
+ maven {
+ url "https://maven.aliyun.com/repository/google"
+ }
+ maven {
+ url "https://maven.aliyun.com/repository/jcenter"
+ }
+
google()
mavenCentral()
}
@@ -44,4 +75,4 @@ task installGitHook(type: Copy) {
from new File(rootProject.rootDir, 'pre-commit')
into { new File(rootProject.rootDir, '.git/hooks') }
fileMode 0777
-}
\ No newline at end of file
+}
~ SagerNet/external/editorkit$ patch -p1 < ~/aliyun_repo_gradle.patch
shadsowsocks-android客户端
下载源码并设置编译环境
1
2
3
4
5
~$ git clone --recurse-submodules https://github.com/shadowsocks/shadowsocks-android
~$ cd shadowsocks-android && git submodule update --init --recursive
~$ cd core/src/main/rust/shadowsocks-rust
~$ rustup target add armv7-linux-androideabi aarch64-linux-android i686-linux-android x86_64-linux-android这里可以用使用
sdkman安装java的开发环境:jdk,gradle. 如果本机支持IPv6连接,可能需要设如下变量:
1 | ~$ export _JAVA_OPTIONS="-Djava.net.preferIPv6Addresses=true" |
- 还需要安装
rust的开发环境。
1 | ~$ rustup target add aarch64-linux-android |
- 编译错误,如下所示,需要设置:
export _JAVA_OPTIONS="-Djava.net.preferIPv6Addresses=true -Dhttps.protocols=TLSv1.2".
1 | FAILURE: Build failed with an exception. |
rust编译错误,这里只需按提示处理就可以了.运行rustup target add armv7-linux-androideabi后再重新运行编译。
1 | Compiling parking_lot_core v0.9.3 |
- 编译错误
1 | error[E0554]: `#![feature]` may not be used on the stable release channel |
- 上面的错误,是因为
rust的工具链不匹配造成的。按如下操作使用nightly版本的工具链。
1 | ~$ rustup toolchain list |
- 再继续编译工程
1 | ~$ git pull --recurse-submodules |
安装apk
- 生成
apk自签名用的key
1 | ~$ keytool -genkey -v -keystore ~/.android/lcy-release.keystore -alias self-build-signed -keyalg RSA -keysize 2048 -validity 10000 |
- 查看目标手机的CPU架构。
1 | $ adb shell getprop ro.product.cpu.abi |
- 对目标安装文件进行
zip压缩对齐
1 | shadowsocks-android$ export PATH=~/Android/Sdk/build-tools/33.0.0:$PATH |
- apk签名
1 | shadowsocks-android$ apksigner sign --ks ~/.android/lcy-release.keystore --out shadowsocks-android-master-$(date +%Y-%m-%d)-signed.apk mobile-arm64-v8a-release-unsigned-aligned.apk |
- 安装apk
1 | shadowsocks-android/mobile/build/outputs/apk/release$ adb install shadowsocks-android-master-2022-08-28-signed.apk |
使用Cloudflare
发现在使用
cloudflare有几个前提,1.需要有一个域名,2.网站访问必须支持TLS/HTTPS,而且我这里使用的是Full(strict)模式:Encrypts end-to-end, but requires a trusted CA or Cloudflare Origin CA certificate on the server.域名我是在dynadot上注册的,选了一个15元一年的域名。先在https://www.cloudflare.com注册一个帐号,在
dash -> Websites -> Add a Site,添加刚才注册的域名,如:example.com。进入example.com站点内,查看DNS -> Records -> Cloudflare Nameservers,会为这个example.com域名分配两个域名服务器NS. 再进入到dynadot -> My Domains -> Name Servers删除默认的dynadot提供的NS,添加cloudflare分配的这两个NS链接。
使用Nginx代理v2ray+headscale
- 先在
DNS -> Records -> Cloudflare Nameservers添加两个A 记录, 如:vmss.example.com,headscale.example.com,这里必须这两个主机名申请到证书,如上面用acme.sh去申请。这里原来走了一些弯路使用了cloudflare -> SSL/TLS -> Edge Certificates,导致下面的验证无法成功。
1 | ~$ cat /etc/nginx/sites-enabled/ssl |
headscale的配置部署就如上面所述,v2ray的配置是基于ws,没有设置TLS加密,TLS交给Nginx反向代理去处理。
1 | ~$ cat /etc/v2ray/config.json |
错误
1 | rejected proxy/vmess/encoding: invalid user > proxy/vmess: Not Found |
- 上面错误,很有可能是有客户端与服务器的时间不对,需要与世界时钟服务器去同步。
URI与二维码
在一些移动APP中,为了安全或是方便分享,可以使用二维码来添加服务器.它的最终格式如下:
1
ss://YmYtY2ZiOnRlc3QvIUAjOkAxOTIuMTY4LjEwMC4xOjg4ODg#example-server
示例,如有一个服务器是
192.168.100.1:8888,使用bf-cfb的加密算法,密码是test/!@#:,它的明文URI是:
ss://bf-cfb:test/!@#:@192.168.100.1:8888,需要把它编码BASE64格式的URI,下面通过浏览器的Web Console运行:1
2> console.log( "ss://" + btoa("bf-cfb:test/!@#:@192.168.100.1:8888") )
ss://YmYtY2ZiOnRlc3QvIUAjOkAxOTIuMTY4LjEwMC4xOjg4ODg=现在可以把
BASE64URI再编码成二维码,还可以加名字标记如:ss:<BASE64>#<server-name>,quick-guide的后面生成二维的工具,IOS系统中的客户端名字是Outline App,它就是只能通过URI来添加服务器.
配置Systemd服务
- 这里可以参照上面
trojan的系统服务,也可以直接复制shadowsocks-libev/debian/shadowsocks-libev.service到系统目录下.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24~$ sudo cp shadowsocks-libev/debian/shadowsocks-libev.default /etc/default/shadowsocks-libev
~$ sudo cat > '/etc/systemd/system/shadowsocks-libev.service' < EOF
[Unit]
Description=Shadowsocks-libev Default Server Service
Documentation=man:shadowsocks-libev(8)
After=network-online.target
[Service]
Type=simple
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_BIND_SERVICE
EnvironmentFile=/etc/default/shadowsocks-libev
User=nobody
Group=nogroup
LimitNOFILE=32768
ExecStart=/usr/local/bin/ss-server -c $CONFFILE $DAEMON_ARGS
[Install]
WantedBy=multi-user.target
EOF
~$ sudo systemctl daemon-reload
~$ sudo systemctl start shadowsocks-libev
插件部分
- shadowsocks-libev可以安装obfs做数据混淆.
使用Docker安装
- How to Assign IPv6 Addresses to LXD Containers on a VPS
- Getting universally routable IPv6 Addresses for your Linux Containers on Ubuntu 18.04 with LXD 4.0 on a VPS
- IPv6 neighbour proxy
- Use IPv6-enabled Docker containers
- IPv6 with Docker
- Docker IPV6 Guide
Dokku安装
- 这里为什么要用
Dokku?本来一个Dockfile直接用Docker就可以,但是关于trojan要用到letscrypt证书的问题,这里还是使用Dokku来完成它.
1 | ~$ wget https://raw.githubusercontent.com/dokku/dokku/v0.21.4/bootstrap.sh; |
安装Brook
它可能是目前最灵活,但同时又保持了较高易用性的架设方法.支持多协议多模式,跨平台也比其它技术好.它是用GO语言写的,这里也是不想从源码编译,直接去下载一个最新使用.下面会是一些使用示例,最完整的还参考它的Wiki,安装(install-cli)参考
服务端
1 | ~$ ./brook server -l :8118 -p passwd1 |
- 客户端
1 | ~# ./brook client -l 127.0.0.1:4444 -i 127.0.0.1 -s <serverip>:8118 -p passwd1 |
使用systemd管理
创建如下文件,服务端与客户端类似,如果要在
systemd内监听小于1024的端口,需要开启CapabilityBoundingSet=CAP_NET_BIND_SERVICE,AmbientCapabilities=CAP_NET_BIND_SERVICE两项.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23~$ cat /etc/systemd/system/brook.service
[Unit]
Description=Brook service
Documentation=https://github.com/txthinking/brook
After=network.target network-online.target nss-lookup.target
[Service]
ExecStart=/usr/bin/brook $DAEMON_ARGS
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_BIND_SERVICE
Restart=always
RestartSec=10
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=brook
EnvironmentFile=/etc/default/brook
User=nobody
Group=nogroup
LimitNOFILE=500000
LimitNPROC=500000
[Install]
WantedBy=multi-user.target环境参数文件
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~$ cat>/etc/default/brook<<EOF
# brook Upstart and SysVinit configuration file
#
# THIS FILE DOES NOT APPLY TO SYSTEMD
#
# Please see the documentation for "systemd drop-ins":
# https://docs.docker.com/engine/admin/systemd/
#
# Use brook --help to modify the daemon startup options.
# Extra command line arguments
DAEMON_ARGS='client -s <your service>:443 --socks5 127.0.0.1:1080 -p <your password>'
# Enable during startup?
START=yes
# User and group to run the server as
USER=nobody
GROUP=nogroup
# Number of maximum file descriptors
MAXFD=32768
EOF
1 | ~$ sudo systemctl enable brook |
FRP服务
编译源码
1 | ~$ git clone https://github.com/fatedier/frp |
使用docker运行
1 | FROM golang:1.17 AS builder |
服务端配置
1 | ~$ cat /etc/frps.ini |
加入Systemed服务
1 | ~$ cat /etc/systemd/system/frps.service |
被控端
P2P Mode
*xtcpis designed for transmitting large amounts of data directly between clients. A frps server is still needed, as P2P here only refers the actual data transmission.
1 | ~$ cat .config/frpc.ini |
运行
1
2
3
4
5
62021/06/04 23:17:52 [I] [service.go:304] [294f53354ddf974b] login to server success, get run id [294f53354ddf974b], server udp port [7002]
2021/06/04 23:17:52 [I] [proxy_manager.go:144] [294f53354ddf974b] proxy added: [win10 zkfd jenkins build_ssh osx]
2021/06/04 23:17:52 [I] [control.go:180] [294f53354ddf974b] [build_ssh] start proxy success
2021/06/04 23:17:52 [I] [control.go:180] [294f53354ddf974b] [win10] start proxy success
2021/06/04 23:17:52 [I] [control.go:180] [294f53354ddf974b] [zkfd] start proxy success
2021/06/04 23:17:52 [I] [control.go:180] [294f53354ddf974b] [osx] start proxy success或者命令行的方式
1
2~$ frpc xtcp --sk aabbcc123 -s <your server address>:7001 --proxy_name osx --uc --ue --local_ip 127.0.0.1 --local_port 5901 -t 1122aabbcc
控制端
1 | cat .config/frpc.ini |
控制端运行
1
2
3
4
5
6
7
82021/06/07 21:30:13 [I] [service.go:304] [b6d7adb82bbcd374] login to server success, get run id [b6d7adb82bbcd374], server udp port [7002]
2021/06/07 21:30:13 [I] [visitor_manager.go:86] [b6d7adb82bbcd374] start visitor success
2021/06/07 21:30:13 [I] [visitor_manager.go:86] [b6d7adb82bbcd374] start visitor success
2021/06/07 21:30:13 [I] [visitor_manager.go:86] [b6d7adb82bbcd374] start visitor success
2021/06/07 21:30:13 [I] [visitor_manager.go:86] [b6d7adb82bbcd374] start visitor success
2021/06/07 21:30:13 [I] [visitor_manager.go:86] [b6d7adb82bbcd374] start visitor success
2021/06/07 21:30:13 [I] [visitor_manager.go:86] [b6d7adb82bbcd374] start visitor success命令行运行.
1
~$ frpc xtcp --role visitor --server_name osx --sk aabbcc123 -s <your server address>:7001 --uc --ue --bind_addr 127.0.0.1 --bind_port 6900 -t 1122aabbcc
在本机或者局域网内运行
控制端后,就可以通过它去连接的服务器上的服务了.如:连接到p2p_ssh_visitor,直接ssh user@127.0.0.1 -p 23222.
*frp本身支持直接暴露HTTP web服务,如果只内网的一些私用的web服务,也可以在frp的代理下,再进行一次SSH本地代理转发,下面是通过SSH -L把对端局域内的某一个8080服务转发本地的8080,如:
1 | ~$ ssh -L 8080:172.17.0.56:8080 user@127.0.0.1 -p 23222 -fNTC |
TLS加密通信
1 | ~$ cat generate_cs_cert.sh |
测试证书
1 | ~$ openssl s_server -cert server.crt -key server.key -accept 1443 -www |
- 可以使用浏览器打开,也可以使用下面命令测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15openssl s_client -connect localhost:1443
CONNECTED(00000003)
Can't use SSL_get_servername
depth=0 C = US, ST = VA, L = SomeCity, O = MyCompany, OU = MyDivision, CN = 66.228.37.43
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 C = US, ST = VA, L = SomeCity, O = MyCompany, OU = MyDivision, CN = 66.228.37.43
verify error:num=21:unable to verify the first certificate
verify return:1
---
Certificate chain
0 s:C = US, ST = VA, L = SomeCity, O = MyCompany, OU = MyDivision, CN = 66.228.37.43
i:CN = 66.228.37.43
---
[...]
服务端证书配置
1 | [common] |
客户端证书配置
1 | [common] |
- 注意,如果开始
TLS后,[common] -> server_addr就必须是证书里的SAN,不要使用/etc/hosts里的映射,否则会报如下:
1 | 2021/06/13 23:58:22 [W] [service.go:104] login to server failed: x509: certificate is not valid for any names, but wanted to match xxx |
使用Cloudflare Warp原生IP
Install cloudflare-warp Client
First, install the repository’s GPG key:
1
curl https://pkg.cloudflareclient.com/pubkey.gpg | sudo gpg --yes --dearmor --output /usr/share/keyrings/cloudflare-warp-archive-keyring.gpg
Then add the repository to your machine’s apt sources:
1 | echo "deb [arch=amd64 signed-by=/usr/share/keyrings/cloudflare-warp-archive-keyring.gpg] https://pkg.cloudflareclient.com/ $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/cloudflare-client.list |
Configure WARP
- If you are first install, your need register an account before using it. That register information will store at
/var/lib/cloudflare-warp/reg.json.
1 | ~$ wrap-cli register |
- And then set the proxy mode, this step is very important because the default mode is
WARPmode, that will bring your wholeVPSinto the thecloudflare VPN Network,and then you will lose the connection with your VPS.
1 | ~$ warp-cli set-mode proxy |
- After that, you can use
wrap-cli settingsto view your configuration.You can also check the the configration to determine if it was success configured. configure file store at/var/lib/cloudflare-warp/settings.json.
Connection to WARP and then verify it
1 | ~$ warp-cli connect |
- When the connection is successful, your system will have a “Socks5” proxy daemon which listens to “127.0.0.1:40000”, you can use the following command to check if WARP is proxied successfully.
1 | ~$ curl -x "socks5://127.0.0.1:40000" ipinfo.io |
- If you saw the kind of text output like above, it’s indicates that WARP configure right and work fine. However, if you see some of warnings during connection, such as the following WARP warning.
1 | ~$ warp-cli connect |
- You should edit the
/lib/systemd/system/warp-svc.servicelike the following:
1 | [Service] |
customize v2ray route
- The following configuration enables some domains or IP addresses to pass through the WARP proxy.
1 | { |
- As you can see at above
"openai.com","disneyplus.com",...will go through the WARP proxy.