FRP + Shadowsocks 内网穿透实战:远程安全访问内网服务
之前写过一篇 SSH 隧道与内网穿透实战,用的是最基础的 SSH 端口转发。那篇适合临时用,但如果需要长期稳定、多端口映射、流量加密,FRP 配 Shadowsocks 是更专业的方案。
这篇文章聊聊怎么搭一套完整的内网穿透+代理系统,让你在外网像在内网一样自由。
两种方案对比
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| SSH 端口转发 | 零部署、自带加密 | 只能单端口、断线重连麻烦 | 临时调试 |
| FRP + Shadowsocks | 多端口、稳定、可代理 | 需要公网服务器、配置稍复杂 | 长期远程办公 |
简单说,SSH 适合应急,FRP 适合过日子。
环境准备
你需要:
- 一台有公网 IP 的服务器(云服务器,1核1G 足够)
- 一台内网机器(家里或公司,要暴露的服务跑在上面)
- 外网设备(手机、笔记本,需要远程访问)
本文示例:
- 公网服务器
vps.yolonote.cc(CentOS 8) - 内网机器
homelab.local(Ubuntu 22.04,IP 192.168.1.100) - 要暴露的服务:内网 Web 服务、SSH、Samba 共享
第一步:部署 FRP
FRP(Fast Reverse Proxy)是个开源的内网穿透工具,GitHub 上搜 fatedier/frp 就行。架构分两部分:
- frps:服务端,跑在公网服务器上
- frpc:客户端,跑在内网机器上
服务端配置(frps.toml)
创建 /etc/frp/frps.toml:
bindPort = 7000
auth.method = "token"
auth.token = "your-strong-token-here"# Web 面板(可选)
webServer.addr = "0.0.0.0"
webServer.port = 7500
webServer.user = "admin"
webServer.password = "admin-password"
# 指定允许使用的端口范围
allowPorts = [
{ start = 6000, end = 7000 }
]
启动服务:
systemctl enable frps
systemctl start frps防火墙放行 7000(FRP 通信)和 7500(面板)端口。
客户端配置(frpc.toml)
内网机器创建 /etc/frp/frpc.toml:
serverAddr = "vps.yolonote.cc"
serverPort = 7000
auth.method = "token"
auth.token = "your-strong-token-here"[[proxies]]
name = "web"
type = "tcp"
localPort = 80
remotePort = 6080[[proxies]]
name = "ssh"
type = "tcp"
localPort = 22
remotePort = 6022
[[proxies]]
name = "samba"
type = "tcp"
localPort = 445
remotePort = 6045
启动:
systemctl enable frpc
systemctl start frpc现在你可以在外网通过 vps.yolonote.cc:6080 访问内网 Web,vps.yolonote.cc:6022 SSH 连回家。
第二步:Shadowsocks 加密代理
FRP 本身只做了端口映射,流量还是明文传输。如果你映射的是 HTTP 或 SMB,数据在公网上裸奔,不太安全。加上 Shadowsocks 做一层加密隧道。
服务端(ss-server)
公网服务器安装 shadowsocks-libev:
# CentOS
dnf install shadowsocks-libev配置 /etc/shadowsocks-libev/config.json:
{
"server":"0.0.0.0",
"server_port":8388,
"password":"another-strong-password",
"timeout":300,
"method":"aes-256-gcm",
"fast_open":true
}启动:
systemctl enable shadowsocks-libev
systemctl start shadowsocks-libev防火墙放行 8388。
客户端(ss-local)
内网机器同样安装 shadowsocks-libev,配置 /etc/shadowsocks-libev/config.json:
{
"server":"vps.yolonote.cc",
"server_port":8388,
"local_port":1080,
"password":"another-strong-password",
"timeout":300,
"method":"aes-256-gcm"
}local_port 是本地 SOCKS5 代理端口。启动后,内网机器上任何走 127.0.0.1:1080 的流量都会加密后发到公网服务器。
第三步:让 FRP 走 Shadowsocks 代理
现在 FRP 和 Shadowsocks 各自独立运行。关键是把 FRP 的流量也塞进 Shadowsocks 隧道里。
方案 A:frpc 直接走 SOCKS5
frpc 支持通过 SOCKS5 代理连接 frps。修改 frpc.toml:
serverAddr = "vps.yolonote.cc"
serverPort = 7000
auth.method = "token"
auth.token = "your-strong-token-here"# 走本地 Shadowsocks 代理
transport.proxyURL = "socks5://127.0.0.1:1080"
[[proxies]]
name = "web-secure"
type = "tcp"
localPort = 80
remotePort = 6080
这样 frpc → ss-local(加密)→ ss-server → frps,整个 FRP 控制通道都是加密的。
方案 B:只加密特定映射流量
如果你只想加密某些敏感服务,可以不改 FRP 控制通道,而是让特定代理走 Shadowsocks。比如给 Web 映射加一层 stunnel,或者直接用 proxychains 启动需要保护的程序。
更简单的做法:在内网机器上装一个 Nginx,把 HTTP 强制转 HTTPS(自签名证书也行),然后 FRP 映射 443 端口。这样数据至少不是明文。
第四步:外网访问配置
你在外网手机/笔记本上,需要:
- SSH 回家:直接
ssh -p 6022 [email protected] - 访问内网 Web:浏览器打开
http://vps.yolonote.cc:6080 - 全局代理:手机装 Shadowsocks 客户端,配置服务器
vps.yolonote.cc:8388,这样就能像在内网一样访问所有映射端口
进阶:域名+HTTPS
给 FRP 的 Web 映射绑个域名,比如 home.yolonote.cc,用 Nginx 反代加 Let's Encrypt 证书:
server {
listen 443 ssl;
server_name home.yolonote.cc;ssl_certificate /etc/letsencrypt/live/home.yolonote.cc/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/home.yolonote.cc/privkey.pem;
location / {
proxy_pass http://127.0.0.1:6080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
这样外网访问 https://home.yolonote.cc,数据全程加密,看起来也专业。
安全加固建议
- Token 和 Password 分开:FRP 和 Shadowsocks 不要用同一个密码
- 限制 IP:frps.toml 里加
auth.additionalScopes = [{ allowSourceIP = ["你的外网IP"] }](如果有固定 IP) - 防火墙:只开放必要端口,FRP 面板 7500 限制 IP 访问
- 定期更新:FRP 和 shadowsocks-libev 保持最新版
- 日志监控:FRP 面板可以看到连接状态,异常流量及时发现
总结
这套组合的思路是:
- FRP 负责打洞,把内网端口映射到公网
- Shadowsocks 负责加密,让映射流量不在公网裸奔
- 两者结合,既方便又安全
相比纯 SSH 转发,FRP 可以一次映射多个端口,支持 UDP,有 Web 面板看状态;加上 Shadowsocks 后,整个链路有了加密层,不像 SSH 端口转发那样容易被中间人窥探。
如果你只是临时用,SSH 够了。但如果长期远程办公、要访问内网多台设备,这套方案值得折腾一下。