这两天偶然间发现了Caddy这样一个开箱即用,简洁却强大的服务器,也发现它也提供了在Termux上部署的选项。在Android设备上部署服务器的方法有很多,但是我认为使用Caddy可以大大简化流程,所以记录下来这个过程,供其他人参考。
值得注意的是,单纯使用Caddy部署网站的过程很简单,但是在这个过程中我采取了一系列的手段来提高可用性和简化流程,这部分我将会有所标注。

(可选)为Android设备刷入合适的系统

这步对于某些设备来说是必须的,特别是一些老旧设备,无法安装Termux(Termux现在最低要求是Android7.0),所以需要进行系统升级。除此之外,还有一些厂家的ROM相当冗杂,在占用设备资源的同时降低了设备稳定性,比如MIUI…也需要刷机。
刷机这部分我就不多说了,毕竟我也是按照其他人的教程一步一步来的,这里就推荐一个教程吧:
点击查看【bilibili】

教程是根据小米4来的,但是思路对于大部分设备来说应该是通用的。我也上一张刷好原生Android10后的效果图:

平心而论,体验好了很多。
还有一点需要注意的,在Android10之后,Android的Root管理变得更加严格,更加难获得Root权利,而Caddy的某些功能需要使用Root权利(但是基本功能仍然可以使用,在下面的文章中我会详细展开),如果你正在考虑刷机,请选择一个你有信心Root的版本。

安装Termux

Termux是一个用于在Android系统上实现最小Linux系统的终端模拟器,其内置了许多常用的Linux功能。一般来说,可以在应用商店直接搜索下载,或者通过电脑进行ADB安装,我在这里提供了F-Droid上的下载链接

(可选)为Termux启用SSH

虽然说直接在设备上进行操作也可以,但是触屏的效率的确比不上键盘,而且会占用更多的系统资源,所以说通过SSH连接设备也是有必要的。

安装OpenSSH

先执行以下命令:

1
2
apt update
apt install openssh

获得设备信息

