首个提交。webproxy 是部署在服务器上的 Web 正向代理:打开网页输入任意 URL,由服务器代为请求目标站点,经 HTML/CSS 重写、静态资源代理、 重定向/Cookie/表单处理后回填浏览器,核心场景是经服务器访问其所在 内网的客户网站。 - 开源件:MIT LICENSE、根级 SECURITY.md、CONTRIBUTING.md、 CHANGELOG.md、Makefile、CI(gofmt/vet/build/test) - 安全止损:.gitignore 排除 debug.log(含内网 IP)/二进制/调试散文件/ 本地 config.json;config.example.json 默认 blacklist,不关 SSRF - module 路径规范化为 github.com/yexuejc/webproxy - 测试:新增 proxy_test.go(URL 编解码/子域解析/SSRF 分类/Origin 改写); tests/cookietest 手工 E2E 程序加 build tag 并拆为独立子包,不污染 go test ./... - 注释:全部 Go 源码按函数作用/场景/入参/出参 + 分支 + 变量标准补齐 - 清理:删除旧"浏览器持有 Cookie"方案弃用代码(rewriteSetCookie/ stripDomainSecure/reCookieDomain/reCookieSecure);会话 Cookie 改由 服务端按 origin 的 jar 持有,绕开跨站 iframe 的 SameSite 扣发
6.5 KiB
部署指南
覆盖四种形态:本地跑通 → 单二进制上服务器 → Docker 一键 → 上 NAS。生产变更前先备份 config.json,确认变更窗口与回退方式。
1. 本地跑通(开发/验证)
前置:Go 1.22+(go.mod 声明 go 1.22,开发机 1.23 验证通过)。
cd webproxy
go run . # 直接跑
# 或编译后运行:
go build -o webproxy . && ./webproxy
浏览器打开 http://127.0.0.1:8765/,输入目标 URL 回车。局域网联调时用 http://<本机IP>:8765/。
调试提示:
- 要看 SSRF 拦截原因:
curl -s "http://127.0.0.1:8765/p/$(printf '%s' 'http://127.0.0.1:9/' | base64 | tr '+/' '-_' | tr -d '=')"会返回 403 + 原因; - 代理到本机目标站时,先临时把
config.json的ssrf.block_loopback改为false,调完改回true。
2. 单二进制上服务器(无 Docker)
# 在有 Go 的机器上交叉编译(服务器是 Linux amd64 时)
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -trimpath -o webproxy .
# 拷贝 webproxy、config.json、static/ 到服务器同一目录(三者相对位置必须保持)
scp -r webproxy config.json static user@server:/opt/webproxy/
ssh user@server 'cd /opt/webproxy && ./webproxy'
static/index.html 与 config.json 都是运行时相对路径读取,缺一个 UI 就 500。建议配 systemd:
# /etc/systemd/system/webproxy.service
[Unit]
Description=webproxy
After=network.target
[Service]
WorkingDirectory=/opt/webproxy
ExecStart=/opt/webproxy/webproxy
Restart=on-failure
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload && sudo systemctl enable --now webproxy
journalctl -u webproxy -f # 看日志
3. Docker 一键部署(推荐上服务器/NAS)
前置:Docker 已装、daemon 在跑、当前用户有权限(不在 docker 组就 sudo 或加组)。
cd webproxy
./deploy.sh # 默认对外 8765
PORT=9000 ./deploy.sh # 自定义对外端口(WEBPROXY_PORT 亦可)
脚本做三件事:检查 Docker → docker build 构建镜像(首次联网拉 golang:1.23-alpine、alpine:3.20)→ 清理同名旧容器后 docker run -d --restart unless-stopped -p ${PORT}:8765。
完成后访问 http://<服务器IP>:8765/。
常用运维命令:
docker logs -f webproxy # 跟踪日志
docker rm -f webproxy # 停止并删除容器
docker images | grep webproxy # 看镜像
3.1 compose 方式
docker compose up -d --build
docker-compose.yml 默认映射 8765:8765;换端口改 ports 段。需要实时覆盖配置(不重打镜像)时取消 volumes 注释:
volumes:
- ./config.json:/app/config.json:ro
挂载后改宿主机
config.json重启容器即生效:docker compose restart。
3.2 镜像说明
- 多阶段构建:编译静态二进制(
CGO_ENABLED=0),运行基座alpine:3.20,打进去ca-certificates(校验目标 HTTPS)与二进制 +config.json+static/index.html; - 容器内固定监听
8765(改监听要改config.json并重新构建); - 带 HEALTHCHECK(每 30s
wget探一次/); .dockerignore已排除webproxy.exe、.git、测试目录,构建上下文干净。
3.3 构建时拉取 Go 依赖失败 / 离线构建
docker compose up -d 或 docker build 在第一步 RUN go mod download 报类似
dial tcp 142.250.x.x:443: connect: connection refused(目标是 proxy.golang.org),
是构建环境无法直连 Google Go 模块代理所致(国内/受限网络常见),与代码无关。
方案 A(推荐,适用大多数网络):Dockerfile 已把模块代理改为国内镜像:
ENV GOPROXY=https://goproxy.cn,https://goproxy.io,https://mirrors.aliyun.com/goproxy/,direct
直接重跑即可:
docker compose up -d --build
# 或
./deploy.sh
方案 B(服务器完全离线 / 纯内网,连 goproxy.cn 也不通):依赖已通过 go mod vendor 预先打包进 vendor/,用离线 Dockerfile 构建,全程不联网:
# vendor/ 已由开发机(能联网)通过 go mod vendor 生成,直接拷到服务器构建:
docker build -f Dockerfile.offline -t webproxy:latest .
docker run -d --restart unless-stopped -p 8765:8765 --name webproxy webproxy:latest
# compose 用户:把 docker-compose.yml 的 build.dockerfile 改为 Dockerfile.offline
若
vendor/缺失(如换了依赖后),在有网的机器执行go mod vendor重新生成,再拷到服务器。.dockerignore已确认未排除vendor/,离线COPY vendor/可正常命中。
4. 上 NAS(群晖 DSM / 威联通 QNAP)
镜像本身无特殊要求,用 NAS 自带的容器管理即可:
群晖 DSM 7+(Container Manager)
- 套件中心安装 Container Manager;
- 项目 → 新增 → 上传
webproxy目录(或docker-compose.yml 内容粘贴),启动; - 或直接用映像方式:把
webproxy目录传到 NAS,ssh 进 NAS 跑./deploy.sh。
威联通(Container Station)
- App Center 安装 Container Station;
- "创建应用程序"导入
docker-compose.yml,或镜像页拉取/构建后创建容器,端口映射8765。
NAS 提示:
- NAS 与目标内网必须路由可达——部署在 NAS 上时它看到的内网就是 NAS 所在网段;
- 只给家里/办公网用就够,别映射到公网;确需公网见 SECURITY.md 的加固清单;
- NAS 的存储空间放配置即可,镜像不占数据卷。
5. 升级与回退
| 操作 | 命令 |
|---|---|
| 升级到新代码 | 更新源码目录后 ./deploy.sh(自动重建+换容器);compose 用 docker compose up -d --build |
| 只改配置 | 本地改 config.json → ./deploy.sh;或挂载 volume 方式下 docker compose restart |
| 回退 | 代码回滚后重跑 ./deploy.sh;配置回退=恢复备份的 config.json 再重启 |
| 完全卸载 | docker rm -f webproxy && docker rmi webproxy:latest |
6. 网络与防火墙 checklist
- 服务器到目标内网路由可达(
curl -I http://目标IP在服务器上先验证); - 对外端口已在安全组/防火墙放行(只放需要的端口,如 9000);
- 公网暴露前已完成入口鉴权(见 SECURITY.md);
config.json的 SSRF 档位与实际上线环境匹配(off/blacklist/whitelist);- 内网目标为 HTTPS 自签证书时已设
insecure_skip_verify: true。