diff --git a/README.md b/README.md index 21ff005..ba60352 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,7 @@ _\* 使用 WatchTower 可以自动更新面板,Windows 终端可以使用 nssm - `--disable-auto-update` 禁止 **自动更新** Agent(安全特性) - `--disable-force-update` 禁止 **强制更新** Agent(安全特性) - `--disable-command-execute` 禁止在 Agent 机器上执行定时任务、打开在线终端(安全特性) +- `--tls` 启用SSL/TLS加密(使用 nginx 反向代理 Agent 的 grpc 连接,并且 nginx 开启 SSL/TLS 时,需要启用该项配置) ## 功能说明 @@ -320,6 +321,34 @@ restart() { +
+ Agent 连接 Dashboard 域名开启 Cloudflare CDN +根据 Cloudflare gRPC 的要求:gRPC 服务必须侦听 443 端口 且必须支持 TLS 和 HTTP/2。我们可以使用 nginx 反向代理 gRPC 并配置 SSL/TLS 证书。 + +- nginx 配置,比如 Agent 连接 Dashboard 的域名为 ip-to-dashboard.nai.ba,为 nginx 添加如下配置,然后重新启动 nginx 或者重新加载配置文件。 +```nginx +server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + server_name ip-to-dashboard.nai.ba; # 你的 Agent 连接 Dashboard 的域名 + + ssl_certificate /data/letsencrypt/fullchain.pem; # 你的域名证书路径 + ssl_certificate_key /data/letsencrypt/key.pem; # 你的域名私钥路径 + + underscores_in_headers on; + + location / { + grpc_pass grpc://localhost:5555; + } +} +``` +- Agent 端配置,编辑 `/etc/systemd/system/nezha-agent.service`,在 `ExecStart=` 这一行的末尾加上 `--tls`,然后重启 nezha-agent.service。例如: +```bash +ExecStart=/opt/nezha/agent/nezha-agent -s ip-to-dashboard.nai.ba:443 -p xxxxxx --tls +``` +- 在 Cloudflare 中将对应的域名解析设置橙色云开启CDN,并在网络选项中启用gRPC。 +
+ ## 社区文章 - [哪吒探针 - Windows 客户端安装](https://nyko.me/2020/12/13/nezha-windows-client.html) diff --git a/cmd/agent/main.go b/cmd/agent/main.go index 71510c5..06a6979 100644 --- a/cmd/agent/main.go +++ b/cmd/agent/main.go @@ -2,6 +2,7 @@ package main import ( "context" + "crypto/tls" "encoding/json" "errors" "fmt" @@ -18,6 +19,7 @@ import ( "github.com/p14yground/go-github-selfupdate/selfupdate" flag "github.com/spf13/pflag" "google.golang.org/grpc" + "google.golang.org/grpc/credentials" "github.com/naiba/nezha/cmd/agent/monitor" "github.com/naiba/nezha/cmd/agent/processgroup" @@ -38,6 +40,7 @@ type AgentConfig struct { Server string ClientSecret string ReportDelay int + TLS bool } var ( @@ -80,6 +83,7 @@ func main() { flag.BoolVar(&agentConf.DisableCommandExecute, "disable-command-execute", false, "禁止在此机器上执行命令") flag.BoolVar(&agentConf.DisableAutoUpdate, "disable-auto-update", false, "禁用自动升级") flag.BoolVar(&agentConf.DisableForceUpdate, "disable-force-update", false, "禁用强制升级") + flag.BoolVar(&agentConf.TLS, "tls", false, "启用SSL/TLS加密") flag.Parse() if agentConf.ClientSecret == "" { @@ -138,7 +142,13 @@ func run() { for { timeOutCtx, cancel := context.WithTimeout(context.Background(), networkTimeOut) - conn, err = grpc.DialContext(timeOutCtx, agentConf.Server, grpc.WithInsecure(), grpc.WithPerRPCCredentials(&auth)) + var securityOption grpc.DialOption + if agentConf.TLS { + securityOption = grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{MinVersion: tls.VersionTLS12})) + } else { + securityOption = grpc.WithInsecure() + } + conn, err = grpc.DialContext(timeOutCtx, agentConf.Server, securityOption, grpc.WithPerRPCCredentials(&auth)) if err != nil { println("与面板建立连接失败:", err) cancel()