此时在设备上已经安装好了OpenSSH,我们需要在PC上安装SSH连接工具,我这里使用的是[Xshell家庭教育版](https://www.xshell.com/zh/free-for-home-school/),Ubuntu用户可以使用内置的Remmina。

此时,再在Termux上执行以下命令来获得本机用户名:

1
2
$ whoami
u0_a103
然后,再执行以下命令获得设备的内网IP
1
2
3
4
5
6
$ ip addr | grep inet
inet 127.0.0.1/8 scope host lo
inet6 ::1/128 scope host
inet6 fe80::eca3:ceff:fe4c:1a38/64 scope link
inet 192.168.3.31/24 brd 192.168.3.255 scope global wlan0
inet6 fe80::5a44:98ff:fe41:297/64 scope link

192.168.3.31 即为我设备的内网地址,这个地址因人而异。

为设备指定密码

如果不为设备指定密码,我们就需要通过密钥来进行连接,相比之下更复杂。
在Termux中执行以下命令,然后隐式输入两次密码即可成功设置。

1
passwd

连接设备

然后我们在SSH连接工具中新建连接,填入上面获得的信息,在这里OpenSSH的默认端口是8022:

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
Connecting to 192.168.3.31:8022...
Connection established.
To escape to local shell, press 'Ctrl+Alt+]'.

WARNING! The remote SSH server rejected X11 forwarding request.

Welcome to Termux!

Wiki: https://wiki.termux.com
Community forum: https://termux.com/community
Gitter chat: https://gitter.im/termux/termux
IRC channel: #termux on freenode

Working with packages:

* Search packages: pkg search <query>
* Install a package: pkg install <package>
* Upgrade packages: pkg upgrade

Subscribing to additional repositories:

* Root: pkg install root-repo
* Unstable: pkg install unstable-repo
* X11: pkg install x11-repo

Report issues at https://termux.com/issues
连接成功。

此后,如果你重启了Termux,则需要你手动执行以下命令开启ssh:

1
shhd

安装Caddy并部署静态站点

注意,虽然按照接下来的教程你可以搭建一个简易的网站,但是会有很大的概率踩坑,当你发现无法进行下去的时候,请看章节末的补充提示。

安装Caddy

在Termux中运行以下指令:

1
pkg install caddy

创建网站

然后在Termux根目录下创建一个测试目录并进入:

1
mkdir test && cd test
接下来在此目录中创建一个Caddy的配置文件:[Caddyfile](https://caddyserver.com/docs/caddyfile-tutorial),更详细的信息可以在官网查看,我这里只作简单介绍:
1
2
3
4
//安装vim
pkg install vim
//创建Caddyfile,注意,这个文件没有拓展名
vim Caddyfile
在Caddyfile中填入以下内容来部署一个静态服务器(如果你不会使用vim,你也可以用其他的工具创建,比如说在Termux外部使用文本编辑器编辑Caddyfile):
1
2
3
localhost

file_server
简单的解释一下,第一行中的localhost代表了你指定的站点地址(Site's Address),而第二行则代表该站点所对应的是一个静态文件服务器。

强烈建议感兴趣的去阅读Caddy文档来更全面的了解Caddy的用法。

为网站添加内容

Caddy的file_server功能提供了很多选项:

1
2
3
4
5
6
7
8
9
file_server  [<matcher>]  [ browse ]  { 
root <path>
hide <files...>
index <filenames...>
browse [ <template_file> ]
precompressed <formats...>
status <status>
disable_canonical_uris
}

我们在上文并未指定额外的选项,所以说这是一个静态网站服务器,你需要像传统服务器那样组织你的目录结构,并包含一个index.html。
如果我们将Caddyfile改为如下的内容:

1
2
3
localhost

file_server browse

服务器则会在找不到index.html的情况下将网站根目录变为一个文件服务器:

对了,想要开启服务器,只需要在网站根目录下执行:

1
caddy run

(重要)解决空白响应页内容

还有很重要的一点,如果你调试和使用该服务器都是在你的Android设备上的话,那么将站点地址指定为localhost是没有问题的,但是当你试图从内网中的其他设备访问这个站点的时候,你仅仅会得到一个空白的响应页。这是因为虽然对于Caddy服务器来说,localhost和192.168.3.31(我的内网地址)是一样的,而事实上你也可以成功的连接到服务器,但是,由于你访问的192.168.3.31并不等同于指定的站点地址localhost,所以Caddy无法为你响应内容。如果你想要让你的网站在整个内网可用,请这样修改Caddyfile:

1
2
3
192.168.3.31

file_server
当然,你也需要将上面的IP地址更改为你自己设备的。

(重要)可能出现的低端口问题

某些Android系统版本或者相关ROM可能会限制打开低端口,所以Caddy可能无法正常在约定好的80或者443端口开启。这个问题有两个解决办法,一是刷入限制较少的系统(经测试,原生Android10可以正常开启),二是为站点指定一个比较大的端口:

1
2
3
192.168.3.31:8080

file_server

当然,此时如果你想访问你的站点,也需要加上相应的端口号。

(重要)可能出现的https问题

Caddy默认为网站提供https连接,并且会对本地站点进行自签,然而,当我在Android设备上按照默认配置启动服务器时,Caddy会报错:

1
ERROR	pki.ca.local	failed to install root certificate	{"error": "install is not supported on this system", "certificate_file": "storage:pki/authorities/local/root.crt"}


简单解释就是说Caddy未能成功安装根证书(在此系统上不支持),这个可能是因为缺少某种权限(虽然我用root权限执行,这个过程还是失败了),根据Github上的issue说,也有可能是Caddy本身的问题。看来还需要进一步去解决,在此之前,我们只能为站点指定使用http连接来避开这个问题,Caddyfile文件如下:

1
2
3
http://192.168.3.31

file_server
这样的话,就能成功开启服务了。

(可选)为站点设置内网穿透

如果你仅仅想在内网中使用这个服务器,那这一步是没有必要的,但是如果想在外部网络访问的话,就需要设置内网穿透,这里我使用的是免费的Ngrok。

下载并安装Ngrok

安装Ngrok并不难,最简单的办法是通过包管理安装Ngrok:

1
pkg install ngrok
但是这种方法也有可能失败,所以,除此之外我们也可以直接下载已经编译好的二进制文件,你可以在[这个页面](https://ngrok.com/download)下载并解压他。

注册Ngrok并获取Authtoken

在Ngrok官网注册并登陆后,你可以在后台查看或者复制为Ngrok指定密钥的命令,复制后在终端中执行:

开启Ngrok

进入Ngrok所在目录,并在终端中输入:

1
./ngrok http 80

这里的http参数以及80参数可以按照你的实际情况进行更改。
注:使用Ngrok进行内网穿透的时候我遇到了Ngrok无法连接服务器的问题,如果你也遇到了类似的问题,可以选择其它的内网穿透方式。

总结

在Termux出现之前,人们更多的是考虑如何在Android设备上高效的运行Linux虚拟机或者如何将Linux系统刷入移动设备,Termux出现之后,为Android系统带来了前所未有的可玩性。
与此同时,本文使用的CaddyServer并不像Nginx那样注重于高性能,而更在乎易用性,更加适合部署在Android设备上。我自己还是很看好其发展前景的。
比较可惜的是我手头并没有一个主流的Android设备,要不然的话或许可以把自己的私有云迁移到它上面?😂