cloudflared内网穿透

Cloudflared Zero Trust

Zero Trust是Cloudflare公司推出的一项企业级虚拟网关服务,官方对其介绍如下:

Cloudflare Zero Trust是一个安全框架,旨在通过验证和保护所有的网络访问(无论用户或地点)来保护组织免受网络威胁。该框架基于 “不信任任何人 “的原则,这意味着所有访问请求在被批准之前必须经过验证和授权。

Zero Trust “旨在提供一种全面的安全方法,涵盖一个组织的网络和基础设施的所有方面。这包括用户认证、设备安全、网络分段和应用安全。

Zero Trust的主要好处之一是它能够提供细化的访问控制,使企业能够根据用户角色和权限限制对敏感资源的访问。这可以通过最小化攻击面和限制任何潜在漏洞的影响来帮助防止数据泄露和其他安全事件。

Cloudflare Zero Trust是一项基于云的服务,可以很容易地与组织的现有安全基础设施集成。它的设计具有可扩展性和灵活性,允许企业定制框架,以满足其特定需求和要求。

(通过DeepL翻译)

本文仅使用其中的tunnel功能,对其余功能不做赘述

准备工作

  1. 一个域名(通过阿里云等购买然后解析到Cloudflare上)
  2. 一个Cloudflare账号
  3. 一台设备(本文使用的系统是centos 7
  4. 一张双币信用卡(到后面需要验证,但是可能也不需要,因为我第一次使用tunnel的时候要信用卡验证,但是等我第二次用的时候就不需要了)

一共有两种操作方式,一个网页版操作,一个是本地指令操作

下面所作的一切操作的前提就是上面的已经准备好了

在此说一下,除了http/https协议外,像是其他的tcp/ssh…这些协议是需要端对端的链接映射端口的

网页版

初始化

登录之后点击左边的Zero Trust

来到这个页面,点击Access->Tunnel

这里的xnj是我之前做的,所以忽略,之后点击页面的新建,就是哪个蓝色的按钮

这里是输入这个隧道的名称,随便输入就行,之后就到了这个页面,根据自己的系统选就行,我是Linux所以选那个企鹅,因为下面两个框,要是第一次使用的话就选左边的框,里面因为是要从GitHub上下载东西,但是GitHub在国内经常抽风,所以需要一个节点来加速


1
2
3
4
5
6
7
8
9
10
11
12
13
#原链接
curl -L --output cloudflared.rpm https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-x86_64.rpm &&

sudo yum localinstall -y cloudflared.rpm &&

sudo cloudflared service install eyJhIjoiNzQ0MTMwNW0IjoiNmM5ZDU0YzAtZDAyYS00MDJlLThlYjktZTdmMzg1YzRmkRnd0xUbGhOR1F0TjJKbU5tSTFPVGhsWTJFNCJ9

#新链接
curl -L --output cloudflared.rpm https://ghjs.ximuliunian.top/https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-x86_64.rpm &&

sudo yum localinstall -y cloudflared.rpm &&

sudo cloudflared service install eyJhIjoiNzQ0MTMwNW0IjoiNmM5ZDU0YzAtZDAyYS00MDJlLThlYjktZTdmMzg1YzRmkRnd0xUbGhOR1F0TjJKbU5tSTFPVGhsWTJFNCJ9

就是https://ghjs.ximuliunian.top这个链接,然后把链接复制到终端加速下载

看到这个就是代表安装好了,然后回到网页看看是否成功,如果在链接的下面看到有显示数据或者退出去隧道状态显示绿色就代表🆗了

然后滑倒下面,点击右下角的next

操作

这个是让你输入对应内容进行穿透,按照图片提示输入即可

在这里再次说一下,除了http/https协议外,像是其他的tcp/ssh…这些协议是需要端对端的链接映射端口的,这个稍后说

在里面填的映射端口,要是http/https协议的话是可以直接游览器访问的,这些就可以让家里不用的设备去用来做网站什么的,除了速度慢一点,其他一切都好

可以在一条隧道里面添加多条数据使用,但是毕竟是免费版的,所以会有条数限制具体就不再演示

指令版

下载

1
2
3
curl -L --output cloudflared.rpm https://ghjs.ximuliunian.top/https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-x86_64.rpm && 

sudo yum localinstall -y cloudflared.rpm

把这个复制到控制台上,然后运行开始下载,链接跟上面的一样,只不过这是优化后的链接和没有第三行绑定内容

软件默认安装到:/usr/local/bin目录下

身份认证

使用Argo Tunnel Client 需要使用者登录 Cloudflare 账号以进行授权

1
cloudflared tunnel login

出现上图内容之后复制其中的链接到本地游览器进行登录认证操作,成功之后就会出现下图

本地也会进行相应的操作如下图,大致意思就是登录成功,已经在 /root/.cloudflared/ 目录下生成了cert.pem一个文件,这个文件差不多就是类似于认证证书什么的,反正很重要

新建 Tunnel

1
2
3
4
#样品
cloudflared tunnel create [名字]
#例子 如我想创建一个名为 test 的Tunnel
cloudflared tunnel create test

运行之后就会就会在/root/.cloudflared/目录下生成一个隧道凭据(是json文件),同时还有隧道ID(就是json文件的名字),这个东西很重要,千万不能丢

配置DNS记录

有两种方法进行配置,第一种方法就是直接去网站里面进行配置,第二种就是指令配置

网站配置

进入到你的网站解析页面,新建一条记录就如下面这让

类型:CNAME

名称:随便填

目标:创建隧道的ID.cfargotunnel.com

其他默认就好点击保存就好了

指令配置

还是打开终端,然后按照下面的格式输入指令

1
cloudflared tunnel route dns [隧道的ID] [想要绑定的域名或二级域名]

出现下图情况就是绑定成功了

配置文件编写

参考:本地管理的隧道 ·Cloudflare 零信任文档

/root/.cloudflared/目录下创建一个名为config.yml的文件,使用vi命令进行创建和编写

vim 是一个兼容 vi 的文本编辑器,通常用来编辑纯文本。 vi 文件名 命令可以编辑一个文件,若文件名不存在则会新建

在目录下使用vi config.yml,进入页面后点击I键进入书写模式并写入以下内容,#后面的包括#可以不写

1
2
3
4
5
6
7
tunnel: 隧道ID
credentials-file: /root/.cloudflared/隧道ID.json

ingress:
- hostname: [CNAME 记录名称].[接入 CLoudflare 的域名] #域名,就是相面配置的DNS域名
service: hello_world #这里面就是本地映射的端口,这里写这个是为了判断是否配置成功
- service: http_status:404 #不管上面怎么设置,下面永远是这一条,否则就出错

这个可以配置多个,只需要配置相对应的DNS在上面多添加一条记录即可,格式如下

1
2
3
4
5
6
7
8
ingress:
- hostname: [CNAME 记录名称].[接入 CLoudflare 的域名]
service: http://localhost:80
- hostname: [CNAME 记录名称].[接入 CLoudflare 的域名]
service: tcp://0.0.0.0:25565
- hostname: [CNAME 记录名称].[接入 CLoudflare 的域名]
service: ssh://0.0.0.0:22
- service: http_status:404

写完之后点击键盘左上角的ESC键,然后输入:wq保存并退出,这样就会有config.yml文件了

执行 Tunnel

1
2
3
cloudflared tunnel --config [配置文件路径] run
#如果在 .cloudflared目录下,那么执行下面语句
cloudflared tunnel --config config.yml run

如果不指定配置文件路径,cloudflared 会默认读取 ~/.cloudflared/config.yml

别管报错的有多离谱,只要上面配置对了,那么基本上就没问题,报错那就多运行几次,直到运行到隧道为状态绿色为止

这就代表是成功了,访问一下你刚才绑定的域名,如果你用的是hello_world那么你访问的结果会是下图

但是还没完,还要把这个搞成Linux服务

服务

安装服务

1
cloudflared service install

他会在/etc/systemd/system目录下创建3个文件(cloudflared.service、cloudflared-update.service、cloudflared-update.timer),会在 /etc/cloudflared 目录下创建config.yml文件

安装好之后会有下图情况

大概意思就是,/root/.cloudflared/config.yml/etc/cloudflared/config.yml存在冲突,要么删除 /etc/cloudflared目录下的config.yml文件,要么运行一下 cloudflared --config /etc/cloudflared/config.yml service install这个指令(应该是用于区分作用)

此时他的服务默认路径不是咱在root下创建的文件,而是运行的etc下的文件

上面这个这个咱不用管,咱只需要把路径调试对即可,因为安装服务的时候在/etc/systemd/system目录下创建了三个文件,其中有一个cloudflared.service文件,用编译器打开它,在第8行左右的位置更改一下内容

1
2
3
4
5
6
#格式
ExecStart=/usr/bin/cloudflared --no-autoupdate --config config文件路径 tunnel run
#原内容
ExecStart=/usr/bin/cloudflared --no-autoupdate --config /etc/cloudflared/config.yml tunnel run
#新内容
ExecStart=/usr/bin/cloudflared --no-autoupdate --config /root/.cloudflared/config.yml tunnel run

然后就OK了,如果此时服务以运行,那么就进行重启服务即可,如遇到报错内容,根据内容进行输入即可

启动服务

1
2
3
4
5
6
7
8
#启动服务
systemctl start cloudflared

#查看服务状态(可选)
systemctl status cloudflared

#重启服务(更新后数据后重启一下)
systemctl restart cloudflared

查看是否OK

通过端对端的映射可以看到,ssh已经是映射成功了,其他协议也可以这样搞

Windows使用

在windows系统(以下简称win)中也需要内穿,比如测试程序、穿透某项服务等。在win中操作方式跟linux大差不差,首先需要下载相对应的软件在GitHub中有两种软件一种是后缀为 msi 的安装程序,还有一个是 exe 的程序,我使用的是exe程序。至于区别以下为GPT的答案

cloudflared-windows-amd64.msicloudflared-windows-amd64.exe 是两种不同的文件格式,通常用于在 Windows 操作系统上安装应用程序或工具。这两个文件的区别在于它们的安装方式和功能:

  1. cloudflared-windows-amd64.msi:
  • .msi 文件是 Windows Installer 包的文件扩展名,通常用于安装程序。当您双击运行一个 .msi 文件时,Windows Installer 将会启动安装向导,引导您完成安装过程。这种文件格式通常提供更多的安装选项和设置,例如选择安装路径、添加桌面快捷方式等。
  • cloudflared-windows-amd64.msi 文件可能是 Cloudflared 工具的安装程序,通过运行这个文件,您可以按照安装向导的指示在 Windows 系统上安装 Cloudflared 工具。
  1. cloudflared-windows-amd64.exe:
  • .exe 文件是 Windows 可执行文件的常见扩展名,它们通常是独立的可执行程序。当您运行一个 .exe 文件时,它会直接执行其中的程序代码,而无需通过安装向导。
  • cloudflared-windows-amd64.exe 文件可能是 Cloudflared 工具的独立可执行文件。通过运行这个文件,您可以直接启动 Cloudflared 工具,而无需进行安装过程。

因此,如果您想要安装 Cloudflared 工具并在系统中进行设置,您可以选择运行 .msi 文件以启动安装向导。如果您只是想要快速运行 Cloudflared 工具而不需安装,您可以选择运行 .exe 文件。

操作

首先穿透的时候不是使用网页版的,而是使用本地配置文件的方式进行(跟以上指令版很像),首先建议配一下环境变量(如果你知道如何操作的话不配也行),然后打开命令窗口输入以下命令进行授权操作

1
cloudflared login

完成授权之后会在 C:\Users\%USERNAME%\.cloudflared 目录中生成登录凭证,之后才可以进行后续的操作

创建隧道(<NAME> 处写上隧道名)

1
cloudflared tunnel create <NAME>

创建隧道完成还是会在 C:\Users\%USERNAME%\.cloudflared 目录下生成隧道的凭据是一个名是UUID的json文件

然后配置穿透需要的域名

1
cloudflared tunnel route dns <隧道ID> <域名>

隧道ID就是生成的UUID,域名是二级域名,建议使用泛解析,可以不需要重复的进行域名绑定操作如:*.xxx.com

然后编写配置文件,在你存放exe程序的文件夹中创建一个 config.yaml 文件,然后开始编辑内容,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 隧道的标识 - UUID
tunnel: 隧道的UUID
# 隧道的凭据
credentials-file: C:\Users\用户名\.cloudflared\隧道凭据.json
# 穿透的内容 - 可以有多个
ingress:
# 服务1
- hostname: fw1.xxx.top # 域名
service: http://localhost:8080 # 本机服务
# 服务2
- hostname: fw2.xxx.top
service: http://localhost:9527
# 默认错误404 - 一定要有这个 - 最后一个入口规则必须是与所有流量匹配的 catch-all 规则
- service: http_status:404

对上面的配置按照提示进行修改,在上面的服务中域名有fw1和fw2两个甚至可能更多,配置一个域名的泛解析之后会非常方便的进行穿透不需要一直进行创建DNS记录,但是也有一个弊端就是如果二级域名重复会导致冲突

在编写这种 yaml 格式的文件需要注意缩进

启用穿透

创建一个cmd文件如:开启穿透.cmd,对文件继续编辑,输入以下内容

1
cloudflared --config=D:\cloudflared\config.yaml tunnel run

其中 --config= 后面的内容写上配置文件的全路径然后保存,最后双击文件即可开始穿透

速度

在DNS中有泛解析的一条数据,这条数据默认是开启DNS代理的,这个建议不要关,因为关闭的话链接超时的概率会非常大,这是开启的情况下进行 ping 10次的速度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
正在 Ping xxx.ximuliunian.top [172.67.178.240] 具有 32 字节的数据:
来自 172.67.178.240 的回复: 字节=32 时间=193ms TTL=1
来自 172.67.178.240 的回复: 字节=32 时间=209ms TTL=1
来自 172.67.178.240 的回复: 字节=32 时间=191ms TTL=1
来自 172.67.178.240 的回复: 字节=32 时间=189ms TTL=1
来自 172.67.178.240 的回复: 字节=32 时间=192ms TTL=1
来自 172.67.178.240 的回复: 字节=32 时间=186ms TTL=1
来自 172.67.178.240 的回复: 字节=32 时间=185ms TTL=1
来自 172.67.178.240 的回复: 字节=32 时间=185ms TTL=1
来自 172.67.178.240 的回复: 字节=32 时间=193ms TTL=1
来自 172.67.178.240 的回复: 字节=32 时间=197ms TTL=1

172.67.178.240 的 Ping 统计信息:
数据包: 已发送 = 10,已接收 = 10,丢失 = 0 (0% 丢失),
往返行程的估计时间(以毫秒为单位):
最短 = 185ms,最长 = 209ms,平均 = 192ms

常用指令

创建隧道

1
cloudflared.exe tunnel create <tunnel_name>

通过此命令可以创建一个新的隧道,<tunnel_name> 是您为隧道指定的名称。

启动隧道

1
cloudflared.exe tunnel run <tunnel_name>

使用此命令可以启动指定名称的隧道。

停止隧道

1
cloudflared.exe tunnel stop <tunnel_name>

通过此命令可以停止运行中的隧道。

删除隧道

1
cloudflared.exe tunnel delete <tunnel_name>

使用此命令可以删除指定的隧道。

列出隧道

1
cloudflared.exe tunnel list

该命令可以列出所有已创建的隧道。

查看隧道状态

1
cloudflared.exe tunnel status <tunnel_name>

通过此命令可以查看特定隧道的状态信息。

特殊

像是 tcp/rdp/ssh/smb 这一类的协议,是需要端对端的支持,什么意思呢,就是你是对Linux进行的内网穿透,你想要在Windows上进行ssh或者tcp的使用就需要在Windows上面下载一个cloudflared软件供使用,找到适合的版本下载

下载链接:https://github.com/cloudflare/cloudflared/releases

然后在cloudflared软件路径上进行cmd,运行cloudflared -v看看是否能正常输出版本号,能的话就可以对其及进行操作了

比如我内穿了22端口到网址上那么就要在本地进行端口映射

还是在然后在cloudflared软件路径上进行cmd,输入以下内容

1
2
3
4
#样品
cloudflared access 协议 --hostname 网址 --url 127.0.0.1:端口
#例子
cloudflared access ssh --hostname test.ximuliunian.top --url 127.0.0.1:9527

出现下图中则代表把网址映射到本地的9527端口,因为映射的是Linux的ssh远程,所以可以通过ssh软件尝试连接

可以看到,在本地的9527已经被映射到本地了,并且也可以被访问,

同理,其他特殊协议也是这样的,就如我的世界服务器,在Linux上面开设服务器在Linux的25565端口正常开放,通过内网穿透映射到网址上,在通过上面这一串指令映射到本地,就可以进行连接

脚本

但是他要一直运行着那个黑窗口才能正常进行本地映射,那有没有什么方法可以没有这个黑窗口但是也能保持映射状态呢?

YOU!!!

通过我的绞尽脑汁的思考,突然灵光一现,Windows服务这个词出现在了我的脑海中,既然服务实在后台开着呢,那我是不是也可以进行保持映射状态呢,想到这里我就去试了一试,不出我所料,果然可以,然后通过着进行了c语言的脚本编写最终写完了

注意事项

可以把下载的软件和cloudflared软件这两放在一个文件夹里面

使用软件有一个前提,那就是要使用管理员的方式打开文件,否则无法打开(可以右键软件 -> 点击属性 -> 点击上面的兼容性一栏 -> 勾选以管理员身份运行此程序)

要把cloudflared软件配置到环境变量里面(右键此电脑 -> 属性 -> 高级系统设置 -> 环境变量 -> 系统变量 -> 在里面找到Path这条数据进入)

然后把cloudflared软件的路径复制到上面去(比如文件夹A里面就有cloudflared软件,那么从文件夹A开始包括A往上到盘符的路径复制下来),然后点击环境变量里面的新建,把路径复制到上面去

如何判断环境变量是否配置成功了,在任何地方cmd然后输入cloudflared -v都可以输出信息那么就是配置成功了

使用软件(我自己写的)会产生一个文件config这个文件里面存放的是服务的信息,万万不可删除,有时也会有一个temp的文件出现,这个文件也不要删,切记!切记!切记!!!

下载

点击下载

源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <stdbool.h>

void adds();

void removes();

int view();

void qidong();

void guanbi();

bool IsProcessRunAsAdmin() {
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
PSID AdministratorsGroup;
BOOL b = AllocateAndInitializeSid(
&NtAuthority,
2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&AdministratorsGroup);
if (b) {
CheckTokenMembership(NULL, AdministratorsGroup, &b);
FreeSid(AdministratorsGroup);
}
return b == TRUE;
}


int main() {
if (!IsProcessRunAsAdmin()) {
printf("请以管理员身份打开");
Sleep(3000);
return 0;
}
system("title 曦暮流年 - 端口映射");
printf("\t##########################\n");
printf("\t# #\n");
printf("\t# 曦 暮 流 年 #\n");
printf("\t# 端 口 映 射 #\n");
printf("\t# #\n");
printf("\t##########################\n\n\n");
while (1) {
printf("\t1. 增加服务\n");
printf("\t2. 删除服务\n");
printf("\t3. 查看服务\n");
printf("\t4. 启用服务\n");
printf("\t5. 关闭服务\n");
printf("\t0. 退出\n\n");

printf("\t作者博客:www.ximuliunian.top\n\n");

int a;
printf("\t请输入数字编号:");
scanf("%d", &a);

switch (a) {
case 1:
adds();
break;
case 2:
removes();
break;
case 3:
view();
break;
case 4:
qidong();
break;
case 5:
guanbi();
break;

case 0:
printf("\t感谢使用 再见!");
Sleep(2000);
exit(0);

default:
system("CLS");
printf("\t输入的不是应有的编号哦~~~\n");
printf("\t请重新输入\n\n");
}
}
}

void adds() {
FILE *fp = fopen("config", "a+");
if (fp == NULL) return;
char ServiceName[300];
char access[50];
char hostname[200];
char url[50];
printf("\n\n\t请输入服务名字:");
scanf("%s", ServiceName);
char tempName[300] = "AAA_XMLN_";
strcat(tempName, ServiceName);
strcpy( ServiceName,tempName);
printf("\t请输入类型(tcp/rdp/ssh/smb):");
scanf("%s", access);
printf("\t请输入映射网址:");
scanf("%s", hostname);
printf("\t请输入被映射的端口(如:25565)127.0.0.1:");
scanf("%s", url);
fprintf(fp, "\n%s %s %s %s", ServiceName, access, hostname, url);

char sc[1024] = "sc create ";
char qd[100] = "net start ";
strcat(qd, ServiceName);
strcat(sc, ServiceName);
strcat(sc, " binPath= \"cmd.exe /c cloudflared access ");
strcat(sc, access);
strcat(sc, " --hostname ");
strcat(sc, hostname);
strcat(sc, " --url 127.0.0.1:");
strcat(sc, url);
strcat(sc, "\" start= auto");
system(sc);
system(qd);
fclose(fp);
}

void removes() {
int j = view();
int a;
char name[100];
printf("\t请输入删除序号:");
scanf("%d", &a);
FILE *ffp = fopen("config", "r");
FILE *fp = fopen("temp", "w");
if (fp == NULL || ffp == NULL || a <= 0 || a > j) return;
char sc[] = "sc delete ";
for (int i = 1; !feof(ffp); ++i) {
char f[4][100];
fscanf(ffp, "%s %s %s %s", f[0], f[1], f[2], f[3]);
if (i == a) {
strcpy(name, f[0]);
continue;
}
fprintf(fp, "\n%s %s %s %s", f[0], f[1], f[2], f[3]);
}
strcat(sc, name);
system(sc);
fclose(fp);
fclose(ffp);
system("del config");
system("ren temp config");
}

int view() {
system("CLS");
FILE *fp = fopen("config", "r");
if (fp == NULL) return -1;
int j = 1;
printf("\n\n\t序号\t服务名字\t类型\t映射网址\t被映射端口\n\n");
while (!feof(fp)) {
char a[4][100];
fscanf(fp, "%s %s %s %s", a[0], a[1], a[2], a[3]);
printf("\t%d\t", j++);
for (int i = 0; i < 4; ++i) {
printf("%s\t", a[i]);
}
printf("\n\n");
}
fclose(fp);
return j;
}

void kg(int a, int j, char sc[]);

void qidong() {
int j = view();
int a;
printf("\t请输入序号:");
scanf("%d", &a);
kg(a, j, "net start ");
}

void guanbi() {
int j = view();
int a;
printf("\t请输入序号:");
scanf("%d", &a);
kg(a, j, "net stop ");
}

void kg(int a, int j, char sc[]) {
char name[100];
char sp[100];
strcpy(sp, sc);
FILE *ffp = fopen("config", "r");
if (ffp == NULL || a <= 0 || a > j) return;
for (int i = 1; !feof(ffp); ++i) {
char f[5][100];
fscanf(ffp, "%s %s %s %s %s", f[0], f[1], f[2], f[3], f[4]);
if (i == a) {
strcpy(name, f[0]);
break;
}
}
strcat(sp, name);
system(sp);
fclose(ffp);
}