Nginx 代理请求到 frp 做内网穿透
frp 安装
frp 安装:https://gofrp.org/zh-cn/docs/setup/
使用 systemd 命令管理 frps 服务:https://gofrp.org/zh-cn/docs/setup/systemd/
注:客户端和服务端可以分别配置 frps.service 和 frpc.service,配置步骤一样。
frp 配置和使用
- 通过 SSH 访问内网机器
- 多个 SSH 服务复用同一端口
- 通过自定义域名访问内网的 Web 服务
- 为本地 HTTP 服务启用 HTTPS
- 身份认证
- Web 界面
- 修改 HTTP 请求 Header
- 自定义二级域名
- URL 路由
frps.service
vi /usr/lib/systemd/system/frps.service
shell
[Unit]
Description = frp server
After = network.target syslog.target
Wants = network.target
[Service]
Type = simple
# 启动frps的命令,需修改为您的frps的安装路径
ExecStart = /opt/frp/frps -c /opt/frp/frps.toml
[Install]
WantedBy = multi-user.target
frpc.service
vi /usr/lib/systemd/system/frpc.service
shell
[Unit]
Description = frp client
After = network.target syslog.target
Wants = network.target
[Service]
Type = simple
# 启动frps的命令,需修改为您的frps的安装路径
ExecStart = /opt/frp/frpc -c /opt/frp/frpc.toml
[Install]
WantedBy = multi-user.target
systemd 命令管理 frps.service 服务
shell
# 设置 frps 开机自启动
systemctl enable frps
# 启动frps
sudo systemctl start frps
# 停止frps
sudo systemctl stop frps
# 重启frps
sudo systemctl restart frps
# 查看frps状态
sudo systemctl status frps
注:frpc.service 同理。
frp 内网穿透示例
frps.toml (vhostHTTPPort 使用 81 端口,避免和 nginx 冲突)
toml
bindPort = 13462
vhostHTTPPort = 81
#vhostHTTPSPort = 443
auth.token = "abcdef"
frpc.toml (serverAddr 填写实际的服务器端IP或域名)
toml
serverAddr = "aday.fun"
serverPort = 13462
auth.token = "abcdef"
# 以下为代理 ssh 端口
[[proxies]]
name = "ssh"
type = "tcp"
localIP = "127.0.0.1"
localPort = 22
remotePort = 13463
# 以下为代理为 http
[[proxies]]
name = "home_http"
type = "http"
localPort = 8001
customDomains = ["home.aday.fun"]
[[proxies]]
name = "vitality_http"
type = "http"
localPort = 8080
customDomains = ["vitality.aday.fun"]
[[proxies]]
name = "jenkins_http"
type = "http"
localPort = 8090
customDomains = ["jenkins.aday.fun"]
# 以下为代理为 https
# http 配置可和 https 配置同时存在,以达到同时支持两种协议的目的
[[proxies]]
name = "home"
type = "https"
customDomains = ["home.aday.fun"]
[proxies.plugin]
type = "https2http"
localAddr = "127.0.0.1:8001"
crtPath = "/etc/nginx/ssl/aday.crt"
keyPath = "/etc/nginx/ssl/aday.key"
hostHeaderRewrite = "home.aday.fun"
requestHeaders.set.x-from-where = "frp"
[[proxies]]
name = "vitality"
type = "https"
customDomains = ["vitality.aday.fun"]
[proxies.plugin]
type = "https2http"
localAddr = "127.0.0.1:8080"
crtPath = "/etc/nginx/ssl/aday.crt"
keyPath = "/etc/nginx/ssl/aday.key"
hostHeaderRewrite = "vitality.aday.fun"
requestHeaders.set.x-from-where = "frp"
[[proxies]]
name = "jenkins"
type = "https"
customDomains = ["jenkins.aday.fun"]
[proxies.plugin]
type = "https2http"
localAddr = "127.0.0.1:8090"
crtPath = "/etc/nginx/ssl/aday.crt"
keyPath = "/etc/nginx/ssl/aday.key"
hostHeaderRewrite = "jenkins.aday.fun"
requestHeaders.set.x-from-where = "frp"
Nginx 代理到 frp 内网穿透示例
假设 frps 服务端有一个 nginx, 本身代理了 80/443 端口提供了一个 home.aday.fun 服务。
现在 frpc 客户端有一个 vitality 服务需要被代理,用户需要先访问 vitality.aday.fun 域名,然后请求穿过 nginx,再由 nginx 转发到 frp 穿透的主机上。
frpc.toml 配置参考
toml
serverAddr = "aday.fun"
serverPort = 13462
auth.token = "abcdef"
# 假设 frpc 客户端已经代理好了 http://vitality.aday.fun:81 来访问服务。如下:
[[proxies]]
name = "vitality"
type = "http"
localPort = 8080
customDomains = ["vitality.aday.fun"]
nginx.conf
shell
# user nobody;
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
client_max_body_size 1024m;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
server {
listen 80;
server_name *.aday.fun;
rewrite ^(.*)$ https://$host$1 permanent;
}
server {
listen 443 ssl;
server_name home.aday.fun;
ssl_certificate /etc/nginx/ssl/aday.cer;
ssl_certificate_key /etc/nginx/ssl/aday.key;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
# vue 项目这样配置
#try_files $uri $uri/ /index.html;
# vitepress 项目这样配置
try_files $uri $uri.html $uri/ =404;
error_page 404 /404.html;
error_page 403 /404.html;
}
}
server {
listen 443 ssl;
server_name vitality.aday.fun;
ssl_certificate /etc/nginx/ssl/aday.cer;
ssl_certificate_key /etc/nginx/ssl/aday.key;
location / {
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# 注意,这里使用了不同的 81 frp 端口
proxy_pass http://vitality.aday.fun:81/;
}
}
}
txt
这样:
访问 https://vitality.aday.fun:443 就会被 nginx 转发到 frp 代理的 http://vitality.aday.fun:81/ 地址;
访问 http://vitality.aday.fun:80 就会被 nginx 转先转为 https,然后再转发到 frp 代理的 http://vitality.aday.fun:81/ 地址;
访问 http://vitality.aday.fun:81 就直接会被 frp 接收到,直接转发到真实服务。
也比较推荐从 nginx 转发到 frp 做内网穿透:
- 这样 ssl 证书可以放在 nginx 端
- 可使用 nginx 隐藏访问端口,来更方便的访问多个服务
- 让 frp 符合单一职责,就只让 frp 做内网穿透,其他交给 nginx 来做,逻辑更清楚。