选购VPS
- 这里选择尝试使用Linode来做VPS,如果预算购的可以选择高配,一般可以选择
Standard Linode plan
10刀一月,我只选了Nanodes
5刀一月,具体参数请查看它的官网,注册时可以提供这个推荐码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=现在可以把
BASE64
URI再编码成二维码,还可以加名字标记如: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
*xtcp
is 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
WARP
mode, that will bring your wholeVPS
into 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 settings
to 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.service
like 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.