在公网服务器搭建frps(service),在内网本地机子搭建frpc(client),流量通过访问公网ip,经过frps服务端转发到fprc客户端,fprc再转发到本地web应用。
官方下载地址 https://github.com/fatedier/frp/releases
官方文档地址https://gofrp.org/docs/
服务端:frp_0.44.0_linux_amd64.tar.gz
客户端:frp_0.44.0_windows_amd64.zip
一、http
服务端frps(公网服务器)
这里我用虚拟机模拟了一台公网服务器:192.168.111.201
# 解压
tar -xzvf frp_0.44.0_linux_amd64.tar.gz
cd frp_0.44.0_linux_amd64
# 配置服务端
vi frps.ini
配置 frps.ini
[common]
# frp服务端的端口,frp客户端需要连接这个端口握手
bind_port = 7000
# 公网服务端对外提供的http端口
vhost_http_port=8080
启动服务端
./frps -c frps.ini
后台启动运行服务端
nohup ./frps -c frps.ini >/dev/null 2>&1 &
客户端frpc(内网本地)
配置 frpc.ini
[common]
# frps服务端的ip和端口
server_addr = 192.168.111.201
server_port = 7000
[web01]
type = http
# 本地web应用的ip和端口
local_ip = 127.0.0.1
local_port = 8080
#公网服务器的ip或域名
custom_domains = 192.168.111.201
到解压根目录启动客户端
frpc -c frpc.ini
访问公网ip已经可以反向代理到本地web服务了。
以上就是一个简单的内网穿透 http 例子。
二、https
使用官方推荐的如下配置:
frps.ini
[common]
bind_port = 7000
vhost_https_port = 443
frpc.ini
[common]
server_addr = 192.168.111.201
server_port = 7000
[plugin_https2https]
type = https
custom_domains = 192.168.111.201
plugin = https2https
plugin_local_addr = 127.0.0.1:8443
#plugin_crt_path = ./server.crt
#plugin_key_path = ./server.key
plugin_host_header_rewrite = 127.0.0.1
plugin_header_X-From-Where = frp
结果一直报如下错误,没找到解决办。
三、tcp实现https
研究了好久,才反应过来,http协议在应用层,tcp在传输层,且http是基于tcp的。
既然https失败了,直接转发tcp就是,把ssl放在本地web应用中就可以了,frp只做tcp流量转发。
frps.ini
[common]
bind_port = 7000
frpc.ini
[common]
server_addr = 192.168.111.201
server_port = 7000
[tcp]
type = tcp
# 本地web应用的ip和端口
local_ip = 127.0.0.1
local_port = 8443
# 公网服务器提供给外网访问的端口
remote_port = 443
四、安全加固
上面有2个不安全的地方:
1、frpc 和 frps 之间的身份验证不安全,默认为 token,这种方式存在被中间人攻击的威胁。
2、frpc 和 frps 之间的流量为加密,可以通过 TLS 协议加密,解决被中间人攻击的威胁。
frps.ini
[common]
#frps服务端监听的端口,frpc客户端要来连接。
bind_port = 7000
#密码设置复杂点,frps服务端密码和frpc客户端密码要一致。
token = mm123456789
frpc.ini
[common]
# frps服务端的ip和端口
server_addr = 192.168.111.201
server_port = 7000
#密码设置复杂点,frps服务端密码和frpc客户端密码要一致。
token = mm123456789
[tcp]
type = tcp
# 本地web应用的ip和端口
local_ip = 127.0.0.1
local_port = 8443
# 公网服务器提供给外网访问的端口
remote_port = 443
双向验证
双向验证即 frpc 和 frps 通过本地 ca 证书去验证对方的身份。理论上 frpc 和 frps 的 ca 证书可以不同,只要能验证对方身份即可。
frps.ini
# frps.ini
[common]
#frps服务端监听的端口,frpc客户端要来连接。
bind_port = 7000
#密码设置复杂点,frps服务端密码和frpc客户端密码要一致。
token = mm123456789
tls_cert_file = ./server.crt
tls_key_file = ./server.key
tls_trusted_ca_file = ./ca.crt
frpc.ini
# frpc.ini
[common]
# frps服务端的ip和端口
server_addr = 192.168.111.201
server_port = 7000
#密码设置复杂点,frps服务端密码和frpc客户端密码要一致。
token = mm123456789
# frpc开启TLS加密功能
tls_enable = true
tls_cert_file = ./client.crt
tls_key_file = ./client.key
tls_trusted_ca_file = ./ca.crt
[tcp]
type = tcp
# 本地web应用的ip和端口
local_ip = 127.0.0.1
local_port = 8443
# 公网服务器提供给外网访问的端口
remote_port = 443
生成SAN 证书
1、准备默认 my-openssl.cnf 配置文件于当前目录
cat > my-openssl.cnf << EOF
[ ca ]
default_ca = CA_default
[ CA_default ]
x509_extensions = usr_cert
[ req ]
default_bits = 2048
default_md = sha256
default_keyfile = privkey.pem
distinguished_name = req_distinguished_name
attributes = req_attributes
x509_extensions = v3_ca
string_mask = utf8only
[ req_distinguished_name ]
[ req_attributes ]
[ usr_cert ]
basicConstraints = CA:FALSE
nsComment = "OpenSSL Generated Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
[ v3_ca ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = CA:true
EOF
2、生成默认CA
openssl genrsa -out ca.key 2048
openssl req -x509 -new -nodes -key ca.key -subj "/CN=example.ca.com" -days 3650 -out ca.crt
3、生成服务端证书
将 192.168.111.201 改成自己的服务端的ip
openssl genrsa -out server.key 2048
openssl req -new -sha256 -key server.key \
-subj "/C=XX/ST=DEFAULT/L=DEFAULT/O=DEFAULT/CN=192.168.111.201" \
-reqexts SAN \
-config <(cat my-openssl.cnf <(printf "\n[SAN]\nsubjectAltName=DNS:localhost,IP:127.0.0.1,DNS:server.com,IP:192.168.111.201")) \
-out server.csr
openssl x509 -req -days 3650 -sha256 \
-in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
-extfile <(printf "subjectAltName=DNS:localhost,IP:127.0.0.1,DNS:server.com,IP:192.168.111.201") \
-out server.crt
4、生成客户端证书
使用 who 命令查询客户端的ip地址。我这里是192.168.111.1
将 192.168.111.1 改成自己的客户端的ip
openssl genrsa -out client.key 2048
openssl req -new -sha256 -key client.key \
-subj "/C=XX/ST=DEFAULT/L=DEFAULT/O=DEFAULT/CN=192.168.111.1" \
-reqexts SAN \
-config <(cat my-openssl.cnf <(printf "\n[SAN]\nsubjectAltName=DNS:client.com,IP:192.168.111.1")) \
-out client.csr
openssl x509 -req -days 3650 -sha256 \
-in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
-extfile <(printf "subjectAltName=DNS:client.com,IP:192.168.111.1") \
-out client.crt
最终生成了10个文件。
server.crt、server.key、ca.crt 拷贝到 frp服务端解压目录下。
client.crt、client.key、ca.crt 拷贝到 frp客户端解压目录下。