分类 网络

我的家庭AIO服务器方案

发布于
分类 网络

618期间给家里换了个雷鸟的电视,想着给小孩看纪录片用。既然播放设备有了那还得有个纪录片存储的设备,所以就本着够用就好的原则在闲鱼捡了套垃圾DIY了一台飞牛NAS,硬件配置如下

  • CPU:NAS神U 奔腾G4560
  • 主板:梅捷H110M
  • 散热器:卖家送的垃圾散热器
  • 电源:卖家送的垃圾电源180W
  • 内存:多多20买的杂牌8G
  • 机箱:多多20多买的铁皮机箱
  • 网卡:主板自带的为百兆网卡,自己加了块之前买的2.5G网卡,型号为8125B

之所以要选G4560这颗U呢,首先因为它便宜,才10元左右,另外功耗比较低,核显为HD 610,支持硬解的格式比较多

image.png

结构

image.png

远程开机

因为飞牛NAS上没有部署需要24h跑的作业,仅仅用来作为下载机下载一些电影或者资源和备份相册,所以平时都会关机,只有要使用时才会开机。但是又有需要在外远程开机的诉求,因此我在家里找到了一台闲置多年的荣耀手机,安装了termux,然后在上面部署了一个我用Go写的IOT程序,这个程序会与巴法云建立连接,监听来自巴法云的开机消息,收到开机消息后会向内网的飞牛主机发送网络唤醒魔术包(即WOL)来唤醒飞牛主机。

我在我的阿里云服务器上部署了一个web服务,在外可以随时通过web服务向巴法云发送开机消息,这样就达到了在外远程开机的效果。

公网IP获取

开机后就要想办法能够连接到家里的NAS主机。在没有公网IP的情况下只能通过类似于frp这样的工具做内网穿透,这种方案的原理是通过一个公网的服务器进行转发,效率不高。

幸运的是我家联通宽带有公网IP,只需要将现有的通过光猫拨号修改为路由器拨号即可。不过这需要你拿到光猫的超管密码,具体的获取方式我是参考的这篇博客:《中国联通光猫G-140W-UG超管密码获取》,有需要的同学可以参考自取。拿到光猫超管密码后进到光猫后台和路由器后台一通配置即可,具体的配置步骤网上有很多这里我就不过多赘述了。

家宽的IP是会动态变化的,所以我们需要通过DDNS来将一个固定的域名解析到动态的公网IP上。恰好我的域名采购自腾讯云,使用的是DNSPOD作为域名解析服务商,而我的中兴路由器支持DNSPOD作为DDNS的服务商,所以DDNS的配置对于我来说还是非常简单方便的。

wireguard回家

拿到公网IP后我们就有了连接到家里NAS的基础条件,那么要连接到家里NAS一个最直接的方案就是暴露出飞牛的端口号到公网,但是这个方案有两个风险:

  • 安全问题,暴露到公网意味都任何人都能访问我们的NAS,纯靠账号密码进行安全验证的方式对于我来说还是有些大胆了
  • 从一些社区和论坛得知某些地域运营商不允许架设web server,发现后会进行封禁

我采用的方案是在NAS中通过docker部署wireguard来架设VPN服务,通过VPN达到“回家”的目的。我实际使用的是github.com/wg-easy/wg-easy这个项目来架设的wireguard服务,部署简单管理也非常简单。

监控

作为一个后端工程师,不能实时观测到服务器的状态始终让人感觉到不太可靠,虽然飞牛APP上提供了一些监控指标,但是没有提供web界面。因此我在NAS上通过docker部署了一个galance服务,然后将其web监控页面通过iframe嵌套到了我用AI帮我做的一个AIO导航页中,整体效果如下:

image.png

...

阅读全文 »

网络编程中的tips

发布于
分类 网络

Connection reset by peer

网络编程中某一端可能会产生Connection reset by peer的报错,这是因为收到了对端发送的RST包。RST包是在tcp异常关闭时发出的,产生的情形很多。

我在写cat-agent 也遇到了这个报错,经排查发现是客户端发送数据后没有读取服务端的响应而直接关闭了连接(之所以不读取就关闭是因为客户端为提高发送效率不care服务端返回,后来为避免大量的RST包选择服务端不回包来解决)

EPOLL_CLOEXEC

epoll_create1() flags中有个EPOLL_CLOEXEC,类似的还有open()函数的O_CLOEXEC,它们的用处在于:当父进程fork出子进程之后,子进程会继承父进程的文件描述符,当子进程执行exec系统调用之后保存文件描述符的变量就不存在了,这些继承过来的文件描述符将无法关闭。

xxx_CLOEXEC选项就可以标识当子进程执行exec系统调用之后就内核自动关闭继承过来的文件描述符。

syscall.Forklock

在go标准库和其他一些网络库创建socket通常会有如下的代码:

syscall.ForkLock.RLock()
s, err = socketFunc(family, sotype, proto)
if err == nil {
	syscall.CloseOnExec(s)
}
syscall.ForkLock.RUnlock()

syscall.CloseOnExec(s)与上一节的xxx_CLOEXEC选项作用的相同的。这里ForkLock的作用是保证fork操作时socket的创建与设置CloseOnExec原子性。

持续更新中

...

阅读全文 »