Docker 部署frp内网穿透
- 简介
frp([项目主页](https://github.com/fatedier/frp)frp 是一个专注于内网穿透的高性能的反向代理应用,支持 TCP、UDP、HTTP、HTTPS 等多种协议,且支持 P2P 通信。可以将内网服务以安全、便捷的方式通过具有公网 IP 节点的中转暴露到公网。。架构如下:
简单来说,就是可以随时随地通过有公网 IP 的服务器中转连接到运行 frpc 程序的任意机器的任意端口。
为什么使用 frp ?
通过在具有公网 IP 的节点上部署 frp 服务端,可以轻松地将内网服务穿透到公网,同时提供诸多专业的功能特性,这包括:
- 客户端服务端通信支持 TCP、QUIC、KCP 以及 Websocket 等多种协议。
- 采用 TCP 连接流式复用,在单个连接间承载更多请求,节省连接建立时间,降低请求延迟。
- 代理组间的负载均衡。
- 端口复用,多个服务通过同一个服务端端口暴露。
- 支持 P2P 通信,流量不经过服务器中转,充分利用带宽资源。
- 多个原生支持的客户端插件(静态文件查看,HTTPS/HTTP 协议转换,HTTP、SOCK5 代理等),便于独立使用 frp 客户端完成某些工作。
- 高度扩展性的服务端插件系统,易于结合自身需求进行功能扩展。
- 服务端和客户端 UI 页面。
开发状态
frp 目前已被很多公司广泛用于测试、生产环境。
master 分支用于发布稳定版本,dev 分支用于开发,您可以尝试下载最新的 release 版本进行测试。
我们正在进行 v2 大版本的开发,将会尝试在各个方面进行重构和升级,且不会与 v1 版本进行兼容,预计会持续较长的一段时间。
现在的 v0 版本将会在合适的时间切换为 v1 版本并且保证兼容性,后续只做 bug 修复和优化,不再进行大的功能性更新。
官方文档
第1集 frp怎么使用
使用场景
做具体的配置前,根据对应的操作系统及架构,从 Release 页面下载最新版本的程序。
将 frps 及 frps.toml 放到具有公网 IP 的机器上。请注意配置防火墙或安全组放过配置文件中使用的端口。
将 frpc 及 frpc.toml 放到处于内网环境的机器上。
通过自定义域名访问内网的 Web 服务
- 配置 frps.toml
bindPort = 7000
vhostHTTPPort = 8080
- 配置 frpc.toml
serverAddr = "x.x.x.x"
serverPort = 7000
[[proxies]]
name = "web"
type = "http"
localPort = 80
customDomains = ["www.yourdomain.com"]
[[proxies]]
name = "web2"
type = "http"
localPort = 8080
customDomains = ["www.yourdomain2.com"]
-
启动 frps 和 frpc
-
域名解析
将 www.yourdomain.com
和 www.yourdomain2.com
的域名 A 记录解析到服务器的 IP 地址 x.x.x.x
。如果服务器已经有对应的域名,您还可以将 CNAME 记录解析到原始域名。另外,通过修改 HTTP 请求的 Host 字段也可以实现相同的效果。
- 通过浏览器访问
使用浏览器访问 http://www.yourdomain.com:8080
即可访问内网机器上的 80 端口服务,访问 http://www.yourdomain2.com:8080
可以访问内网机器上的 8080 端口服务。
为本地 HTTP 服务启用 HTTPS
-
配置 frps.toml
bindPort = 7000 vhostHTTPSPort = 443
-
配置 frpc.toml
serverAddr = "x.x.x.x" serverPort = 7000 [[proxies]] name = "test_htts2http" type = "https" customDomains = ["test.yourdomain.com"] [proxies.plugin] type = "https2http" localAddr = "127.0.0.1:80" # HTTPS 证书相关的配置 crtPath = "./server.crt" keyPath = "./server.key" hostHeaderRewrite = "127.0.0.1" requestHeaders.set.x-from-where = "frp"
请注意,您需要根据您的域名和证书路径自行更改上述配置。
-
启动 frps 和 frpc
-
访问 HTTPS 服务
- 打开您的 Web 浏览器,访问
https://test.yourdomain.com
。
通过按照以上步骤进行配置,您将能够为本地 HTTP 服务启用 HTTPS,以实现安全的外部访问。
- 打开您的 Web 浏览器,访问
通过 SSH 访问内网机器
通过简单配置 TCP 类型的代理,使用户能够访问内网服务器。
- 在具有公网 IP 的机器上部署 frps
部署 frps 并编辑 frps.toml 文件。以下是简化的配置,其中设置了 frp 服务器用于接收客户端连接的端口:
bindPort = 7000
- 在需要被访问的内网机器上部署 frpc
部署 frpc 并编辑 frpc.toml 文件,假设 frps 所在服务器的公网 IP 地址为 x.x.x.x。以下是示例配置:
serverAddr = "x.x.x.x"
serverPort = 7000
[[proxies]]
name = "ssh"
type = "tcp"
localIP = "127.0.0.1"
localPort = 22
remotePort = 6000
localIP
和localPort
配置为需要从公网访问的内网服务的地址和端口。localIP
和localPort
配置为需要从公网访问的内网服务的地址和端口。
-
启动 frps 和 frpc
-
通过 SSH 访问内网机器
使用以下命令通过 SSH 访问内网机器,假设用户名为 test:
ssh -o Port=6000 test@x.x.x.x
frp 将请求发送到 x.x.x.x:6000
的流量转发到内网机器的 22 端口。
多个 SSH 服务复用同一端口
通过使用 tcpmux 类型的代理,您可以实现多个 SSH 服务通过同一端口进行暴露。这种方法还适用于任何支持 HTTP Connect 代理连接方式的客户端,以实现端口的复用。
-
在具有公网 IP 的机器上部署 frps
修改 frps.toml 文件以包含以下内容(这里使用了最简化的配置):
bindPort = 7000 tcpmuxHTTPConnectPort = 5002
-
在内网机器 A 上部署 frpc
创建 frpc 配置文件,例如 frpc.ini,然后将以下内容添加到配置文件中:
serverAddr = "x.x.x.x" serverPort = 7000 [[proxies]] name = "ssh1" type = "tcpmux" multiplexer = "httpconnect" customDomains = ["machine-a.example.com"] localIP = "127.0.0.1" localPort = 22
-
在内网机器 B 上部署另一个 frpc
创建 frpc 配置文件,例如 frpc.toml,然后将以下内容添加到配置文件中:
serverAddr = "x.x.x.x" serverPort = 7000 [[proxies]] name = "ssh2" type = "tcpmux" multiplexer = "httpconnect" customDomains = ["machine-b.example.com"] localIP = "127.0.0.1" localPort = 22
-
通过 SSH ProxyCommand 访问内网机器 A
使用 SSH ProxyCommand 访问内网机器 A,假设用户名为 test。使用以下命令:
ssh -o 'proxycommand socat - PROXY:x.x.x.x:machine-a.example.com:22,proxyport=5002' test@machine-a
要访问内网机器 B,只需更改域名,假设用户名仍然为 test:
ssh -o 'proxycommand socat - PROXY:x.x.x.x:machine-b.example.com:22,proxyport=5002' test@machine-b
通过按照以上步骤进行配置,您可以实现多个 SSH 服务复用同一端口,以便在具有公网 IP 的机器上进行访问。
安全地暴露内网服务
通过创建一个只有授权用户能够访问的 SSH 服务代理,实现内网服务的安全暴露。某些内网服务,如果直接暴露在公网上,可能存在安全风险。使用 stcp(secret tcp)
类型的代理可以让您安全地将内网服务暴露给经过授权的用户,这需要访问者也部署 frpc 客户端。
-
配置 frps.toml
在 frps.toml 文件中添加以下内容:
bindPort = 7000
-
部署 frpc 客户端并配置
在需要将内网服务暴露到公网的机器上部署 frpc,并创建如下配置:
serverAddr = "x.x.x.x" serverPort = 7000 [[proxies]] name = "secret_ssh" type = "stcp" # 只有与此处设置的 secretKey 一致的用户才能访问此服务 secretKey = "abcdefg" localIP = "127.0.0.1" localPort = 22
-
在访问者机器上部署并配置 frpc
在想要访问内网服务的机器上也部署 frpc,并创建如下配置:
serverAddr = "x.x.x.x" serverPort = 7000 [[visitors]] name = "secret_ssh_visitor" type = "stcp" # 要访问的 stcp 代理的名字 serverName = "secret_ssh" secretKey = "abcdefg" # 绑定本地端口以访问 SSH 服务 bindAddr = "127.0.0.1" bindPort = 6000
-
通过 SSH 访问内网机器
使用以下命令通过 SSH 访问内网机器,假设用户名为 test:
ssh -o Port=6000 test@127.0.0.1
转发 DNS 查询请求
本示例演示如何通过简单配置 UDP 类型的代理来实现 DNS 查询请求的转发。DNS 查询请求通常使用 UDP 协议,而 frp 支持对内网 UDP 服务的穿透,配置方式与 TCP 类似。
-
配置 frps.toml
在 frps.toml 文件中添加以下内容:
bindPort = 7000
-
配置 frpc.toml
在 frpc.toml 文件中添加以下内容:
serverAddr = "x.x.x.x" serverPort = 7000 [[proxies]] name = "dns" type = "udp" localIP = "8.8.8.8" localPort = 53 remotePort = 6000
请注意,这里示例中反代了 Google 的 DNS 查询服务器的地址,仅用于测试 UDP 代理,并没有实际意义。
-
启动 frps 和 frpc
-
测试 DNS 查询请求
使用以下命令通过
dig
工具测试 UDP 包转发是否成功,预期会返回www.baidu.com
域名的解析结果:dig @x.x.x.x -p 6000 www.baidu.com
转发 Unix 域套接字
通过配置 Unix 域套接字客户端插件,您可以使用 TCP 端口访问内网的 Unix 域套接字服务,例如 Docker Daemon。
-
配置 frps.toml
在 frps.toml 文件中添加以下内容:
bindPort = 7000
-
配置 frpc.toml
在 frpc.toml 文件中添加以下内容,确保设置正确的 Unix 域套接字路径:
serverAddr = "x.x.x.x" serverPort = 7000 [[proxies]] name = "unix_domain_socket" type = "tcp" remotePort = 6000 [proxies.plugin] type = "unix_domain_socket" # Unix 域套接字路径 unixPath = "/var/run/docker.sock"
-
启动 frps 和 frpc
-
使用 curl 查看 Docker 版本信息
curl http://x.x.x.x:6000/version
对外提供简单的文件访问服务
通过配置 static_file
客户端插件,您可以将本地文件暴露在公网上,以供其他人访问。通过使用 static_file
插件,您可以轻松地提供一个基于 HTTP 的文件访问服务,让其他人可以访问您指定的文件。
-
配置 frps.toml
在 frps.toml 文件中添加以下内容:
bindPort = 7000
-
配置 frpc.toml
在 frpc.toml 文件中添加以下内容,确保设置合适的文件路径、用户名和密码:
serverAddr = "x.x.x.x" serverPort = 7000 [[proxies]] name = "test_static_file" type = "tcp" remotePort = 6000 [proxies.plugin] type = "static_file" # 本地文件目录,对外提供访问 localPath = "/tmp/file" # URL 中的前缀,将被去除,保留的内容即为要访问的文件路径 stripPrefix = "static" httpUser = "abc" httpPassword = "abc"
请根据实际情况修改
localPath
、stripPrefix
、httpUser
和httpPassword
。 -
启动 frps 和 frpc
-
通过浏览器访问文件
使用浏览器访问
http://x.x.x.x:6000/static/
,以查看位于/tmp/file
目录下的文件。系统会要求输入您设置的用户名和密码。
点对点内网穿透
这个示例将演示如何通过点对点 (P2P) 连接来访问内网服务,流量不会通过服务器中转。frp 提供了一种新的代理类型 xtcp
,用于在需要传输大量数据且不希望流量经过服务器的情况下实现内网穿透。与 stcp
类似,使用 xtcp
需要在两端都部署 frpc 以建立直接连接。需要注意的是,xtcp
并不适用于所有类型的 NAT 设备,如果穿透失败,可以尝试使用 stcp
代理。
-
配置需要暴露到外网的机器上的 frpc.toml 文件
在 frpc.toml 文件中添加以下内容,确保设置了正确的服务器地址和端口以及共享密钥 (
secretKey
),以及本地服务的 IP 地址和端口:serverAddr = "x.x.x.x" serverPort = 7000 # 如果默认的 STUN 服务器不可用,可以配置一个新的 STUN 服务器 # natHoleStunServer = "xxx" [[proxies]] name = "p2p_ssh" type = "xtcp" # 只有共享密钥 (secretKey) 与服务器端一致的用户才能访问该服务 secretKey = "abcdefg" localIP = "127.0.0.1" localPort = 22
-
在想要访问内网服务的机器上部署 frpc
在 frpc.toml 文件中添加以下内容,确保设置了正确的服务器地址和端口,共享密钥 (
secretKey
) 以及要访问的 P2P 代理的名称:serverAddr = "x.x.x.x" serverPort = 7000 # 如果默认的 STUN 服务器不可用,可以配置一个新的 STUN 服务器 # natHoleStunServer = "xxx" [[visitors]] name = "p2p_ssh_visitor" type = "xtcp" # 要访问的 P2P 代理的名称 serverName = "p2p_ssh" secretKey = "abcdefg" # 绑定本地端口以访问 SSH 服务 bindAddr = "127.0.0.1" bindPort = 6000 # 如果需要自动保持隧道打开,将其设置为 true # keepTunnelOpen = false
-
通过 SSH 访问内网机器
使用 SSH 命令访问内网机器,假设用户名为
test
:ssh -oPort=6000 test@127.0.0.1
第2集 容器化部署frp
构建frps 服务端
-
dockerfile
FROM alpine:3.8 LABEL maintainer="chengran@gamil.com" ENV VERSION 0.52.3 ENV TZ=Asia/Shanghai WORKDIR / RUN apk add --no-cache tzdata \ && ln -snf /usr/share/zoneinfo/${TZ} /etc/localtime \ && echo ${TZ} > /etc/timezone RUN if [ "$(uname -m)" = "x86_64" ]; then export PLATFORM=amd64 ; \ elif [ "$(uname -m)" = "aarch64" ]; then export PLATFORM=arm64 ; \ elif [ "$(uname -m)" = "armv7" ]; then export PLATFORM=arm ; \ elif [ "$(uname -m)" = "armv7l" ]; then export PLATFORM=arm ; \ elif [ "$(uname -m)" = "armhf" ]; then export PLATFORM=arm ; fi \ && wget --no-check-certificate https://github.com/fatedier/frp/releases/download/v${VERSION}/frp_${VERSION}_linux_${PLATFORM}.tar.gz \ && tar xzf frp_${VERSION}_linux_${PLATFORM}.tar.gz \ && cd frp_${VERSION}_linux_${PLATFORM} \ && mkdir /frp \ && mv frps frps.toml /frp \ && cd .. \ && rm -rf *.tar.gz frp_${VERSION}_linux_${PLATFORM} VOLUME /frp CMD /frp/frps -c /frp/frps.toml
-
标记推送镜像
docker tag frp-server:v0.52.3 registry.cn-shenzhen.aliyuncs.com/code-frp/frps:v0.52.3 docker push registry.cn-shenzhen.aliyuncs.com/code-frp/frps:v0.52.3
-
启动
docker run -d --name=frps-server --restart=always \ --network host \ -v /opt/frps/frps.toml:/frp/frps.toml \ registry.cn-shenzhen.aliyuncs.com/code-frp/frps:v0.52.3
-
frps.toml基本配置
#服务端监听地址,用于接收 frpc 的连接,默认监听 0.0.0.0 bindAddr = "0.0.0.0" #服务端监听端口,默认值为 7000 bindPort = 7000 #客户端连接认证token auth.token = "xxxxx" #HTTP 类型代理监听的端口,启用后才能支持 HTTP 类型的代理 vhostHTTPPort = 880 #HTTPS 类型代理监听的端口,启用后才能支持 HTTPS 类型的代理 vhostHTTPSPort = 8443 #管理界面配置 webServer.addr = "0.0.0.0" webServer.port = 7500 webServer.user = "admin" webServer.password = "xxxxx" #启用服务端限速 transport.bandwidthLimitMode = "server"
构建frpc客户端
-
dockerfile
FROM alpine:3.8 LABEL maintainer="chengran@gamil.com" ENV VERSION 0.52.3 ENV TZ=Asia/Shanghai WORKDIR / RUN apk add --no-cache tzdata \ && ln -snf /usr/share/zoneinfo/${TZ} /etc/localtime \ && echo ${TZ} > /etc/timezone RUN if [ "$(uname -m)" = "x86_64" ]; then export PLATFORM=amd64 ; \ elif [ "$(uname -m)" = "aarch64" ]; then export PLATFORM=arm64 ; \ elif [ "$(uname -m)" = "armv7" ]; then export PLATFORM=arm ; \ elif [ "$(uname -m)" = "armv7l" ]; then export PLATFORM=arm ; \ elif [ "$(uname -m)" = "armhf" ]; then export PLATFORM=arm ; fi \ && wget --no-check-certificate https://github.com/fatedier/frp/releases/download/v${VERSION}/frp_${VERSION}_linux_${PLATFORM}.tar.gz \ && tar xzf frp_${VERSION}_linux_${PLATFORM}.tar.gz \ && cd frp_${VERSION}_linux_${PLATFORM} \ && mkdir /frp \ && mv frpc frpc.toml /frp \ && cd .. \ && rm -rf *.tar.gz frp_${VERSION}_linux_${PLATFORM} VOLUME /frp CMD /frp/frpc -c /frp/frpc.toml
-
标记推送镜像
$ docker tag frp-client:v0.52.3 registry.cn-shenzhen.aliyuncs.com/code-frp/frpc:v0.52.3 $ docker push registry.cn-shenzhen.aliyuncs.com/code-frp/frpc:v0.52.3
-
启动
docker run -d --name=frpc30 --restart=always -v /opt/frpc/frpc-30.toml:/frp/frpc.toml registry.cn-shenzhen.aliyuncs.com/code-frp/frpc:v0.52.3
-
frps.toml基本配置
serverAddr = "43.154.222.111" serverPort = 7000 auth.token = "xxxx" webServer.addr = "0.0.0.0" webServer.port = 7400 webServer.user = "admin" webServer.password = "xxxx" [[proxies]] name = "admin_ui" type = "tcp" localPort = 7400 remotePort = 7400 [[proxies]] name = "link-api" type = "http" localIP = "192.168.1.202" localPort = 8888 customDomains = ["link.open1024.top"] # 目前支持 v1 和 v2 两个版本的 proxy protocol 协议。 #本地的 HTTPS 服务可以通过在 nginx 的配置中启用 Proxy Protocol 的解析并将结果设置在 X-Real-IP 这个 Header 中就可以在自己的 Web 服务中通过 X-Real-IP 获取到用户的真实 IP #transport.proxyProtocolVersion = "v2" #加密和压缩 transport.useEncryption = true transport.useCompression = true
评论区