Published on

自动更新服务端口

Authors

该日志中很多表述不够严谨准确,待更新。

需求

在服务器上搭建了科学上网工具后,发现用一段时间,端口就会被封,无法继续使用。

现在需要写一个自动化脚本,封禁后自动切换端口。

思路

  1. 检测当前端口是否被封。
  2. 在配置文件中切换端口。
  3. 重新启动 nginx 服务,并将链接复制到 ftp 上。

步骤

1. 获取当前公网 ip

通过ifconfig无法正常获取本机公网 ip,ip.sb提供相关接口。

使用curl ip.sb以纯文本形式获取公网 ip。

ip.sb API

2. 获取当前使用的端口

一种方案思路是在本地保存一个using_port文件,文件内容是当前正在使用的端口,每次修改端口后更新该文件。

另一种方案思路是直接在配置文件中寻找端口号。

最简单的方法,按行列搜索。例如端口号在$conf文件的第9行第2列,可用如下命令获取:

cat $conf | sed -n '9p' | awk '{print $2}'

cat $conf命令读取$conf文件并将内容通过管道输送给sed命令,sed -n '9p'命令抽取第9行输出给awk命令,awk '{print $2}'输出第2列数据。

sed命令和awk命令都是强大的文本分析工具,后面替换端口号时还会用到sed命令。在搜索数据时,sed通常以行为单位,awk通常以列为单位。

上面这个方法的缺点是,如果$conf文件中增删了行,可能导致执行结果错误。可以选择使用正则匹配进行更严谨的搜索。

cat $conf | sed -n '1,//{/listen.*ssl http2/p}' | awk '{print $2}'

该命令按listen.*ssl http2正则匹配搜索行,1,表明从第一行开始搜索,输出找到的第一个匹配项。

3. 查看当前端口是否开放

使用nc命令,全称netcat,网络工具中的瑞士军刀。

最简单的用法:nc -z -w 3 $Domain $port,其中-z是指扫描端口时不发送其他数据,-w设定超时时长,大部分开放的端口扫描在 2 秒内就会出结果,这里设置超时时长为 3 秒。

这条命令执行后,如果结果为 0,表明端口开放,如果为 1,表明端口未开放。

4. 获取新的端口

在防火墙配置中开放了一批连续的端口号,一个端口被封禁后,直接使用下一个端口。

shell 中变量加一的方法有以下几种:

a=$(($a+1))
a=$[$a+1]
a=`expr $a + 1`
let a++
let a+=1
((a++))

5. 替换端口号

使用sed命令进行替换

sed -i "s/$port/$next_port/g" $conf,该命令将$conf中所有的$port替换为$next_port

6. 保存订阅链接

将链接结果输出到 ftp 文件中,以供订阅。ftp 搭建及 vmess 订阅参考该链接

7. 定时启动

可以在/etc/crontab文件中注册定时任务,这些任务同时也会开机自动启动(满足设定条件的情况下)。

Crontab 表达式规则:
*    *    *    *    *
-    -    -    -    -
|    |    |    |    |
|    |    |    |    +----- 星期中星期几 (0 - 6) (星期天 为0)
|    |    |    +---------- 月份 (1 - 12)
|    |    +--------------- 一个月中的第几天 (1 - 31)
|    +-------------------- 小时 (0 - 23)
+------------------------- 分钟 (0 - 59)

Crontab 在线验证

设置脚本每 10 分钟自动执行一次:

/10 * * * * root bin/sh /home/user/auto_run.sh

最终代码

#!/bin/sh
# 设置你自己的域名或IP
Domain="Your Domain or IP"
# nginx对应的配置文件路径
conf="/etc/nginx/conf.d/"$Domain".conf"
# 根据自己实际情况设定端口提取规则
port=$(cat $conf | sed -n '1,//{/listen.*ssl http2/p}' | awk '{print $2}')

# 检测端口是否可以访问
nc -z $Domain $port -w 3
if [ $? -eq 0 ]; then
		# 正常访问,直接退出
        exit
fi
# 不能访问,准备更新端口号
echo $(date): $Domain:$port NOT reachable.
# 下一端口号
next_port=`expr $port + 1`
# 替换配置文件中的端口号
sed -i "s/$port/$next_port/g" $conf
echo $(date): replace $conf, $port -\> $next_port.
# 重新启动nginx和v2ray服务
systemctl restart nginx
systemctl restart v2ray
systemctl status nginx
systemctl status v2ray

# 生成链接,并写入ftp文件
./v2ray_info.sh

echo ============================================================