安全使用 Pi Coding Agent 的两种隔离方案

最近几个月我一直在用 Pi Coding Agent 写代码。它很极简,速度快,token 消耗也比其他 agent 低不少。代价是安全上基本没有护栏。

我搜过一圈,能直接拿来用的方案不多,于是自己折腾了一段时间,最后定下两条路:Docker 容器Linux 独立用户降权。下面是原理、配置,以及我实际用下来的一些经验。

一、风险点

Pi 官方文档里有一节专门讲 No Built-in Sandbox,原文大意是:

Pi 不包含内置沙箱。内置工具可以读文件、写文件、改文件、执行 shell 命令,使用的就是 pi 进程的权限。扩展是以相同权限运行的 TypeScript 模块。

官方还解释了为什么不做进程内沙箱:半成品的沙箱容易被当成真正的安全边界,但它照样要用宿主的 shell、文件系统和凭据,所以隔离得靠操作系统,或者容器/虚拟化这一层

顺带澄清一个容易搞混的地方:Pi 的 project trust(启动时问你要不要信任当前项目)不是沙箱,它只管防止仓库在你批准之前偷偷加载扩展或改配置。

真正要担心的是这几类:

  • 越权读取~/.ssh~/.aws、项目里的 .env、数据库密码,都可能在它一次 cat 之后进了模型上下文。
  • 越权写入和误删:改坏系统配置、删掉别的项目、覆盖家目录里的其他文件。模型经常把路径算错,容易删错东西。
  • 提示注入与供应链:第三方扩展、MCP server、skills 和 Pi 同权限运行;仓库里的 README、代码注释、构建输出都可以藏指令,官方也说了防不住。

指望”我只让 Agent 干安全的事”是不行的。只要它读到的内容不完全可控,就该默认它哪天会执行一条你没写过的命令。

二、方案一:Docker 容器隔离

1. 思路

让 Pi 整个跑在容器里,只把当前项目目录挂进去,再单独给它一份配置目录。宿主上的 ~/.ssh~/.aws 不挂载,容器里压根没有这些路径,也就谈不上读到或者修改。

2. 镜像与启动

镜像不复杂,装好 Node 和 Pi 就行。唯一的坑是别用 root 跑:建一个和宿主 UID 对齐的普通用户,否则写回宿主目录的文件全是 root 属主,后面收拾起来很烦。

FROM ubuntu:24.04

