前言

很开心之前写的Nginx反代frp成功实现https和泛域名/泛解析能够受到大家的欢迎,下面开始填之前说过的纯享版的坑
包含本地nginx和frpc的配置文件,远端nginx和frps的配置文件,可谓是懒人的福音~

最近忙于工程没有关注blog的情况,发现很多朋友在考虑如何不暴露端口,请注意,本文是为了容差性兼容不正确配置的后端http和https才会暴露端口的,如果你对你的后端nginx配正确性很有信心,则不需要劫持502响应码,但这样如果发生后端配置错误,将直接抛出502给用户,降低用户体验。请谨慎考虑!

为了方便大家偷懒,我已经把配置文件上传至Github,大家下载的时候麻烦给颗星星吧~


如需理解原理,请查找文章末尾的原理链接,如有问题,欢迎大家留言或者知乎私信我~
如实在太懒连粘贴都不爱粘且比较壕气,本人可以提供廉价帮助配置服务,详情请咨询知乎私信~
请务必看完服务器拓扑假设及相关说明再复制代码

关于后端混杂htpps和http还不想全部在frps端处理http到https还想隐藏端口的问题

这种奇怪要求当然我有考虑到 解决方案有两种:
1.为个别后端为http的站点建立单独一组配置文件,在frps所在的服务器的nginx上反代http到https
2.自动检测后端是否为只有http,这里可以直接调用frps提供的api,用lua批量处理
我个人目前使用后的是第二种,但无奈写blog的时间太少,相关方案的示例我会在下一次摸鱼时总结放出

服务器拓扑假设

FRP拓扑图

如上图所示,假设本地有两台服务器,一台nginx服务器负责本地网站的承载下面称为LS1,另一台负责运行frpc下面称为LS2

实际使用中这两台服务器可以合二为一

远端有一台frps服务器
本纯享代码可分别实现四种不同方案(电脑端可根据用途按右侧标题导航快速查找)

  1. 本地LS1正确配置http跳转到https(TLS),远端frps直接监听80 443端口
  2. 本地LS1正确配置http跳转到https(TLS),远端nginx反代frps转发的https实现泛解析和http跳转到https,frps监听其他端口(适用于想要正确传递https客户端真实IP,由于frpc到frps线路质量不佳需要缓存,frps服务器同时需要挂其他网站等特殊需求)
  3. 本地LS1只配置http,远端nginx反向代理frps转发的http到https,frps监听其他端口(是远端nginx反代的伪https,极不推荐,但如有本地特殊http需求或因为懒癌晚期本地确不想用https的请看本部分)
  4. 本地LS1只配置http,远端nginx反向代理frps转发的http到http,frps监听其他端口

方案一:本地LS1正确配置http跳转到https(TLS),远端frps直接监听80 443端口

本地LS1的nginx配置server部分(最简代码,不含安全配置和静态资源缓存配置部分,不含引入开启PHP的配置文件部分,不含日志文件配置,如需要请自行添加原有配置文件的location和include)

