CentOS 7.9 + 宝塔 + FRP 自建内网穿透:公网访问 Armbian noVNC 与 1Panel
侧边栏壁纸
  • 累计撰写 7 篇文章
  • 累计收到 0 条评论

CentOS 7.9 + 宝塔 + FRP 自建内网穿透:公网访问 Armbian noVNC 与 1Panel

agblr
2026-09-19 / 0 评论 / 3 阅读 / 正在检测是否收录...

一、需求背景

目前有两台服务器:

公网服务器

系统环境:

CentOS 7.9.2009 x86_64
宝塔面板
Nginx
公网 IP

用途:

  • 部署 FRP 服务端 frps
  • 作为公网入口
  • 使用宝塔 Nginx 配置域名
  • 使用 HTTPS 访问内网服务

内网设备

系统环境:

Armbian 23.02.2 Jammy
Ubuntu 22.04

目前运行:

noVNC:
127.0.0.1:6081

1Panel:
127.0.0.1:2333

目标:

https://vnc.agblr.xyz
        ↓
访问 Armbian noVNC

https://a.agblr.xyz
        ↓
访问 Armbian 1Panel

并且内网的 6081、2333 不直接暴露到公网。


二、最终架构

整体架构如下:

                    Internet
                        │
                        ▼
                Cloudflare / DNS
                        │
                        ▼
              CentOS 公网服务器
                宝塔 + Nginx
                  :80 / :443
                        │
          ┌─────────────┴─────────────┐
          │                           │
          ▼                           ▼
127.0.0.1:16081                127.0.0.1:2333
     noVNC代理                    1Panel代理
          │                           │
          └────────── FRPS ───────────┘
                        │
                     :7000
                        │
                    Internet
                        │
                       FRPC
                        │
               ┌────────┴────────┐
               │                 │
               ▼                 ▼
       127.0.0.1:6081      127.0.0.1:2333
            noVNC              1Panel
               │
               └──── Armbian ────

公网只需要开放:

80/TCP
443/TCP
7000/TCP

FRP 映射出来的:

16081
2333

只监听:

127.0.0.1

因此无法直接从公网通过:

公网IP:16081
公网IP:2333

访问。


三、为什么不用宝塔 FRP 插件

最开始尝试使用宝塔的 FRP 管理器,但报错:

AttributeError: module 'public' has no attribute 'get_server_ip'

完整关键位置:

self.config['serveraddr'] = public.get_server_ip()

原因是:

宝塔版本:7.9.2
CentOS:7.9.2009
Python:3.7.9

FRP 插件调用了旧版宝塔 API:

public.get_server_ip()

而当前宝塔代码中已经不存在该接口。

因此最终放弃宝塔 FRP 插件,改为:

FRP 手动安装
+
systemd 管理
+
宝塔只负责 Nginx / 域名 / HTTPS

这种方式也更加稳定。


四、CentOS 安装 FRP 服务端

创建目录:

mkdir -p /www/server/frp
cd /www/server/frp

下载 FRP:

wget gh-proxy.com/https://github.com/fatedier/frp/releases/download/v0.70.1/frp_0.70.1_linux_amd64.tar.gz

解压:

tar -zxf frp_0.70.1_linux_amd64.tar.gz

复制 frps:

cp frp_0.70.1_linux_amd64/frps /www/server/frp/frps
chmod 755 /www/server/frp/frps

验证:

/www/server/frp/frps --version

输出:

0.70.1

说明安装成功。


五、一个实际踩过的坑:下载文件损坏

第一次下载时,由于目录里已经有同名文件,wget 实际把新的完整文件保存为了:

frp_0.70.1_linux_amd64.tar.gz.1

但后续却执行:

tar -zxf frp_0.70.1_linux_amd64.tar.gz

导致解压的是旧的残缺文件。

报错:

gzip: stdin: unexpected end of file
tar: Unexpected EOF in archive
tar: Error is not recoverable

随后复制出来的 frps 也不完整:

/www/server/frp/frps --version

直接出现:

Segmentation fault

解决方法是删除旧文件重新下载:

