本文不过多赘述 Naiveproxy 的特点和原理,也不介绍与其他工具的区别及优缺,仅仅从运维实践的角度分享服务端部署和客户端使用的操作记录。

依赖

  • 服务器环境:centos 8.5
  • 客户端:macos
  • go 版本:go1.23.3
  • naiveproxy 版本:v131.0.6778.86-1

背景介绍

有个 TrippleCloud 的 CN2 GIA+CU+CM 三网直连 vps,一直使用 trojan-go 部署提供的魔法服务,可是每隔几个月会抽风一次,通常需要切换服务端口亦或者更新 ssl 证书,才能恢复正常使用,同时因为之前的 ip 被 ChatGPT 给 block ,在原有 ip 的基础上使用 warp-go 套了一层。

导致每次 trojan 的配置操作较为繁琐(trojan 服务抽风及网络配置优化,一直懒得研究),曾经也浅浅了解过 naiveproxy,看相关论坛里面的评价说是较为稳定,索性切换魔法生态,好好体验一下 naiveproxy。

搭建步骤

服务端 naiveproxy 部署

1. 编译 caddy 可执行文件

xcaddy 是包含 naiveproxy 的特殊 caddy 分支,naiveoproxy 依赖 caddy 来实现其协议,具体原理可以参考官方 wiki 了解。

连接服务器后,先按照 naiveproxy 仓库的 wiki 简中教程尝试部署。但实际情况下服务器环境和 go 版本会导致安装命令行无法得到期望的成功。先需要确保服务器存在 go 环境,且 go version >=1.21,建议步骤如下

  • 创建操作目录并进入

    mkdir /opt/naiveproxy & cd /opt/naiveproxy
    
  • 初始化 xcaddy 模块

    go mod init xcaddy
    

    见 FAQ-1,初始化一个 xcaddy 模块作为 go 模块,go get 才不会报错

  • 拉取 xcaddy 模块

    go get -u github.com/caddyserver/xcaddy/cmd/xcaddy
    
  • 包含 naïve 的 caddy forwardproxy 分支,也就是上面拉取的 xcaddy 模块

    ~/go/bin/xcaddy build --with github.com/caddyserver/forwardproxy@caddy2=github.com/klzgrad/forwardproxy@naive
    

    编译可能会出现 FAQ-2 所在错误,需要将 go 版本升级到 1.21 及以上。编译比较耗时,博主 1h 的 vps 耗时 10min+,编译结束后当前目标会生成一个名为 caddy 的可执行文件

  • 赋予 caddy 可执行文件特定权限

    sudo setcap cap_net_bind_service=+ep ./caddy 
    

    为 Caddy 二进制文件赋予特定的权限,使其能够绑定到低端口(即小于 1024 的端口),而无需使用 root 权限。

2. Caddy 配置编写

前置注意

  • 需有一个域名解析到当前 vps 的 ip 上,如果你有域名及 vps 之后,这些基本知识应该无需赘述。
  • 提前为该域名申请好 ssl 证书,并存放在服务器上的某个路径。

在 caddy 当前执行以下命令,创建 Caddyfile 文件,也就是 caddy 及 naiveproxy 一体的配置文件。

如果你想把 Caddyfile 文件放在其他目录,后续执行 caddy start 启动命令时,需要使用 --config 指明 Caddyfile 的路径,如 caddystart --config /etc/caddy/Caddyfile

vi Caddyfile
  • 笔者是参考其他博客,采用反向代理的模式部署,以下配置与官方的参考配置有出入,官方默认配置是当访问提供 naiveproxy 的服务时如果没有携带 username 和 password,就会展示静态 html(魔法服务伪装),而笔者因为参考其他优质博文,直接采用以下配置,当浏览器访问 naiveproxy 会反向代理其他网站,也是起到一定的伪装。
  • 以下配置也实现 tls 配置样例,如无特殊目的,仅需修改 path_to_crtpath_to_keyusernamepasswordhostdomain.com 即可。
  • 笔者的 443 端口已经有其他服务占用,所以采用高位端口(也听人说高位端口较为稳定)
{
	order forward_proxy before route
	admin off
	auto_https off
}

