远程控制NAS开关Samba

远程控制NAS开关Samba

之前通过一些方法,可以用手机控制家里的NAS,开始的时候手动开关Samba服务,后来写了一个小Shell脚本,可以设置定时关闭Samba,当时只考虑半个小时,后来呢可能其他需求,时间有变化,就在脚本后面加参数,控制关闭时间。后来有一天开车,无法用手机远程开Samba服务,就想到了NAS提供一个服务,外面调用就OK,然后手机用Siri语音远程调用。

修改Shell脚本

在原来的基础上,增加参数,可以调节时间。

g.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/bin/bash

if [ $# -gt 1 ]; then
echo 'Too many args' >&2
exit 1
fi

if [ $# == 0 ]; then
DEADTIME=$(date -d "+30 minutes" +'%H:%M')
fi

if [ $# == 1 ]; then
DEADTIME=$(date -d "+"$1" minutes" +'%H:%M')
fi

HOUR=$(echo $DEADTIME | cut -d ':' -f1)
MINUTE=$(echo $DEADTIME | cut -d ':' -f2)

sudo systemctl start smbd

crontab -l 2>/dev/null | head -n -1 > /tmp/crontemp
echo "$MINUTE $HOUR * * * sudo systemctl stop smbd" >> /tmp/crontemp
crontab /tmp/crontemp
rm /tmp/crontemp

内网穿透

现在访问家里的NAS有三个方式吧,一个是之前IPv6的方式,但是有的时候有些地方没有IPv6。另外一个方式就是Frp,VPS的一个端口访问NAS的SSH端口,另外一个方式就是NAS的SSH Remote Tunnel,再另外一个方式就是自己用Netty写了一个内网穿透的东东。

最终考虑的方式是Frp,简单,占用资源不多,可以SSH远程命令。

对外服务

有了内网穿透提供SSH,然后前面的Shell脚本,其实就比较简单了,ssh -p port -i id_rsa username@ip cmd,就可以直接调用NAS的Shell脚本了。

方式呢考虑了好几个:

  1. Nginx + Lua脚本,Nginx重新编译增加Lua支持,然后指定url运行脚本,os.execute('cmd'),Nginx增加Lua需要下一些东西, LuaJIT, ngx_devel_kit, ngx_lua, Nginx, lua-resty-core, lua-resty-lrucache,虽然本身Nginx是自己编译的,但是下这多东西,还是算了。
  2. PHP,嗯,最好的编程语言 :(,本身一个老的VPS上面架了个Wordpress,是有PHP的,但是为了一些安全考虑,php配置文件中已经禁用了shell调用,为了一个功能也懒得打开了。
  3. Java/Golang/C#/Python,写个小的Web服务,用Nginx反代,调用Shell脚本。Python资源比较大,C#/Java占用资源也比较大,就考虑用Golang写个简单的服务吧,直接调用Shell命令,后来查了下,可以连接SSH直接运行远程命令。

运行shell

main.go
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
func main() {
gin.SetMode(gin.ReleaseMode)
router := gin.Default()
router.GET("/tv/tv", openTV)
router.GET("/tv/tv/:min", openTV)

router.Run(":8888")
}

func openTV(c *gin.Context) {
minParam := c.Param("min")
x := int64(35)

if min, err := strconv.ParseInt(minParam, 10, 32); err == nil {
x = min
}

cmd := exec.Command("ssh", "-p", "10000", "-i", "/home/liangwu/.ssh/id_rsa", "liangwu@127.0.0.1", "~/g.sh", strconv.Itoa(int(x)))

result, err := cmd.Output()
if err != nil {
log.Println(err)
c.IndentedJSON(http.StatusInternalServerError, gin.H{"status": "wrong"})
return
}

resultString := string(result[:])
c.IndentedJSON(http.StatusOK, gin.H{"result": resultString})

连接SSH

Siri语音指令

Shortcuts新增指令,名字可以直接用Siri打开,比如Shortcuts命名为打开电视,直接用Hi Siri 打开电视就可以执行。

  • Ask for Input,’Ask for Number with How much time?
  • Text, ‘host/tv/tv/Provided Input
  • Safari Open URLs, ‘Open Text

OK,这样就可以Siri打开家里电视咯。。。