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 资源