server
{
    listen 80;
    listen 443 ssl http2;
    server_name abc.yourdomain.com; #这里写你网站的域名,注意别删掉结尾的分号
    index index.php index.html index.htm default.php default.htm default.html;
    root /www/wwwroot/default; #这里写你网站根目录的地址
    real_ip_header X-Forwarded-For; #用于接收远端frps服务器上nginx传递的真实IP
    real_ip_recursive on;
    if ($server_port !~ 443{ #用于80端口自动跳转到HTTPS
        rewrite ^(/.*)$ https://$host$1 permanent;
    }
    ssl_certificate    /etc/fullchain.pem; #这里写你ssl证书公钥(完整链)的位置,记得要给nginx访问这个文件的权限
    ssl_certificate_key    /etc/privkey.pem; #这里写你ssl证书私钥的位置,记得要给nginx访问这个文件的权限
    ssl_protocols TLSv1.1 TLSv1.2;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    error_page 497  https://$host$request_uri;
}

本地LS2的frpc配置文件

[common]
server_addr = 121.8.1.111 frps服务器地址
server_port = frps服务端口
log_file = ./frpc.log
log_level = info
log_max_days = 3
privilege_token = 你在frps配置文件设置的验证密钥
pool_count = 5
tcp_mux = true
user = 自己定义的用户名
login_fail_exit = true
protocol = tcp

[服务名-自己定义-http]
type = http
local_ip = 192.168.1.111待转发的本地服务器IP,本机写127.0.0.1
local_port = 80 (如其他端口则修改)
use_encryption = false
use_compression = true
custom_domains = 定义域名,如abc.domain.com

[服务名-自己定义-https]
type = https
local_ip = 192.168.1.111待转发的本地服务器IP,本机写127.0.0.1
local_port = 443 (如其他端口则修改)
use_encryption = false
use_compression = true
custom_domains = 定义域名,如abc.domain.com

远程frps服务器的frps配置文件

[common]
bind_addr = 121.8.1.111服务器地址
bind_port = frp的服务端口
bind_udp_port = udp端口需要另外写好
kcp_bind_port = 与frp的服务端口相同即可
vhost_http_port = 80
vhost_https_port = 443
dashboard_addr = 后台面板的地址(可写服务器地址)
dashboard_port = 后台面板的端口,不能为上面定义过的端口
dashboard_user = 后台面板的用户名
dashboard_pwd = 后台面板的密码
log_file = ./frps.log
log_level = info
log_max_days = 3
privilege_token = 验证密钥,自己设置
heartbeat_timeout = 90
privilege_allow_ports = 123-456,789 端口范围 自己设置
authentication_timeout = 900
tcp_mux = true

方案二:本地LS1正确配置http跳转到https(TLS),远端nginx反代frps转发的https实现泛解析和http跳转到https,frps监听其他端口(适用于想要正确传递https客户端真实IP,由于frpc到frps线路质量不佳需要缓存,frps服务器同时需要挂其他网站等特殊需求)

本地LS1的nginx配置server部分(最简代码,不含安全配置和静态资源缓存配置部分,不含引入开启PHP的配置文件部分,不含日志文件配置,如需要请自行添加原有配置文件的location和include)

server
{
    listen 80;
    listen 443 ssl http2;
    server_name abc.yourdomain.com; #这里写你网站的域名,注意别删掉结尾的分号
    index index.php index.html index.htm default.php default.htm default.html;
    root /www/wwwroot/default; #这里写你网站根目录的地址
    real_ip_header X-Forwarded-For; #用于接收远端frps服务器上nginx传递的真实IP
    real_ip_recursive on;
    if ($server_port !~ 443{ #用于80端口自动跳转到HTTPS
        rewrite ^(/.*)$ https://$host$1 permanent;
    }
    ssl_certificate    /etc/fullchain.pem; #这里写你ssl证书公钥(完整链)的位置,记得要给nginx访问这个文件的权限
    ssl_certificate_key    /etc/privkey.pem; #这里写你ssl证书私钥的位置,记得要给nginx访问这个文件的权限
    ssl_protocols TLSv1.1 TLSv1.2;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    error_page 497  https://$host$request_uri;
}

本地LS2的frpc配置文件

[common]
server_addr = 121.8.1.111 frps服务器地址
server_port = frps服务端口
log_file = ./frpc.log
log_level = info
log_max_days = 3
privilege_token = 你在frps配置文件设置的验证密钥
pool_count = 5
tcp_mux = true
user = 自己定义的用户名
login_fail_exit = true
protocol = tcp

[服务名-自己定义-http]
type = http
local_ip = 192.168.1.111 待转发的本地服务器IP,本机写127.0.0.1
local_port = 80 (如其他端口则修改)
use_encryption = false
use_compression = true
custom_domains = 定义域名,如abc.domain.com

[服务名-自己定义-https]
type = https
local_ip = 192.168.1.111 待转发的本地服务器IP,本机写127.0.0.1
local_port = 443 (如其他端口则修改)
use_encryption = false
use_compression = true
custom_domains = 定义域名,如abc.domain.com

远程frps服务器的frps配置文件

[common]
bind_addr = 121.8.1.111服务器地址
bind_port = frp的服务端口
bind_udp_port = udp端口需要另外写好
kcp_bind_port = 与frp的服务端口相同即可
vhost_http_port = 1234 #选择任意非80端口即可
vhost_https_port = 5678 #选择任意非443端口即可
dashboard_addr = 后台面板的地址(可写服务器地址)
dashboard_port = 后台面板的端口,不能为上面定义过的端口
dashboard_user = 后台面板的用户名
dashboard_pwd = 后台面板的密码
log_file = ./frps.log
log_level = info
log_max_days = 3
privilege_token = 验证密钥,自己设置
heartbeat_timeout = 90
privilege_allow_ports = 123-456,789 端口范围 自己设置
authentication_timeout = 900
tcp_mux = true

远程frps服务器的nginx配置server部分(最简代码,不含安全配置和静态资源缓存配置部分,不含引入开启PHP的配置文件部分,不含日志文件配置,如需要请自行添加原有配置文件的location和include)

server
    {
        listen 80;
        listen 443 ssl http2;
        server_name *.yourdomain.com; #你的域名,记得确认已经将*的A记录解析到
        charset utf-8;
    if ($server_port !~ 443){ #http跳转到https
        rewrite ^(/.*)$ https://$host$1 permanent;
   }
    ssl_certificate    /etc/fullchain.pem; #这里写你ssl证书公钥(完整链)的位置,记得要给nginx访问这个文件的权限
    ssl_certificate_key    /etc/privkey.pem; #这里写你ssl证书私钥的位置,记得要给nginx访问这个文件的权限
    ssl_protocols TLSv1.1 TLSv1.2;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    error_page 497  https://$host$request_uri;

        location / {
                resolver 8.8.8.8; #重要,依靠此行解析$host,也可更换其他DNS服务器
                proxy_ssl_server_name on; #重要,反代后端https必要
                proxy_set_header X-Real-IP $remote_addr; #将真实IP封在head中传递给后端
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
                proxy_set_header X-Forwarded-Proto $scheme;
                proxy_set_header Host $host; 
####################################################################################
#重要提示!!
#如果上一行这样写出现跳转到有端口号的网址,为后端跳转方式过于僵硬,建议修改后端网站程序
#若实在难以debug后端代码,则如此修改即可避免:proxy_set_header Host $host:$server_port;
####################################################################################
                proxy_pass https://$host:5678; #5678为frps的https端口
            error_page 502 http://$host:6666/$request_uri; 
                #遇到502错误(后端为http时)通过error_page跳转给下一个server处理
                #6666端口定义为任意值,和下文对应初相等即可
        }
    }
server
    {
        listen 6666; #任意端口,用于接收上一个server502错误不能处理的请求
        listen 7777 ssl http2; #任意端口但需要注意修改后下文的两个也需要修改
        server_name _; #为避免server_name相同导致的错误,这里使用_接管其他配置文件未定义的host
        charset utf-8;
    if ($server_port !~ 7777){ #这里的7777要和上文保持一直
        rewrite ^(/.*)$ https://$host:777$1 permanent; #这里的7777要和上文保持一致
   }
    ssl_certificate    /etc/fullchain.pem; #这里写你ssl证书公钥(完整链)的位置,记得要给nginx访问这个文件的权限
    ssl_certificate_key    /etc/privkey.pem; #这里写你ssl证书私钥的位置,记得要给nginx访问这个文件的权限
    ssl_protocols TLSv1.1 TLSv1.2;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    error_page 497  https://$host:7777$request_uri;
        location / {
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto $scheme;
                proxy_set_header Host $host;
                proxy_pass http://121.8.1.111:1234; 
                #注意,这里的121.8.1.111需要改成你frps服务器的IP,1234需改成你frps服务器的http监听端口
                error_page 502 http://$host:1234$request_uri; 
                #如再次处理不了 则直接跳转给frps的http,1234需改成你frps服务器的http监听端口
        }
    }

方案三:本地LS1只配置http,远端nginx反向代理frps转发的http到https,frps监听其他端口(是远端nginx反代的伪https,极不推荐,但如有本地特殊http需求或因为懒癌晚期本地确不想用https的请看本部分)

本地LS1的nginx配置server部分(最简代码,不含安全配置和静态资源缓存配置部分,不含引入开启PHP的配置文件部分,不含日志文件配置,如需要请自行添加原有配置文件的location和include)

server
{
    listen 80;
    server_name abc.yourdomain.com; #这里写你网站的域名,注意别删掉结尾的分号
    index index.php index.html index.htm default.php default.htm default.html;
    root /www/wwwroot/default; #这里写你网站根目录的地址
    real_ip_header X-Forwarded-For; #用于接收远端frps服务器上nginx传递的真实IP
    real_ip_recursive on;
}

本地LS2的frpc配置文件

[common]
server_addr = 121.8.1.111 frps服务器地址
server_port = frps服务端口
log_file = ./frpc.log
log_level = info
log_max_days = 3
privilege_token = 你在frps配置文件设置的验证密钥
pool_count = 5
tcp_mux = true
user = 自己定义的用户名
login_fail_exit = true
protocol = tcp

[服务名-自己定义-http]
type = http
local_ip = 192.168.1.111 待转发的本地服务器IP,本机写127.0.0.1
local_port = 80 (如其他端口则修改)
use_encryption = false
use_compression = true
custom_domains = 定义域名,如abc.domain.com

远程frps服务器的frps配置文件

[common]
bind_addr = 121.8.1.111服务器地址
bind_port = frp的服务端口
bind_udp_port = udp端口需要另外写好
kcp_bind_port = 与frp的服务端口相同即可
vhost_http_port = 1234 #选择任意非80端口即可
vhost_https_port = 5678 #选择任意非443端口即可
dashboard_addr = 后台面板的地址(可写服务器地址)
dashboard_port = 后台面板的端口,不能为上面定义过的端口
dashboard_user = 后台面板的用户名
dashboard_pwd = 后台面板的密码
log_file = ./frps.log
log_level = info
log_max_days = 3
privilege_token = 验证密钥,自己设置
heartbeat_timeout = 90
privilege_allow_ports = 123-456,789 端口范围 自己设置
authentication_timeout = 900
tcp_mux = true

远程frps服务器的nginx配置server部分(最简代码,不含安全配置和静态资源缓存配置部分,不含引入开启PHP的配置文件部分,不含日志文件配置,如需要请自行添加原有配置文件的location和include)

server
    {
        listen 80;
        listen 443 ssl http2;
        server_name *.yourdomain.com; #你的域名,记得确认已经将*的A记录解析到
        charset utf-8;
    if ($server_port !~ 443){ #http跳转到https
        rewrite ^(/.*)$ https://$host$1 permanent;
   }
    ssl_certificate    /etc/fullchain.pem; #这里写你ssl证书公钥(完整链)的位置,记得要给nginx访问这个文件的权限
    ssl_certificate_key    /etc/privkey.pem; #这里写你ssl证书私钥的位置,记得要给nginx访问这个文件的权限
    ssl_protocols TLSv1.1 TLSv1.2;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    error_page 497  https://$host$request_uri;

        location / {
                proxy_set_header X-Real-IP $remote_addr; #将真实IP封在head中传递给后端
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
                proxy_set_header X-Forwarded-Proto $scheme;
                proxy_set_header Host $host; 
####################################################################################
#重要提示!!
#如果上一行这样写出现跳转到有端口号的网址,为后端跳转方式过于僵硬,建议修改后端网站程序
#若实在难以debug后端代码,则如此修改即可避免:proxy_set_header Host $host:$server_port;
####################################################################################
                proxy_pass http://121.8.1.111:1234; 
                #注意,这里的121.8.1.111需要改成你frps服务器的IP,1234需改成你frps服务器的http监听端口
                error_page 502 http://$host:1234$request_uri; 
                #如处理不了 则直接跳转给frps的http,1234需改成你frps服务器的http监听端口
        }
    }

方案四:本地LS1只配置http,远端nginx反向代理frps转发的http到http,frps监听其他端口

本地LS1的nginx配置server部分(最简代码,不含安全配置和静态资源缓存配置部分,不含引入开启PHP的配置文件部分,不含日志文件配置,如需要请自行添加原有配置文件的location和include)

server
{
    listen 80;
    server_name abc.yourdomain.com; #这里写你网站的域名,注意别删掉结尾的分号
    index index.php index.html index.htm default.php default.htm default.html;
    root /www/wwwroot/default; #这里写你网站根目录的地址
    real_ip_header X-Forwarded-For; #用于接收远端frps服务器上nginx传递的真实IP
    real_ip_recursive on;
}

本地LS2的frpc配置文件

[common]
server_addr = 121.8.1.111 frps服务器地址
server_port = frps服务端口
log_file = ./frpc.log
log_level = info
log_max_days = 3
privilege_token = 你在frps配置文件设置的验证密钥
pool_count = 5
tcp_mux = true
user = 自己定义的用户名
login_fail_exit = true
protocol = tcp

[服务名-自己定义-http]
type = http
local_ip = 192.168.1.111 待转发的本地服务器IP,本机写127.0.0.1
local_port = 80 (如其他端口则修改)
use_encryption = false
use_compression = true
custom_domains = 定义域名,如abc.domain.com

远程frps服务器的frps配置文件

[common]
bind_addr = 121.8.1.111服务器地址
bind_port = frp的服务端口
bind_udp_port = udp端口需要另外写好
kcp_bind_port = 与frp的服务端口相同即可
vhost_http_port = 1234 #选择任意非80端口即可
vhost_https_port = 5678 #选择任意非443端口即可
dashboard_addr = 后台面板的地址(可写服务器地址)
dashboard_port = 后台面板的端口,不能为上面定义过的端口
dashboard_user = 后台面板的用户名
dashboard_pwd = 后台面板的密码
log_file = ./frps.log
log_level = info
log_max_days = 3
privilege_token = 验证密钥,自己设置
heartbeat_timeout = 90
privilege_allow_ports = 123-456,789 端口范围 自己设置
authentication_timeout = 900
tcp_mux = true

远程frps服务器的nginx配置server部分(最简代码,不含安全配置和静态资源缓存配置部分,不含引入开启PHP的配置文件部分,不含日志文件配置,如需要请自行添加原有配置文件的location和include)

server
    {
        listen 80;
        server_name *.yourdomain.com; #你的域名,记得确认已经将*的A记录解析到
        charset utf-8;

        location / {
                proxy_set_header X-Real-IP $remote_addr; #将真实IP封在head中传递给后端
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
                proxy_set_header X-Forwarded-Proto $scheme;
                proxy_set_header Host $host; 
####################################################################################
#重要提示!!
#如果上一行这样写出现跳转到有端口号的网址,为后端跳转方式过于僵硬,建议修改后端网站程序
#若实在难以debug后端代码,则如此修改即可避免:proxy_set_header Host $host:$server_port;
####################################################################################
                proxy_pass http://121.8.1.111:1234; 
                #注意,这里的121.8.1.111需要改成你frps服务器的IP,1234需改成你frps服务器的http监听端口
                error_page 502 http://$host:1234$request_uri; 
                #如处理不了 则直接跳转给frps的http,1234需改成你frps服务器的http监听端口
        }
    }
Last modification:August 10th, 2019 at 09:53 am