Debian & Ubuntu 搭建部署 trojan-go + Nginx + WebSocket 并使用 CloudFlare

Contents
  1. 1. 准备工作
    1. 1.1. 服务器与域名
    2. 1.2. 内容准备
    3. 1.3. CloudFlare 设置
    4. 1.4. 安装所需基本工具
    5. 1.5. 服务器防火墙配置
    6. 1.6. 查看 nobody 的用户组
    7. 1.7. 添加用户脚本
  2. 2. 安装并配置 trojan-go
    1. 2.1. 安装
    2. 2.2. 设置自启
    3. 2.3. 配置
  3. 3. 安装并配置 Nginx
    1. 3.1. 安装 nginx
    2. 3.2. 配置
    3. 3.3. 启用配置
  4. 4. 利用 acme.sh 生成证书
    1. 4.1. 准备工作
    2. 4.2. 生成证书
    3. 4.3. 安装证书
    4. 4.4. 设置读取权限
  5. 5. 设置定时任务
  6. 6. 启动服务
  7. 7. 客户端配置文件
  8. 8. References

本文最后更新于 2024 年 2 月 25 日


本文以 Debian 12 为例,介绍如何搭建 trojan-go + WebSocket 服务端,使用 Nginx 建立 Web,并利用 CloudFlare 隐藏源站 IP,最后说明对应的客户端配置文件的格式。本文同样完全适用于 Ubuntu 22.04 系统。

注:请先参照 Debian & Ubuntu 服务器的初始化配置 一文对服务器进行各种必要的配置。本文以 sammy 用户为例,进行 trojan-go 的部署,并默认已按初始化配置文章对服务器进行了配置。


准备工作

服务器与域名

  1. 可用的公网 IP 服务器(例如在 BandwagonHostVultr 等处购买的 VPS)
  2. 注册一个域名,本文以 example.com 为例

内容准备

  1. 起一个随机的路径名,本文使用 /random
  2. 准备自定义的 Web 页面,用于浏览器正常访问 example.com 显示的网页
  3. 准备自定义的 404 页面(可选)

CloudFlare 设置

  1. 将域名的 Namesever 指向 CloudFlare 所提供的地址,等待生效
  2. NS 记录更新后,将 CloudFlare 中域名的 A 记录指向服务器 IP,确保云朵为橙色(Proxied)
  3. SSL/TLS 版块中的 Overview 里,将加密模式调整为 Full (strict)
  4. SSL/TLS 版块中的 Edge Certificates 里,将 Minimum TLS Version 调整为 TLS 1.3,并在下方确保开启对 TLS 1.3 的支持
  5. Firewall 版块中的 Firewall Rules 里,添加一个规则,允许 /random 路径的访问(Allow URI path)
  6. 在 CloudFlare 上获取域名的 Zone ID,记录之
  7. 在 CloudFlare 的 My Profile 中生成一个 API Token,权限为 Zone DNS EditZone Resources 特指区域为 example.com,完成后记下 Token
  8. 根据自己的需要在 CloudFlare 上进行其他设置(可选),例如配置 Always Use HTTPSHSTSAutomatic HTTPS RewritesAuto 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.sh
1
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.sh
1
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.sh
1
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 定时任务:

1
sudo crontab -e

首行开始,添加如下内容,代表每日服务器时间 03:05 自动更新 ip 列表:

1
2
MAILTO=""
5 3 * * * /bin/bash /root/scripts/ufw/update.sh

查看 nobody 的用户组

执行命令:

1
id 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

添加如下内容,注意替换其中的 sammynobody:nogroup(如有必要):

~/scripts/acme.sh
1
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 trojan-go

执行以下命令:

1
vim ~/scripts/cert.sh

添加如下内容:

~/scripts/cert.sh
1
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"

至此,准备工作已完成。


安装并配置 trojan-go

安装

设置一个本地安装脚本:

1
vim ~/scripts/trojan.sh

添加如下内容:

~/scripts/trojan.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
#!/bin/bash

NOCOLOR="\033[0m"
GREEN="\033[0;32m"

echo -e "\n${GREEN}Installing trojan-go...${NOCOLOR}\n"