# Node 22 + 基础工具
RUN apt-get update && apt-get install -y --no-install-recommends \
      ca-certificates curl git ripgrep build-essential \
 && curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \
 && apt-get install -y --no-install-recommends nodejs \
 && rm -rf /var/lib/apt/lists/*

# 安装 pi
ARG PI_VERSION=0.85.1
RUN npm install -g @earendil-works/pi-coding-agent@${PI_VERSION}

# 非 root 用户,UID 与宿主对齐,避免挂载目录出现 root 属主文件
ARG HOST_UID=1000
RUN useradd -m -u ${HOST_UID} -s /bin/bash dev
USER dev
WORKDIR /home/dev/workspace
ENTRYPOINT ["pi"]

构建完之后,配置和凭据也单独放一份,不要挂宿主的 ~/.pi

docker build --build-arg HOST_UID=$(id -u) -t pi-sandbox .

# 专用的 Pi 配置/凭据目录,不要直接用宿主的 ~/.pi
mkdir -p ~/pi-data/pi

cd ~/code/my-project
docker run --rm -it \
  -v "$PWD:/home/dev/workspace" -w /home/dev/workspace \
  -v "$HOME/pi-data/pi:/home/dev/.pi" \
  pi-sandbox

--rm 表示容器退出即删。容器里临时装的东西会丢,项目代码和 ~/pi-data 是持久保存的。

3. 几个坑

  1. 别挂 docker.sock 很多人为了让容器里也能跑 docker,把 /var/run/docker.sock 挂进去。这等于把宿主的 root 权限交出去,隔离白做。
  2. 别直接挂宿主的 ~/.pi 那里有你所有的会话、设置和凭据。需要哪个凭据,就往 ~/pi-data/pi 里放哪个。当然了如果你使用docker,可以直接删除宿主机的Pi。
  3. git 同理。要让 Agent push 代码,就单独生成一把只对单个仓库有效的 deploy key,别把能开所有仓库的私钥塞进去,出事后的损失不是一个量级。
  4. 构建时记得用 .dockerignore 把数据目录排除掉。否则含密钥的文件会被打进镜像层,docker history 一翻就出来了。

4. pi-docker:完整实现

上面这个最小版本只能算跑通。真正用起来还有一堆琐事:在任意目录一条命令启动、同时开几个项目、dev server 的端口映射、容器用完自动回收……我把这些塞进了一个小工具 pi-docker,顺带把日常最常用的几条命令也封了进去。用法:

cd 任意项目目录
pi-docker        # 启动 Pi 会话(一次性容器,退出即焚)
pi-shell         # 进容器交互 shell,用于试装软件
pi-up / pi-exec  # 常驻容器,可在单独终端跑 dev server
pi-doctor        # 自检路径、凭据、镜像

容器里还跑了个看门狗:没有活跃会话、空闲超过 15 分钟,就自动停掉并删除,免得用久了容器越积越多。

pi-docker 下载地址见:pi-docker.zip

三、方案二:Ubuntu 独立用户降权

如果你的开发机就是 Linux,又不想为每个项目都开容器,还有另一种更轻的做法:不换环境,只换身份,让 Pi 以一个专用的低权限用户运行。

1. 工作原理

Linux 判断一个进程能不能读某个文件,看的是启动它的用户身份(UID)。Pi 以 pi-agent 的身份跑,而你的 ~/.ssh 属主是你自己,内核就会在它试图打开文件的时候直接拒绝。这就是全部的安全来源。

2. 三个细节

  1. 项目不能放在家目录下。Ubuntu 家目录默认 750 甚至 700,other 没有任何权限,pi-agent 连门都进不去。共享工作区得放在双方都能进的地方,比如 /srv/dev
  2. 新建文件的归属会让 git 卡住。pi-agent 建出来的文件,属主和属组都是它自己;默认的 umask 022 又让文件是组只读。结果你既不是属主、也不在它的组里,改都改不动,git 提交自然失败。解决办法是两件事一起做:给共享目录加 setgid 位,让新建文件自动继承 dev 组;再把 pi-agentumask 改成 002,让新文件组内可写,这两件缺一不可。
  3. sudo 会重置 PATH。 它默认把 PATH 换成 secure_path,可以把pi装在系统级目录,或是按我下面的单独设置PATH目录。

3. 配置脚本

这套配置我整理成了脚本,直接跑就行(把 WORKSPACE 换成你自己的共享目录):

#!/usr/bin/env bash
set -euo pipefail

AGENT_USER="pi-agent"
SHARED_GROUP="dev"
WORKSPACE="/srv/dev"

# 1. 建组、建用户(锁定密码,禁止登录)
sudo groupadd -f "$SHARED_GROUP"
if ! id "$AGENT_USER" &>/dev/null; then
  sudo useradd -m -s /bin/bash -g "$SHARED_GROUP" "$AGENT_USER"
  sudo passwd -l "$AGENT_USER"
fi
sudo usermod -aG "$SHARED_GROUP" "$USER"
sudo usermod -aG "$SHARED_GROUP" "$AGENT_USER"

# 2. 共享工作区:双方可读写,setgid 让新文件继承组
sudo mkdir -p "$WORKSPACE"
sudo chgrp -R "$SHARED_GROUP" "$WORKSPACE"
sudo chmod -R g+rwX "$WORKSPACE"
sudo chmod g+s "$WORKSPACE"

# 3. umask 002:新文件组内可写(与 setgid 缺一不可)
grep -q '^umask 002' "/home/$AGENT_USER/.bashrc" \
  || echo 'umask 002' | sudo tee -a "/home/$AGENT_USER/.bashrc"

# 4. 继承 git 身份
sudo tee "/home/$AGENT_USER/.gitconfig" >/dev/null <<EOF
[user]
  name = $(git config user.name 2>/dev/null || echo 'Your Name')
  email = $(git config user.email 2>/dev/null || echo 'you@example.com')
EOF

# 5. 专用 SSH key,去 GitHub 配成单仓库 deploy key
if [ ! -f "/home/$AGENT_USER/.ssh/id_ed25519" ]; then
  sudo -u "$AGENT_USER" ssh-keygen -t ed25519 -N '' -f "/home/$AGENT_USER/.ssh/id_ed25519"
  sudo -u "$AGENT_USER" cat "/home/$AGENT_USER/.ssh/id_ed25519.pub"
fi

4. 无感 wrapper

每次手写 sudo -u pi-agent 实在太烦,我索性写了个 pi-safe 代替 pi,它会顺手把当前目录纳入共享组,用起来和原来几乎没区别:

#!/usr/bin/env bash
set -euo pipefail

AGENT_USER="pi-agent"
AGENT_HOME="/home/pi-agent"
PI_BIN="$AGENT_HOME/.local/share/pi-node/node-v22.23.2-linux-x64/bin/pi"
SHARED_GROUP="dev"
BREW="/home/linuxbrew/.linuxbrew"

p="$(pwd)"
sudo chgrp -R "$SHARED_GROUP" "$p" 2>/dev/null || true
sudo chmod -R g+rwX "$p" 2>/dev/null || true
sudo chmod g+s "$p"

# 单独设置PATH,ENV变量,如果有其他的类似JAVA_HOME,可以自行添加
exec sudo -u "$AGENT_USER" env \
  HOME="$AGENT_HOME" \
  PATH="$AGENT_HOME/.local/share/pi-node/node-v22.23.2-linux-x64/bin:$BREW/opt/python@3.12/libexec/bin:$BREW/bin:$BREW/sbin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" \
  HOMEBREW_PREFIX="$BREW" \
  HOMEBREW_CELLAR="$BREW/Cellar" \
  HOMEBREW_REPOSITORY="$BREW/Homebrew" \
  bash -c 'umask 002; exec "$0" "$@"' "$PI_BIN" "$@"
chmod +x ~/bin/pi-safe
cd /srv/dev/my-project
pi-safe 

四、两种方案对比与选择

两种方案我都用了不短时间,下面是我自己的体感:

维度 Docker 容器 Linux 降权用户
隔离强度
文件权限摩擦 低(UID 对齐后基本无感) 中(需 setgid + umask + 共享组)
环境一致性 强(镜像锁死工具链) 弱(用宿主工具链)
资源开销 几乎为零
跨平台 macOS / Windows / Linux 仅 Linux
内核漏洞逃逸 有风险(与宿主共享内核) 不适用
本地服务 / 端口 需要端口映射 原生支持
对宿主的副作用 几乎无 Agent 装的包会留在系统里

我日常主力是 Docker 模式,隔离干净,代价是每次 Pi 升级都得重新构建镜像,或是安装软件也要重构镜像。这个成本不小,但有AI也很方便。Linux 上如果嫌麻烦,降权用户也够用,但它会随着时间,开发环境会变乱。两者你可以自行尝试选择。

五、参考资料

  1. Pi 官方安全文档(No Built-in Sandbox)
  2. Pi 官方容器化文档
  3. Pi 项目主页

文章未经特殊标明皆为本人原创,未经许可不得用于任何商业用途,转载请保持完整性并注明来源链接 《ITechLib》

Mac环境ComfyUI部署JoyCaption2实现图片反推

一、图片反推利器JoyCaption2介绍

JoyCaption2是一款很优秀的图片反推模型,可以根据图生文(或图片打标),支持多模态语义理解、智能标签优化、并支持与ComfyUI集成。下面介绍Mac环境下插件的安装和使用:

二、软件版本信息

三、安装步骤:

可参考官方文档 进行手工安装,下面内容针对Mac环境进行了适当调整:

1. 插件安装

把仓库下载克隆到 custom_nodes 子文件夹下:

cd custom_nodes
git clone https://github.com/EvilBT/ComfyUI_SLK_joy_caption_two.git

修改requirements.txt,根据mac后面遇到的问题进行修改: 将huggingface_hub改为>=,将bitsandbytes版本改为>=0.42.0,因为mac没有0.44.1的版本,具体如下:

huggingface_hub>=0.23.4
transformers>=4.44.0
numpy==1.26.4
sentencepiece==0.2.0
pillow>=10.4.0
bitsandbytes>=0.42.0
peft>=0.12.0

安装依赖

pip install -r ComfyUI_SLK_joy_caption_two\requirements.txt

2. 模型下载

  • google/siglip-so400m-patch14-384:视觉编码器,使用huggingface-cli来整体下载,并把siglip-so400m-patch14-384内的全部文件复制到models/clip/siglip-so400m-patch14-384
  • unsloth/Meta-Llama-3.1-8B-Instruct语言大模型,务必下载此 8B 版本,bnb-4bit 版本因 bitsandbytes 版本问题在 Mac 上不被支持。下载完成后,将整个文件夹内容复制到models\LLM\Meta-Llama-3.1-8B-Instruct路径下。
  • Joy-Caption-alpha-two核心推理模型(版本2024-09-26a),必须手动下载:鉴于该工程在 huggingface 上属于 space,下载指令如下huggingface-cli download --token 替换为你的token spaces/fancyfeast/joy-caption-alpha-two --local-dir joy-caption-alpha-two;然后将 Joy-Caption-alpha-two 下的cgrkzexw-599808 文件夹的所有内容下载复制到models/Joy_caption_two 下。

3.重启ComfyUI生效

四、示例工作流

工作流支持图生文,批量处理,个性化扩展配置。

下载地址如下:JoyCaption2-comfyUI-example.json

五、常见问题解决:

  1. ImportError: Using bitsandbytes 4-bit quantization requires the latest version of bitsandbytes: pip install -U bitsandbytes:此问题是由于 Mac 系统中的 bitsandbytes 版本过低,且当前无更高版本可供使用。解决方案为采用unsloth/Meta-Llama-3.1-8B-Instruct的 8B 版本,避免使用 bnb-4bit 版本。
  2. 报错huggingface_hub版本太低:因其他工具依赖更高版本,可通过修改 requirements 文件,将 huggingface_hub 改为 “>=” 形式。

参考资料:

文章未经特殊标明皆为本人原创,未经许可不得用于任何商业用途,转载请保持完整性并注明来源链接 《ITechLib》

博客迁移历程

之前我的博客托管在外网的Linode上,Linode整体还是挺好的,支持一键迁移,服务器也很稳定,网站上教程资源很丰富;缺点就是国内访问的网速总是不理想,延迟很大,其间我尝试了 Linode 不同地区的机房,问题都没有解决,网速不稳定,经常会很慢。

近期,我下定决心迁移博客,彻底解决这个问题,后续也准备将博客继续维护起来;经过广泛调研,并综合考量性价比等多方面因素,决定将博客迁移到阿里云。接下来,我将详细分享博客迁移的全过程,其中我也踩了不少坑,希望能给大家提供一些参考。

博客运行环境

博客的运行环境主要涉及以下技术栈:

  • 操作系统:Ubuntu 16.04
  • 编程语言及框架:Ruby 2.3.8、Rails 4.2.4
  • 数据库:MySQL 5.7
  • 搜索服务:Solr 5.5.4
  • Web 服务器及应用服务器:Nginx + Passenger

此外,Rails依赖的需要本地编译的包如下:

  • nokogiri 1.6.6.2
  • mysql2 0.3.20

部署工具方面

  • ansible 2.0.0.2
  • bundler 1.17.2
  • capistrano 3.6.1

迁移目标及方案

如果是将上述系统直接部署到Ubuntu16.04上会很简单,因为我前期已经整理了功能完善的ansible部署工具,可以实现一键部署,完成所有的依赖安装和环境配置。但考虑到Ubuntu16.04已停止维护,为了让这次迁移更加彻底,我决定将操作系统升级到最新的Ubuntu24.04。

不得不说,我前期严重低估了迁移的难度,从过年到现在,竟然花了将近两周时间(原本预计只需两天)。

方案一、 折腾本地虚拟机,重新启用ansible部署工具(失败)

  • 安装Mac版Ubuntu  24.04 虚拟机:需要装arm版的【解决】。难点:arm版本导致很多依赖包无法使用或默认缺失,需要单独下载和编译。
  • 使用最新版ansible软件(2.18.2):仅因为不想安装太久的版本【艰难解决】。难点:和老版本不兼容,部分需要修改代码解决。
  • ~~原计划安装最新版的Ruby 4.1 ,之后因为很多依赖包不兼容,放弃。~~
  • 安装Ruby-2.3.8版本【解决】。难点:缺少libssl1.0-dev,需要源码编译安装,然后才能编译安装Ruby,建议使用rvm来安装。
  • 安装bundler包:使用1.17.2版本。
  • 安装依赖gem包 - nokogiri【艰难成功】。nokogiri编译安装依赖部分本地包,需要通过源码编译安装iconv、 libxml2-2.9.2、libxslt-1.1.28等。
  • 安装依赖gem包 - mysql2:其编译依赖mysql5.7的dev包
  • 安装Mysql 8.0 ,与mysql2 0.3.20包冲突,但这个是底层包无法更新。【冲突】
  • 安装mysql 5.7 成功,但安装依赖的dev包,和其他dev包冲突。【冲突】

在解决了无数问题后,发现这条路走下去,即使编译通过并安装成功,运行过程中也难免出现各种问题,于是决定放弃方案一。

方案二、使用docker镜像安装

为了避免上面遇到的各种编译及依赖问题,我决定将博客主体继续运行在Ubuntu16.04上,但又不想放弃升级到Ubuntu24.04的想法。经过综合考虑,决定采用Docker来部署,这样外部的主机使用Ubuntu24.04,后续有时间再对博客做全面升级,以支持最新的操作系统。具体步骤如下:

  1. 本地安装Ubuntu镜像
    • 开发环境:采用 arm 架构安装 Ubuntu 16.04 镜像,用于博客工程的开发测试和更新,目前使用过程中未发现问题。
    • 准生产环境:为了与生产服务器架构保持一致,采用amd64架构安装Ubuntu镜像。
    • 模拟生产宿主环境:本地安装Ubuntu24.04镜像,用于模拟生产环境的宿主服务器。
  2. 初始化镜像环境:安装必要的包、创建用户、配置ssh服务器。
  3. 安装应用程序:在镜像中安装Rails、solr等应用程序,可以使用之前做的ansible工具直接安装。
  4. 保存镜像:将安装好的容器保存为镜像,使用commit命令。
    • 镜像可以认为是稳定的、可复用、持久化的系统。
    • 容器可以认为是可以丢弃的、不稳定的存在,可以很方便用来试错。
    • commit前尽量删除无用的文件、安装程序等,减小镜像的体积。
  5. Docker向宿主机器暴露端口,进行端口映射:
    • 开发环境:为方便开发,开放了多个端口(前面为宿主机端口、后面为镜像中开放的端口):
      • 10022:22 :SSH服务,便于上传和编辑文件。可通过SSH支持VSCode远程开发代码,但无法使用 AI 是个小缺点,后续可考虑通过 SSH 同步工具实现代码同步。
      • 10080:80 :HTTP服务
      • 13000:3000:Rails server端口,便于在宿主机进行调试
      • 13306:3306:MySQL数据库端口,便于通过Mac的图形化界面进行管理
      • 18983:8983:Solr搜索端口,便于在宿主机调试
      • 8086:8086 和 8087:8087 :作为备用端口,避免每次开放新端口都需要 commit 镜像的麻烦。
    • 生产环境:出于安全性考虑,仅开放最少的端口:
      • 33000:3000:Passenger服务器的默认端口
      • 30022:22 :SSH服务器的端口,为保障安全,关闭了密码登录,仅允许证书登录,并安装了 Fail2ban 软件。
  6. 数据库配置:出于性能考虑,使用宿主机的MySQL服务器。避免在Docker容器中直接运行MySQL。
    • 为了安全,通过设置ufw防火墙,仅允许容器固定IP远程访问MySQL。
  7. 防火墙配置:配置docker-ufw,防止外网访问docker暴露的端口。安装完正常无需特殊配置。
  8. 镜像迁移:将生产镜像导出,上传到生产环境,再导入到生产服务器。

至此,博客主体部署已完成,下面简单列举一下生产服务器的其他配置内容,供大家参考:

  1. SSH登录配置
    • 禁止以root身份登录
    • 取消使用密码登录,改用SSH证书登录
  2. 设置虚拟内存,参考:Ubuntu实例中添加swap分区的方法
  3. 设置ufw防火墙
  4. 安装Fail2ban软件
  5. Web 服务器配置:配置nginx,安装https证书。

参考教程

  1. Ubuntu使用certbot配置nginx服务器的ssl证书
  2. Deploying a Ruby app on a Linux/Unix production server
  3. Installing Older Ruby Versions on Ubuntu 24.04 and 22.04
  4. How to install MySQL 5.7 on ubuntu 20.04 or later
  5. Ubuntu实例中添加swap分区的方法
  6. UFW-Docker 使用教程

文章未经特殊标明皆为本人原创,未经许可不得用于任何商业用途,转载请保持完整性并注明来源链接 《ITechLib》

网络正向代理与反向代理

网络代理是一种存在与网络的中间人,代理是存在与客户端和服务器之间的角色,从用途上看可以分为正向代理和反向代理。一直以来对这两个名词理解不是特别深刻,经过前段时间的项目,对这两种代理有了更深的认识,用一句话来归纳两者的区别就是“两者服务的对象不同”。

正向代理是代理客户端的,是为客户端服务的,可以想到的用途有局域网内访问外网、翻墙、局域网加速、网络访问控制、隐私保护等等。正向代理试图以客户的身份来访问服务端,正向代理更倾向于解决客户或是客户的管理者的问题,例如公司对员工上网的限制,公司节省流量的考虑,个人要访问国外资源的需要等等。典型的正向代理软件有:Squid、Tinyproxy等等。最常用的就属Squid了,Squid的一些相关好的资料请参考本文最后的参考资料。值得一提的是Squid是可以代理http和https协议的,其中代理https协议并不存在大家认为的安全性问题(https协议本身就是防中间人攻击的),具体代理原理可以参考HTTP 代理原理及实现(一)

反向代理则是代理服务端的,是为服务端服务的,可以想到的用途有负载均衡、SSL加密、缓存静态资源、压缩等。常见的反向代理软件有Nginx、Haproxy、Apache等等,如果只谈负载均衡还有一些工作在网络层的软件如LVS或是硬件F5等。反向代理服务器可以对客户端发来的请求进行负载均衡转发(支持多种负载均衡策略),更改请求的HOST头,对客户请求进行过滤(如设置黑名单等)等。我们项目中使用的Nginx,主要用来进行负载均衡、请求转发。

近期我自己也写了个简单的反向代理,它可以对于特定的URL请求进行过滤,并对服务器返回的内容进行修改,替换成你需要的内容。这个在我们的测试中解决了外网访问的问题,因为外网使用的域名和内网测试不同,为了屏蔽差异,我通过这个反向代理对个别URL的内容进行了修改,修改成外网可使用的内容。具体代码见hrcproxy.go,代码采用go语言编写,目前实现了简单的字符串替换,后续考虑再增加表达式相关的替换。

参考资料:

  1. 正向代理与反向代理的区别
  2. Squid中文权威指南
  3. 区网控制者: Proxy 服务器 - Squid
  4. 构建Squid代理服务器
  5. HTTP 代理原理及实现(一)
  6. Nginx通过二级目录(路径)映射不同的反向代理,规避IP+端口访问
  7. Reverse Proxy In Go
  8. How DNS lookups work when using an HTTP proxy (or not) in IE
  9. 三种解密 HTTPS 流量的方法介绍
  10. ZeroSSL,支持多域名的在线 Let’s Encrypt SSL 证书申请工具

文章未经特殊标明皆为本人原创,未经许可不得用于任何商业用途,转载请保持完整性并注明来源链接 《ITechLib》

搭建通往私有内网web服务器的路

项目开发分为生产环境和测试环境,有很多时候测试环境也需要和外部系统互通,目前主要是采用互联网的形式。我们的测试环境更特殊一些,他不仅仅是在内网,而且是在内部私有云上,外部只能通过VPN访问。而且这个VPN有很多限制,例如:

  • 只能使用cisco anyconnect客户端,这个客户端只能安装在windows机器上,不支持Linux;
  • 只要启动了VPN客户端,这个windows机器就只能访问云上的测试环境,不能访问互联网了;
  • VPN登录需要用户名和密码,如果其他单位客户要使用,我们需要给他们提供用户名密码,有安全问题;
  • VPN安装过程复杂,需要安装证书等,有些机器无法安装成功。

我们开发的应用是要对外发布互联网接口的,客户需要调我们的接口来完成他们需要的功能。在生产环境下没什么问题,因为生产环境有自己的域名也支持互联网访问。但在测试环境就有问题了,客户如何调用我们在云上的服务就是一个难题。在经过引导客户装VPN遇到各种问题,被客户各种吐槽后,我们开始想解决之道。一个方案是打通一条不使用VPN的路,可以让互联网直接访问,这需要协调多个部门,开通各种网络访问关系,很复杂。另一个方案就是现在要讲的方案,通过虚拟机支持多网卡的特点,我们可以实现在一台物理机同时访问互联网和vpn,结合NAT穿越可以实现通过互联网直接访问内网服务器。大体的网络配置图如下:

网络配置示意图

这里有几个要点:

  1. 虚拟机要有两个网卡,其中网卡1可以访问互联网(可以是桥接或NAT模式),这个网卡是用来给VPN客户端使用的;另一个网卡2要配置成host only,实现和物理主机的双向访问;
  2. 在虚拟机中要安装nginx,监听80端口,并将请求转发到内网服务器的nginx服务器上,转发http请求;
  3. 在物理机中安装nginx,监听80或443端口,将收到的http/https请求转发到虚拟机的nginx服务器的80端口;
  4. 在物理机中安装frpc客户端,联通与互联网服务器的frps服务器的交互,并将请求转发给本机nginx服务器;
  5. 在互联网上的服务器中安装frps服务器,将收到的请求转发给frpc客户端;
  6. 购买一个公网的域名,指向这个互联网服务器,一个域名很便宜,一年8元就可以了。

物理机的nginx和frpc配置见这里,大家可以参考使用。

参考资料

  1. 使用内网穿透工具frp
  2. ZeroSSL,支持多域名的在线 Let’s Encrypt SSL 证书申请工具
  3. frp github
  4. Nginx通过二级目录(路径)映射不同的反向代理,规避IP+端口访问

文章未经特殊标明皆为本人原创,未经许可不得用于任何商业用途,转载请保持完整性并注明来源链接 《ITechLib》