:61443 {
	tls path_to_crt path_to_key {        #path_to_crt和path_to_key分别换为crt和key文件的绝对地址
		ciphers TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
		alpn h2 http/1.1
	}

	forward_proxy {
		basic_auth username password     #username password变更为帐号密码,后面登录用
		hide_ip
		hide_via
		probe_resistance
	}

	@host {
		host hostdomain.com        # naiveproxy使用的域名 
	}
	route @host {
		header {
			Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
		}
		reverse_proxy hostdomain.com {       # proxy的域名,未登录情况下会redirect到这里
			header_up Host {upstream_hostport}
			header_up X-Forwarded-Host {host}
		}
	}
}

3. 启动 Caddy 服务

启动服务命令如下,caddy start 为后台启动

# 启动服务
./caddy start

# 指定配置文件启动
./caddy start --config /etc/caddy/Caddyfile

启动成功会出现

Successfully started Caddy (pid=2131808) - Caddy is running in the background

其他参考命令

# 停止 caddy 服务
./caddy stop

# 检查 caddy 配置,启动前可以执行下,避免影响启动
./caddy validate --config /etc/caddy/Caddyfile

通过如下命令验证服务启动情况

ss -tulpn | grep caddy

执行后会显示

# ss -tulpn | grep caddy
udp   UNCONN 0      0                       *:61443            *:*    users:(("caddy",pid=2131496,fd=6))                            
udp   UNCONN 0      0                       *:61443            *:*    users:(("caddy",pid=2131808,fd=6))                            
tcp   LISTEN 0      128                     *:61443            *:*    users:(("caddy",pid=2131496,fd=3))                            
tcp   LISTEN 0      128                     *:61443            *:*    users:(("caddy",pid=2131808,fd=3)) 

客户端运行

笔者的笔记本是 macos,故直接下载了 https://github.com/klzgrad/naiveproxy/releases/tag/v131.0.6778.86-1 中对应的二进制执行文件。

解压之后修改其中的 config.json 文件

{
  "listen": ["socks://127.0.0.1:1080"],
  "proxy": "https://username:[email protected]:61443", # username,password,hostdomain.com 与服务的配置中的保持一致
  "log": ""
}

配置文件修改好后,在解压文件目录内,执行如下命令

./naive

注意 macos 需要在 隐私和安全性 内信任 naive 的可执行文件,不然命令行无法执行成功

此时,naiveproxy 服务配置及启动成功,本机也会启动一个 1080 socks 端口用于本地代理。笔者使用SwitchyOmega 浏览器插件配置代理地址进行魔法访问服务。(SwitchyOmega 使用方式请读者自行查阅)

FAQ

1. Go 1.17 开始,go get 不再支持在非模块化环境中安装命令

go: go.mod file not found in current directory or any parent directory.
        'go get' is no longer supported outside a module.
        To build and install a command, use 'go install' with a version,
        like 'go install example.com/cmd@latest'
        For more information, see https://golang.org/doc/go-get-install-deprecation
        or run 'go help get' or 'go help install'.

2. Caddy 或其依赖项(例如 log/slogslices)需要 Go 1.21 或更高版本

/usr/local/go/bin/go get -d -v github.com/caddyserver/caddy/v2 
github.com/caddyserver/caddy/v2 imports
        log/slog: package log/slog is not in GOROOT (/usr/local/go/src/log/slog)
note: imported by a module that requires go 1.21
github.com/caddyserver/caddy/v2 imports
        github.com/quic-go/quic-go imports
        github.com/quic-go/quic-go/internal/wire imports
        slices: package slices is not in GOROOT (/usr/local/go/src/slices)
note: imported by a module that requires go 1.21

参考