if [ $# -eq 1 ];then
echo -e "${GREEN}Do not add parameters! Exiting...${NOCOLOR}\n"
exit
fi

read -p "Fill the version: " version

cd ~/scripts
proxychains wget https://github.com/p4gefau1t/trojan-go/releases/download/v$version/trojan-go-linux-amd64.zip

if [ -f "trojan-go-linux-amd64.zip" ]; then
sudo unzip -o trojan-go-linux-amd64.zip -d /usr/local/bin/trojan-go
else
echo -e "\n\033[0;31mDownloading trojan-go v$version failed!${NOCOLOR}\n"
exit
fi

rm -f trojan-go-linux-amd64.zip

sudo systemctl restart trojan-go

echo -e "\n${GREEN}Installed trojan-go v$version!${NOCOLOR}\n"

此处以 trojan-go v0.8.2 为例,最新版本可见此处,请根据实际最新版本号调整下方输入:

1
2
sudo chmod -R 400 ~/scripts && chmod 700 ~/scripts
bash ~/scripts/trojan.sh

将要求输入版本号,此例中输入 0.8.2,回车继续。

设置自启

新建服务文件:

1
sudo vim /etc/systemd/system/trojan-go.service

添加如下内容:

/etc/systemd/system/trojan-go.service
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[Unit]
Description=Trojan-Go
Documentation=https://github.com/p4gefau1t/trojan-go
After=network.target nss-lookup.target

[Service]
User=nobody
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
NoNewPrivileges=true
ExecStart=/usr/local/bin/trojan-go/trojan-go -config /usr/local/etc/trojan-go/config.json
Restart=on-failure
RestartSec=10

[Install]
WantedBy=multi-user.target

启用服务:

1
sudo systemctl enable trojan-go

配置

编辑配置文件,注意替换其中的 sammy 为当前用户名,替换其中的 随机的密码sammyexample.com/random加密所用密码

1
2
sudo mkdir -p /usr/local/etc/trojan-go
sudo vim /usr/local/etc/trojan-go/config.json
/usr/local/etc/trojan-go/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
{
"run_type": "server",
"local_addr": "0.0.0.0",
"local_port": 443,
"remote_addr": "127.0.0.1",
"remote_port": 80,
"password": [
"随机的密码"
],
"ssl": {
"cert": "/home/sammy/certs/example.com.crt",
"key": "/home/sammy/certs/example.com.key",
"sni": "example.com",
"fallback_addr": "127.0.0.1",
"fallback_port": 11443
},
"router":{
"enabled": true,
"block": [
"geoip:private"
]
},
"websocket": {
"enabled": true,
"path": "/random",
"host": "example.com"
},
"shadowsocks": {
"enabled": true,
"method": "AES-256-GCM",
"password": "加密所用密码"
}
}

注:随机的密码加密所用密码 应该使用不同密码。


安装并配置 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/default
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
server {
listen 80 default_server;
listen [::]:80 default_server;

server_name _;

return 400;
}

server {
listen 11443 ssl default_server;
listen [::]:11443 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

注意替换其中的 example.com 为实际域名:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
server {
listen 80;
listen [::]:80;

server_name example.com;

root /var/www/example.com/html;
index index.html;
error_page 404 /404/index.html;

location / {
try_files $uri $uri/ =404;
}
}

注意,如果不需要设置自定义 404 页面,则删去:

1
error_page 404 /404/index.html;

接着,通过 scprsync 上传之前在本地准备好的 Web 页面文件、资源文件夹到 /var/www/example.com/html 中去。例如:

1
rsync -ruhP --delete public/ sammy_host:/var/www/example.com/html/

其中,网页文件都存放在本地 public 文件夹中,服务器别名为 sammy_hostpublic 文件夹结构为:

  • public/
    • 404/
      • ...
      • index.html
    • ...
    • index.html

启用配置

1
sudo ln -s /etc/nginx/sites-available/exmaple.com /etc/nginx/sites-enabled/

至此,Nginx 部分已经配置完毕。


利用 acme.sh 生成证书

准备工作

安装依赖:

1
sudo apt update && sudo apt install socat -y

安装 acme.sh

1
wget -O - https://get.acme.sh | sh

修改 sudoer 文件:

1
sudo visudo

最后一行新增,注意替换其中的 sammy 为当前的真实用户名,并注意此示例采用的是 nobody:nogroup

1
2
3
4
sammy ALL=(ALL) NOPASSWD: /usr/sbin/service nginx force-reload
sammy ALL=(ALL) NOPASSWD: /bin/systemctl restart trojan-go
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 "bash ~/scripts/cert.sh && sudo service nginx force-reload"

设置读取权限

下面以 nobody:nogroup 为例:

1
sudo chown -R nobody:nogroup ~/certs

设置定时任务

编辑定时任务:

1
crontab -e

删除掉其中 acme.sh 自动生成的定时任务行。

添加如下内容,保存并退出:

1
9 0 * * * /bin/bash ~/scripts/acme.sh

启动服务

1
sudo systemctl restart trojan-go

至此,服务端已部署完成。


客户端配置文件

注意替换下方的 example.com服务端所设置的随机密码/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
{
"run_type": "client",
"local_addr": "127.0.0.1",
"local_port": 1085,
"remote_addr": "example.com",
"remote_port": 443,
"password": [
"服务端所设置的随机密码"
],
"ssl": {
"sni": "example.com"
},
"router":{
"enabled": true,
"bypass": [
"geoip:cn",
"geoip:private",
"geosite:cn",
"geosite:geolocation-cn"
],
"block": [
"geosite:category-ads"
],
"proxy": [
"geosite:geolocation-!cn"
],
"default_policy": "proxy"
},
"websocket": {
"enabled": true,
"path": "/random",
"host": "example.com"
},
"shadowsocks": {
"enabled": true,
"method": "AES-256-GCM",
"password": "服务端所设置的加密密码"
}
}

此设置的代理监听在 socks5://127.0.0.1:1085 上。

而如果是利用了 socat 来中转流量,那么客户端的配置则可见下方,注意替换下方的 中转服务器 IP中转服务器端口服务端所设置的随机密码/randomexample.com服务端所设置的混淆密码

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
{
"run_type": "client",
"local_addr": "127.0.0.1",
"local_port": 1085,
"remote_addr": "中转服务器 IP",
"remote_port": 中转服务器端口,
"password": [
"服务端所设置的随机密码"
],
"ssl": {
"sni": "example.com"
},
"router":{
"enabled": true,
"bypass": [
"geoip:cn",
"geoip:private",
"geosite:cn",
"geosite:geolocation-cn"
],
"block": [
"geosite:category-ads"
],
"proxy": [
"geosite:geolocation-!cn"
],
"default_policy": "proxy"
},
"websocket": {
"enabled": true,
"path": "/random",
"host": "example.com"
},
"shadowsocks": {
"enabled": true,
"method": "AES-256-GCM",
"password": "服务端所设置的加密密码"
}
}

此设置的代理监听在 socks5://127.0.0.1:1085 上。


References

Trojan-Go Docs

自建梯子教程 – Trojan 版本

Trojan 手动安装教程

trojan 教程

Insufficient permissions when using certificates

Mastodon