我是如何低成本建立RapidDNS.io网站的

大家好!我是BaCde,2020年3月我着手开发RapidDNS这个网站,并于2020年4月1日正式上线。

RapidDNS.io是一个在线域名查询和IP反向查询的网站。有超过25亿条记录,支持5种(A,AAAA,CNAME,MX,CERT)数据类型。到目前为止,网站全球Alexa排名15万左右并累计提供超过1亿次查询。现每月网站流量超过1TB。除此之外网站也被加入到Amass,OneForAll,theHarvester,Sudomy,subfinder,ksubdomain等众多知名开源项目中。

接下来我就跟大家分享建设这个网站的过程。

产生想法

2020年在做子域名收集的开发时,想起了Rapid7的DNS数据。经过对其进行分析后,确认是我需要的内容。于是便有了做一个在线的网站的想法,即方便自己同时又可以方便其他有需要的人。

有了这个想法后就开始计划目标,确定只做子域名查询和IP地址反查。其实在开发时,想自己跑数据,但是资源有限。就决定先以Rapid7的DNS数据来尝试。后续也可根据具体情况在增加功能。

面临的问题

开始实现之前要考虑如何以最低的成本实现最好的效果。最好的效果即在多人同时访问时保证查询速度和系统稳定。因为这将直接决定采用什么样的架构来实现。

先来分析下建设网站需要的东西。包括一个域名和至少一台服务器,用来存放web和数据。数据存储的空间至少要300gb,cpu至少双核,内存至少4g。这是没有增量和保存历史记录的情况。到各家云厂商,idc机房,根据这个配置对比了其价格,最低的服务器成本也要5000块一年(仅是数据存储)。

因为打算做免费网站,这样的成本超出了我的预期,而且也可能性能不够。对于这个数据,国外已经有几篇数据运用的文章。其实现的思路有:1. 采用aws的Athena实现,2. 开源的DNSGrep,包括RapidDNS上线后采用mongodb实现的开源项目等。因为大多数围绕的是子域名查询,没有IP地址反查功能。而且Athena将随着用户数量增加,其费用也将非常恐怖,更适合自用。说了这么多,主要的问题说白了就是穷。

另外一个省钱的思路就是从已有资源来想办法,这时想到了跟随我多年联想的笔记本电脑,它已经吃灰好久了,这是一个可利用的资源。这样只需要再买一个web服务器就可以了。根据之前调查的价格,这样的服务器一年大概需要不到2000块。

但是这就产生了另外一个问题,家里的网络是光纤,没有固定ip地址,而且之前测试发现外网ip是无法直接访问的,映射端口是不行的。做端口转发?这个的性能没测试过,无法保证,也不打算采用。当然这里我想到了一个解决办法,在下面的内容中会讲到。

解决方案

经过上面的考虑,最终我采用下面的结构。后来经过线上的运行情况,稳定性和查询速度还在接受的范围内。后续也可以增加worker和消息队列来支持其他方式的数据增加。

本地服务器就是我的一台笔记本电脑,其配置是3代i7,8G内存。1.2TB的固态硬盘(1TB+250TB两块组成)。数据存储与查询使用的是elasticsearch,前面加了一层nginx,并配置了认证。

外部服务器是一台云主机,配置好为双核4G内存。包括nginx反向代理和Flask做的web查询界面。 外面又加了一层CDN。上面没有公网IP的问题,取了个巧,因为现在家里的网络都支持IPv6,所以外部服务器直接使用IPv6地址直连家里的笔记本电脑。

这里说点额外的,对于IPv6地址是可以直接连接的,不需要做映射。一般我们家里的电脑会分配多个IPv6地址,有至少一个临时(temporary,我们连接其他电脑时使用)的地址和secured的。一般我们可以设置一个固定的即可。这里大家还是注意点,避免泄漏IPv6地址。之前看一篇公众号文章,发现对目标的IPv4地址打码了,却没有对IPv6地址打码,这个挺危险的。

以上这套结构的成本为域名450元,cdn服务器免费的,服务器每月费用20美元(差不多140元),电费每月大概60元。前期投入买了一块三星的SSD,成本1000元。截止目前为止,共投入450+2400+1000=3850元。后续维持现状基本是服务器加域名成本,一年2850元。

编码

需要的一些基础知识:

  1. html+javascript+css基础
  2. python+flask基础
  3. elasticsearch基础

其实想好了方案,而且本身也不复杂,具体编码就相对简单了许多。比如查询界面的开发,我直接找了一套现成的模版,改改样式就可以了。后端flask边看文档边开发就可以了,没啥好说的。唯一要说一下的是这里flask使用了协程,其查询效果好了很多。当然后面跟insight-labs的A牛沟通过可以换bjoern,据说效果很好,不过这个我没测试,感兴趣的可以试试看,看完也可以分享出来让我学习学习。

主要的还是在Elasticsearch这里,这里选择他主要因为我比较熟悉,而且有IP字段类型,做IP段查询时非常方便。这里换乘其他的如mongodb、mysql等也可以。mysql使用myisam,加上Partition问题也不大,Insight-labs的QQ群数据查询就是成功案例。大家可以选择自己擅长的。

后来有朋友过来交流查询速度问题,说他那边的查询速度没我的快。其实主要我这边做了一些优化处理。我在导入数据时,对域名处理,将根域名单独存放一个字段,剩下的部分单独放一个字段。因为不需要模糊匹配,查询速度就会非常快,同时存储空间也可以节省几十G。当然,这牺牲掉了模糊搜索的功能。具体字段可以看下图:

创建mapping:

{
  "mappings": {
    "domain": {
      "properties": {
        "name": {
          "type": "text"

        },
        "type": {
          "type": "keyword"

        },
        "value": {
          "type": "ip"

        },
        "domain": {
          "type": "keyword"

        }
      }
    }
  }
}

最关键的其实是导入程序,也是投入时间最多的,因为数据量比较多。单纯使用bulk速度很慢。使用SSD速度会提高几倍。但是依然达不到预期,因为会出现es内存耗尽,队列太多等各种异常,比如导入到8亿多数据时报错。也尝试通过迭代的方式来实现高性能文件读取,但是最后主要的根源还是在es和字符串的处理上。最后采用多进程方式。elasticsearch设置不刷新,0副本,并调整es的queue,线程,最大内存等参数。这个需要根据自己机器配置去进行调整。通过实际使用一天导入大概10亿条记录,当然还是有优化空间的。

修改index设置的方法:

{
  "index": {
    "refresh_interval": -1,
    "number_of_replicas": 0
  }
}

导入完成后在修改回去即可。

以上elasticsearch使用的是6.7.1版本。其他版本可能会有差异,根据实际情况调整即可。

总结

其实总体来说,本文技术上没啥复杂度,实现起来也相对简单。我觉得有点像以前革命时期八路军的风格(完了往自己脸上贴金了,勿喷),在有限的条件下来尽可能实现自己想要的效果。

希望本文对你有所帮助,对于上述内容有任何疑问,可以给我发送消息一起交流。

最后,RapidDNS已经一周年,这一年家人和同事的支持,同学的帮助,以及国内外朋友的称赞和鼓励,才让我坚持维护着网站运行。感谢在网站运行中大家提来的建议和反馈!感谢所有使用RapidDNS的人!感谢你们让RapidDNS更好。
所以,RapidDNS现有查询功能将一直免费开放下去,同时新的一年我也会增加新的功能,也欢迎大家发来你们的建议和想法。

大家也可以关注公众账号,获取最新的网站功能、使用技巧等内容。

The End