frp介绍
frp
是一款非常经典并且功能非常强大的"打洞"(内网穿透)工具,简单来说,就是通过在内网机器和公网服务器之间搭建"隧道"(将内网服务的端口映射到公网服务器),从而使外部用户能够通过公网服务器访问到内网机器的服务
项目地址:https://github.com/fatedier/frp
frp
支持的协议和可实现的功能非常多,具体可以参考文档,本文只介绍如何暴露内网服务并通过nginx
配置https
原理和过程介绍
其实非常简单,就一句话简单带过了
首先,frp
将内网http
服务映射到公网服务器的某个端口,然后在服务器通过nginx
配置反向代理将请求发送到这个端口,由nginx
服务器负责与客户端通信时的SSL/TLS
加密,frp
负责和内网服务通信
配置
首先,在内网机器和公网服务器都下载frp
可执行程序,可以直接到frp
的github项目中的release里下载最新版本。下载并解压后,可以得到服务端程序(frps
)、客户端程序(frpc
)和各自的配置文件(frps.toml
、frpc.toml
)
frps
公网服务器中只需要用到frps
和frps.toml
使用systemd管理frps服务
在多数场景下,我们通常使用的是Linux系统,因此建议使用systemd
来管理frps
首先,在/etc/systemd/system
目录下创建frps.service
文件,写入以下内容,注意,仅需要将ExecStart
后面中的/root/frp/frps
和/root/frp/frps.toml
改为自己的对应文件的绝对路径
[Unit]
Description=Frp Server Service
After = network.target syslog.target
Wants = network.target
[Service]
Type=simple
Restart=on-failure
RestartSec=5s
ExecStart=/root/frp/frps -c /root/frp/frps.toml
LimitNOFILE=1048576
[Install]
WantedBy=multi-user.target
保存并退出后,就可以使用systemd
来管理frps
服务啦
# 启动frp
systemctl start frps
# 停止frp
systemctl stop frps
# 重启frp
systemctl restart frps
# 查看frp状态
systemctl status frps
# 设置frps开机自启
systemctl enable frps
配置文件
接下来编辑frps.toml
文件,写入以下内容:
bindPort = 17000
auth.method = "token"
auth.token = "YourStrongToken"
vhostHTTPPort = 18000
参数解释:
bindPort
:设置frps
服务的监听端口,用于和frpc
建立连接
auth.method
:设置认证方法,用于和frpc
建立连接时进行身份认证,一般用token
就可以
auth.token
:设置一个用于用户认证的密码
vhostHTTPPort
:设置内网http
服务在公网服务器上的映射端口
设置好后,可以通过systemctl restart frps
重启服务,服务端frps
就配置完成,等待内网客户端frpc
发起连接啦
frpc
内网服务器中只需要用到frpc
和frpc.toml
打开frpc.toml
文件进行编辑,写入以下内容:
serverAddr = "server_ip"
serverPort = 17000
auth.token = "YourStrongToken"
[[proxies]]
name = "web"
type = "http"
localPort = 80
customDomains = ["www.domain1.com"]
[[proxies]]
name = "web2"
type = "http"
localPort = 8080
customDomains = ["www.domain2.com"]
参数解释:
serverAddr
:替换为公网服务器的ip地址
serverPort
:frps
服务监听端口
auth.token
:frps
设置的认证密码
[[proxies]]
参数解释:
name
:给内网http
服务起个名字
type
:协议类型设置为http
localPort
:http
服务在内网的监听端口
customDomains
:设置用于访问该http
服务的域名
其中,customDomains
非常重要,它用于确定访问的具体是哪一个内网服务,因为可以通过设置许多[[proxies]]
来设置多个内网http
服务,但是在公网服务器映射的端口只有一个,因此需要通过访问的域名来对应不同的内网http
服务
配置完成后,如果是Linux
系统,到对应路径执行./frpc -c frpc.toml
就可以启动,同样也可以跟frps
一样推荐用systemd
管理;如果是Windows
系统,可以设置任务计划来运行
nginx
完成frps
和frpc
配置后,只需要到公网服务器配置一下nginx
反向代理
首先为内网http
服务设置一个域名,例如www.domain1.com
,然后将域名解析到公网服务的ip,并用certbot
申请SSL
证书
到/etc/nginx/conf.d/
目录下为frps
代理的内网http
服务创建一个统一的nginx
配置文件frps-http.conf
,然后写入以下内容,需要将域名和证书替换为自己的
server {
listen 80;
server_name www.domain1.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
http2 on;
server_name www.domain1.com;
ssl_certificate /etc/letsencrypt/live/www.domain1.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/www.domain1.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:18000/;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
然后systemctl restart nginx
后,就可以通过https://www.domain1.com
访问对应的内网服务啦
关于加密的说明
你可能会发现,在整个过程中,客户端和nginx
之间的通信采用了HTTPS
进行了加密传输,nginx
将流量反向代理到frps
使用的是本地局域网环回地址所以也没有安全问题,但frps
和frpc
之间通信的流量却是在公网传输的,所以是存在安全隐患的
不过,根据官方文档,最新版本的frps
和frpc
之间的数据传输已经默认开启了TLS加密,不需要单独配置,当然,如果你想的话也可以按照如下示例指定开启或关闭:
[[proxies]]
name = "ssh"
type = "tcp"
localPort = 22
remotePort = 6000
transport.useEncryption = true # 开启TLS加密
transport.useCompression = true # 传输内容启动压缩,可以加快流量转发速度,但是会额外消耗一些 CPU 资源