oynix

于无声处听惊雷,于无色处见繁花

在VPS上搭建Trojan节点

1.前言

前文有提到过,黑五的时候看到RackNerd促销,就买了个便宜的VPS小鸡,一年才$10多点,不幸的是,到手没多久发现IP就被封了,意思就是,国内不能直连VPS了,中间需要一个在国内能访问的海外节点当作代理或者跳板才能访问这个小鸡。

但是,如果说要想更换IP,需要额外支付$3,我觉得这个钱不值得,谁知道即使换了新的又能坚持多久,况且监测之后发现,它用的是较差的线路,慢慢就闲置了。

最近为了处理实际需求,经过精心筛选,在DMIT上买了台CN2GIA线路的VPS,2C3G的配置,要月付$19.9,同等配置比搬瓦工要便宜一点。不得不说,一分钱一分货,处理器的差别实际使用感受不大,但是线路的区别就很明显,尤其是晚高峰的时候,用代理访问不了的网站,用CN2GIA就可以,1.5TB的4Gbps高速流量和不限量的低速流量,如果也有需要可以点下面这个链接有没有合适的,支持支付宝:

DMIT-高性能计算设施

2.介绍

节点是什么?简单来说,可以把节点当作运行在一台机器上的一个进程。在国内无法直接访问Google,但是如果把这个访问请求发给节点进程,因为节点的机器在海外,没有限制,它可以访问Google,它把Google返回的响应,再发给国内的你,这样一来,原本无法访问Google的你,通过一个在海外的节点,也可以顺利访问Google了,当然,这只是一个笼统的介绍,中间有诸多流程和细节。

从上面说的过程可以看出,可以运行节点进程的机器首先需要的就是在国内可以直接访问,也就是VPS IP没有被封,如果被封了,本质和Google也就一样了。只有先访问到它,才有了后面所有的可能。

3.架构设计

1
2
3
4
5
6
7
8
9
Client  

公网 443

Nginx stream

127.0.0.1:8443

sing-box Trojan

架构如上。

节点有很多种类型,比如Shadowsocks、VMess、VLess、Trojan等,因为我正在用的代理节点就是Trojan类型,所以我还是选了Trojan类型,至于sing-box,则是一个代理工具,可以运行节点进程,来提供代理/转发服务。

可以看到,在sing-box前还套了一层nginx,因为这个VPS主要是解决其他需求的,搭建个节点只是额外的小需求,如果只是跑节点,也可以不套nginx。

4.流程

因为买的VPS是裸机器,只有一个系统,我用的体积相对较小的Debian的Linux系统,流程大致如下:

  • 安装sing-box
  • 配置sing-box
  • 增加域名A记录解析
  • 安装证书
  • 安装nginx
  • 配置nginx
  • 配置客户端

4.1 安装sing-box

安装命令如下,官方提供的:

1
curl -fsSL https://sing-box.app/install.sh | sh

交给systemd管理:

1
2
3
4
5
6
sudo systemctl daemon-reload
sudo systemctl enable sing-box
sudo systemctl restart sing-box

# 查看状态
sudo systemctl status sing-box

一般安装后,它会自动在/etc/systemd/system下自动创建service文件,如果执行命令时报错找不到sing-box服务,可以在/lib/systemd/system自己创建sing-box.service文件,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[Unit]  
Description=sing-box
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=sing-box
Group=sing-box
ExecStart=/usr/local/bin/sing-box run -c /etc/sing-box/config.json
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

4.2 配置sing-box

sing-box的配置文件在/etc/sing-box/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
{
"inbounds": [
{
"type": "trojan",
"listen": "127.0.0.1",
"listen_port": 8443,
"users": [
{
"password": "强随机密码"
}
],
"tls": {
"enabled": true,
"server_name": "node.example.com",
"certificate_path": "/etc/letsencrypt/live/node.example.com/fullchain.pem",
"key_path": "/etc/letsencrypt/live/node.example.com/privkey.pem",
"alpn": [
"h2",
"http/1.1"
]
}
}
],
"outbounds": [
{
"type": "direct"
}
]
}