rm -rf /www/server/frp/*

重新下载、解压后:

/www/server/frp/frps --version

正常返回:

0.70.1

以后遇到类似问题可以先检查:

ls -lh

以及:

gzip -t frp_0.70.1_linux_amd64.tar.gz

如果 gzip -t 没有输出,一般说明 gzip 文件完整。


六、配置 FRP 服务端

生成一个随机 Token:

openssl rand -hex 32

例如:

52ba40b2e66447009793152b1fe5aa03ba175bed401bfde15922e8969925d831

实际使用时请使用自己生成的 Token。

创建:

vi /www/server/frp/frps.toml

配置:

bindAddr = "0.0.0.0"
bindPort = 7000

proxyBindAddr = "127.0.0.1"

auth.method = "token"
auth.token = "替换成自己的TOKEN"

allowPorts = [
  { single = 16081 },
  { single = 2333 }
]

这里有两个比较重要的地方。

proxyBindAddr

proxyBindAddr = "127.0.0.1"

意味着 FRP 客户端映射出来的端口只监听:

127.0.0.1

不会变成:

0.0.0.0

这样可以避免 16081 和 2333 直接暴露公网。

allowPorts

allowPorts = [
  { single = 16081 },
  { single = 2333 }
]

限制客户端只允许申请:

16081
2333

避免 FRP 客户端随意创建其他公网映射。


七、验证 FRP 服务端配置

执行:

/www/server/frp/frps verify -c /www/server/frp/frps.toml

如果没有配置错误即可继续。


八、配置 systemd

创建:

vi /etc/systemd/system/frps.service

内容:

[Unit]
Description=FRP Server
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=/www/server/frp/frps -c /www/server/frp/frps.toml
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

加载:

systemctl daemon-reload

设置开机启动:

systemctl enable --now frps

检查:

systemctl status frps --no-pager -l

检查监听:

ss -lntp | grep 7000

正常应该看到:

0.0.0.0:7000

九、开放 FRP 服务端端口

CentOS firewalld:

firewall-cmd --permanent --add-port=7000/tcp
firewall-cmd --reload

宝塔安全页面也允许:

TCP 7000

如果使用腾讯云、阿里云等,还需要在云服务器安全组开放:

TCP 7000

注意:

16081
2333

不需要开放。


十、Armbian 安装 FRP 客户端

先查看 CPU 架构:

uname -m

如果:

aarch64

则使用 ARM64 版本。

创建目录:

mkdir -p /opt/frp
cd /opt/frp

下载:

wget gh-proxy.com/https://github.com/fatedier/frp/releases/download/v0.70.1/frp_0.70.1_linux_arm64.tar.gz

解压:

tar -zxf frp_0.70.1_linux_arm64.tar.gz

复制:

cp frp_0.70.1_linux_arm64/frpc /opt/frp/frpc
chmod 755 /opt/frp/frpc

验证:

/opt/frp/frpc --version

应该显示:

0.70.1

十一、确认内网服务

noVNC:

ss -lntp | grep 6081

确认:

127.0.0.1:6081

测试:

curl -I http://127.0.0.1:6081

1Panel:

ss -lntp | grep 2333

确认:

127.0.0.1:2333

十二、配置 FRP 客户端

创建:

nano /opt/frp/frpc.toml

内容:

serverAddr = "CentOS公网IP"
serverPort = 7000

auth.method = "token"
auth.token = "和CentOS完全相同的TOKEN"

[[proxies]]
name = "novnc"
type = "tcp"
localIP = "127.0.0.1"
localPort = 6081
remotePort = 16081

[[proxies]]
name = "1panel"
type = "tcp"
localIP = "127.0.0.1"
localPort = 2333
remotePort = 2333

最终映射关系:

Armbian 127.0.0.1:6081
→
CentOS 127.0.0.1:16081

以及:

Armbian 127.0.0.1:2333
→
CentOS 127.0.0.1:2333

十三、启动 FRP 客户端测试

先检查:

/opt/frp/frpc verify -c /opt/frp/frpc.toml

前台运行:

/opt/frp/frpc -c /opt/frp/frpc.toml

成功后,在 CentOS 上执行:

ss -lntp | grep -E '16081|2333'

应该看到:

127.0.0.1:16081
127.0.0.1:2333

测试 noVNC:

curl -I http://127.0.0.1:16081

测试 1Panel:

curl -I http://127.0.0.1:2333

只要有正常 HTTP 响应,FRP 就已经打通。


十四、Armbian 设置 frpc 开机启动

创建:

vi /etc/systemd/system/frpc.service

内容:

[Unit]
Description=FRP Client
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=/opt/frp/frpc -c /opt/frp/frpc.toml
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

执行:

systemctl daemon-reload
systemctl enable --now frpc

检查:

systemctl status frpc --no-pager -l

查看实时日志:

journalctl -u frpc -f

服务端日志:

journalctl -u frps -f

十五、宝塔配置 noVNC 域名

例如使用:

vnc.agblr.xyz
vnc.23332048.xyz

将域名解析到:

CentOS公网IP

然后创建宝塔站点。

noVNC 的 Nginx 配置可以使用:

server
{
    listen 80;
    server_name vnc.agblr.xyz vnc.23332048.xyz;

    root /www/wwwroot/vnc.agblr.xyz;

    location ^~ /.well-known/acme-challenge/
    {
        root /www/wwwroot/vnc.agblr.xyz;
        allow all;
    }

    location /
    {
        proxy_pass http://127.0.0.1:16081;

        proxy_http_version 1.1;

        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        proxy_set_header Host $host;
        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_connect_timeout 30s;
        proxy_read_timeout 3600s;
        proxy_send_timeout 3600s;

        proxy_buffering off;
        proxy_cache off;
    }

    access_log /www/wwwlogs/vnc.agblr.xyz.log;
    error_log /www/wwwlogs/vnc.agblr.xyz.error.log;
}

其中最重要的是:

proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

因为 noVNC 使用 WebSocket。

如果没有这几行,很可能出现:

网页可以打开
但是 VNC 无法连接
WebSocket connection failed

十六、宝塔配置 1Panel 域名

例如:

a.agblr.xyz
a.23332048.xyz

对应:

127.0.0.1:2333

配置:

server
{
    listen 80;
    server_name a.agblr.xyz a.23332048.xyz;

    index index.php index.html index.htm default.php default.htm default.html;
    root /www/wwwroot/a.agblr.xyz;

    #SSL-START
    #error_page 404/404.html;
    #SSL-END

    #ERROR-PAGE-START
    #error_page 404 /404.html;
    #error_page 502 /502.html;
    #ERROR-PAGE-END

    location ^~ /.well-known/acme-challenge/
    {
        root /www/wwwroot/a.agblr.xyz;
        allow all;
    }

    location /
    {
        proxy_pass http://127.0.0.1:2333;

        proxy_http_version 1.1;

        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        proxy_set_header Host $host;
        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 X-Forwarded-Host $host;

        proxy_connect_timeout 30s;
        proxy_send_timeout 3600s;
        proxy_read_timeout 3600s;

        proxy_buffering off;
        proxy_cache off;
        proxy_request_buffering off;

        client_max_body_size 1024m;
    }

    location ~ ^/(\.user.ini|\.htaccess|\.git|\.svn|\.project|LICENSE|README.md)
    {
        return 404;
    }

    access_log /www/wwwlogs/a.agblr.xyz.log;
    error_log /www/wwwlogs/a.agblr.xyz.error.log;
}

之所以同样保留 WebSocket,是因为 1Panel 的:

SSH终端
容器终端
实时日志

等功能都可能依赖 WebSocket。


十七、检查 Nginx 配置

每次修改完都先执行:

/www/server/nginx/sbin/nginx -t

如果显示:

syntax is ok
test is successful

再重新加载:

/www/server/nginx/sbin/nginx -s reload

不要直接重启 Nginx。

这样即使配置写错,也不会直接把现有网站全部打断。


十八、曾遇到的 Nginx 报错

遇到过:

nginx: [emerg] "location" directive is not allowed here

原因是把:

location /
{
}

写到了:

server
{
}

外面。

Nginx 正确结构必须是:

server
{
    listen 80;

    server_name example.com;

    location /
    {
        ...
    }
}

不能:

location /
{
}

server
{
}

十九、Cloudflare 域名如何访问 noVNC

如果另有一个域名:

xxx.com

托管在 Cloudflare,可以让它访问相同的 noVNC。

Cloudflare DNS:

类型:A
名称:@
内容:CentOS公网IP
代理状态:已代理(橙色云)

访问:

https://xxx.com

时,浏览器实际上还是访问:

Cloudflare :443
→
CentOS Nginx :443

然后由 Nginx 再反代到:

127.0.0.1:16081

这是正常行为。

DNS 本身只负责:

域名 → IP

DNS 不负责:

域名 → IP:端口

所以不能配置:

xxx.com → CentOSIP:16081

二十、CNAME 能不能用

可以。

例如:

xxx.com
CNAME
vnc.agblr.xyz

但是要注意:

CNAME 只是 DNS 别名。

访问:

https://xxx.com

时 HTTP Host 仍然是:

xxx.com

不会自动变成:

vnc.agblr.xyz

因此 Nginx 仍然需要:

server_name vnc.agblr.xyz xxx.com;

否则 Nginx 可能匹配到其他站点。

同时 CNAME 不能写:

vnc.agblr.xyz:16081

也不能写:

https://vnc.agblr.xyz/vnc.html

因为 DNS 不理解端口和 URL 路径。


二十一、URL 跳转与反向代理的区别

如果只要求:

访问 xxx.com

然后浏览器地址变成:

vnc.agblr.xyz

可以使用 Cloudflare Redirect Rules。

这种属于:

301/302 跳转

最终地址栏会发生变化。

例如:

https://xxx.com
        ↓
302
        ↓
https://vnc.agblr.xyz

但是如果要求:

访问 https://xxx.com

地址栏始终保持:
https://xxx.com

实际访问:
noVNC

则应该使用:

Nginx reverse_proxy

而不是 URL 跳转。


二十二、Cloudflare + noVNC 最终链路

最终推荐:

浏览器
   │
   │ HTTPS / WSS
   ▼
Cloudflare
   │
   │ HTTPS
   ▼
CentOS 宝塔 Nginx
   │
   │ HTTP + WebSocket
   ▼
127.0.0.1:16081
   │
   ▼
FRPS
   │
   ▼
FRPC
   │
   ▼
Armbian 127.0.0.1:6081
   │
   ▼
noVNC

如果使用 Cloudflare 橙色云,建议:

SSL/TLS:
Full (strict)

同时源站也申请正常 HTTPS 证书。


二十三、常用排错命令

查看 FRPS

systemctl status frps

日志:

journalctl -u frps -f

监听:

ss -lntp | grep 7000

查看 FRPC

systemctl status frpc

日志:

journalctl -u frpc -f

查看映射端口

CentOS:

ss -lntp | grep -E '16081|2333'

正常:

127.0.0.1:16081
127.0.0.1:2333

noVNC 测试

CentOS:

curl -I http://127.0.0.1:16081

1Panel 测试

curl -I http://127.0.0.1:2333

Nginx 检查

/www/server/nginx/sbin/nginx -t

重新加载:

/www/server/nginx/sbin/nginx -s reload

二十四、安全建议

当前架构中最重要的安全设计是:

proxyBindAddr = "127.0.0.1"

因此:

16081
2333

没有直接暴露公网。

公网真正开放的是:

80
443
7000

推荐继续保持这种模式:

公网
↓
Nginx
↓
本机 FRP 映射端口

而不要直接:

公网IP:16081
公网IP:2333

尤其是 1Panel 这种管理后台,更不建议直接暴露原始端口。

另外建议:

  • FRP 使用长随机 Token
  • 1Panel 开启安全入口
  • 1Panel 开启强密码或二次认证
  • noVNC 本身设置 VNC 密码
  • 对管理后台增加访问限制
  • 宝塔开启 HTTPS
  • Cloudflare 使用 Full (strict)
  • 不对公网开放 16081 / 2333

二十五、最终效果

最终可以实现:

https://vnc.agblr.xyz
        ↓
Armbian noVNC
https://a.agblr.xyz
        ↓
Armbian 1Panel

如果 Cloudflare 还有:

xxx.com

也可以通过:

A / CNAME
+
Nginx server_name

让:

https://xxx.com

访问同一个 noVNC 服务。

整个方案不依赖第三方免费内网穿透节点,核心链路全部自己控制:

Armbian
↓
FRPC
↓
自己的公网 CentOS
↓
FRPS
↓
宝塔 Nginx
↓
自己的域名

相比共享式内网穿透,优势主要是:

节点自己控制
带宽自己控制
延迟更加可控
不限隧道数量
不限自定义域名
不限第三方免费流量配额
支持 HTTPS
支持 WebSocket
容易排错

对于 noVNC、1Panel、SSH Web Terminal 等需要长期稳定访问的服务,这种架构更加合适。

0

评论

博主关闭了所有页面的评论