这个配置表明,sing-box只在本机的8443端口提供服务。这里面有2部分需要修改,分别是密码和域名/证书:

  • password:这是客户端配置节点时密码,可通过openssl rand -base64 24随机生成一个
  • server_name/certificate_path/key_path:这个等后面再说,先这样

校验sing-box配置是否正确可通过这个官方提供的命令,现在第二部分的配置还没准备好,执行这个check会报错,是正常的:

1
sudo sing-box check -c /etc/sing-box/config.json

4.3 增加域名A记录解析

这一步来配置上一步缺少的域名/证书部分。前提是需要拥有一个域名,那样这步就很容易了,只需要打开管理域名的网站后台,在DNS解析里添加一条A记录即可,子域名可以随便起名字,但是最好不要起trojan之类的,过于明显了,可能会增加被封锁的概率,可以用个随机字符串,这里就用:abcd,作为举例。

A记录的子域名写abcd,指向的IP地址,就写VPS的IPv4地址,如果在用CloudFlare管理域名,记得要关闭橙色云,这里不需要代理,只需要DNS解析功能,然后保存即可。

大概几分钟之后,应该就可以正常解析了,可以通过下面命令验证,只要正确返回VPS的IP就表示可以了:

1
dig abcd.domain.com

4.4 安装证书

市面上大多的证书都需要付费,提供免费证书的不多,我选的是Let’s Encrypt,这也是多数人的选择,在Debian上通过certbot工具即可完成,同时还可以帮我们自动刷新,因为这个免费的证书有效期只有3个月。

1
2
3
4
5
sudo apt update
sudo apt install -y certbot

# 申请证书
sudo certbot certonly --standalone -d abcd.domain.com

在这一步完成之后,上门所缺少的证书文件就会自动生成:

1
2
/etc/letsencrypt/live/abcd.domain.com/fullchain.pem
/etc/letsencrypt/live/abcd.domain.com/private.pem

把域名和这两个补充到sing-box的配置文件中,至此,sing-box就算配置完成

4.5 安装nginx

这步很简单,直接命令安装:

1
sudo apt install -y nginx

4.6 配置nginx

nginx有两层常见能力,一个是HTTP层,常用来处理浏览器请求,另一个是TCP/UDP层,常用来做转发,所以这里要用steam层来监听443端口

新建/etc/nginx/streams-enabled/trojan.conf文件,如果没有streams-enabled目录,则手动创建,因为这个不是默认自带的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
stream {
map $ssl_preread_server_name $backend_name {
abcd.domain.com trojan_backend;
default trojan_backend;
}

upstream trojan_backend {
server 127.0.0.1:8443;
}

server {
listen 443;
# 暂时不需要IPv6
# listen [::]:443;
proxy_pass $backend_name;
ssl_preread on;
}
}

/etc/nginx/nginx.conf 顶层确认有包含,注意是顶层,和其他include写在一起即可:

1
include /etc/nginx/streams-enabled/*.conf;

编辑完成之后,检查是否正确:

1
sudo nginx -t

这个时候可能会报错,找不到stream,我在操作时就报错,因为stream没有默认安装,需要手动安装:

1
2
3
4
5
6
7
sudo apt install -y libnginx-mod-stream

# 默认会安装到这个目录
/usr/lib/nginx/modules/ngx_stream_module.so

# 可加载配置文件在这里
/usr/share/nginx/modules-available/mod-stream.conf

当模块文件和配置文件都存在时,再执行 nginx -t 就应该不会再报错了。

4.7 配置客户端

我在本地使用的代理客户端是ClashX Meta,早期用的ClashX Pro由于这样那样的原因已经不用了,早前写过一篇文章,说的是如何在ClashX Pro上优雅管理多个订阅,虽然客户端换了,但配置依然能用,地址如下:

如何在ClashX Pro上优雅管理多个订阅

所以,这一步对我来说,只是添加一个本地file类型的proxy-provider,我是直接复制其他代理的配置文件的,然后替换了其中的节点信息,然后再加到proxy里,最后就可以正常使用了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
mixed-port: 7890
allow-lan: true
bind-address: '*'
mode: rule
log-level: info
external-controller: '127.0.0.1:9090'
dns:
enable: false
ipv6: true
default-nameserver: [223.5.5.5, 119.29.29.29, 8.8.8.8]
enhanced-mode: fake-ip
fake-ip-range: 198.18.0.1/16
use-hosts: true
nameserver: ['https://doh.pub/dns-query', 'https://dns.alidns.com/dns-query']
fallback: ['https://doh.dns.sb/dns-query', 'https://dns.cloudflare.com/dns-query', 'https://dns.twnic.tw/dns-query', 'tls://8.8.4.4:853']
fallback-filter: { geoip: true, ipcidr: [240.0.0.0/4, 0.0.0.0/32] }
proxies:
- { name: '[trojan]', type: trojan, server: abcd.domain.com, sni: abcd.domain.com, port: 443, password: 生成的随机密码, udp: false, skip-cert-verify: false }

如上,如果需要的话,仅需替换节点信息中的server和sni为自己的域名,密码复制上面配置sing-box时生成的密码即可。

5.常见问题

5.1 当和tailscale并存时

我在VPS上装了tailscale,为的是有些服务我只希望通过虚拟内网来访问,而不是公开访问,而tailscale也在监听443端口,这个时候执行nginx -t就会报错,它会说443端口已经被占用。不过这种很好解决,监听不同的IP即可。

tailscale监听的443端口的请求,都是要访问它100开头的内网IP,而nginx监听443端口的请求,都是访问的事VPS的IP,tailscale那边不用管,它自己已经配好了,只需要收窄一下nginx监听的请求范围即可。

原本是这么写的:

1
2
3
4
5
6
7
server {
listen 443;
# 暂时不需要IPv6
# listen [::]:443;
proxy_pass $backend_name;
ssl_preread on;
}

改成这样即可,其中的aa.bb.cc.dd就是VPS的公网IPv4地址:

1
2
3
4
5
6
7
server {
listen aa.bb.cc.dd:443;
# 暂时不需要IPv6
# listen [::]:443;
proxy_pass $backend_name;
ssl_preread on;
}

5.2 查询端口占用

1
2
3
4
5
# 查询tcp
sudo ss -lntp

# 查询udp
sudo ss -lnup

输出的内容格式大概是这个样子:

1
2
3
4
5
6
7
8
State      Recv-Q     Send-Q                       Local Address:Port          Peer Address:Port     Process
LISTEN 0 511 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=1581667,fd=6),("nginx",pid=1581666,fd=6),("nginx",pid=101840,fd=6))
LISTEN 0 128 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=40021,fd=3))
LISTEN 0 511 127.0.0.1:4443 0.0.0.0:* users:(("nginx",pid=1581667,fd=8),("nginx",pid=1581666,fd=8),("nginx",pid=101840,fd=8))
LISTEN 0 511 111.11.11.11:443 0.0.0.0:* users:(("nginx",pid=1581667,fd=5),("nginx",pid=1581666,fd=5),("nginx",pid=101840,fd=5))
LISTEN 0 4096 127.0.0.1:8443 0.0.0.0:* users:(("sing-box",pid=64738,fd=8))
LISTEN 0 4096 100.11.11.11:60107 0.0.0.0:* users:(("tailscaled",pid=40505,fd=24))
LISTEN 0 4096 100.11.11.11:443 0.0.0.0:* users:(("tailscaled",pid=40505,fd=26))
  • State:表示状态,因为加了-l参数,所以这列都是LISTEN监听中
  • Rece-Q:接收队列,0表示没有积压的请求
  • Send-Q:发送队列,后面的数字表示监听队列的上限
  • Local Address/Port:监听的地址和接口,这里可以看到nginx只监听发给111.11.11.11:443的请求
  • Peer Address/Port:对端的地址和端口,也就是发请求的一方,都是0表示接受任意来源的连接
  • Process:占用端口的进程信息
------------- (完) -------------
  • 本文作者: oynix
  • 本文链接: https://oynix.com/2026/03/0c27452fd9df/
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

欢迎关注我的其它发布渠道