nx54的ipv6配置nas,内网穿透访问,nxginx、DDNS都在这里

前言

上一篇说到nx54路由器如何在官方防火墙上加一个自己主机允许访问的规则,在不关闭防火墙的情况下,还能走ipv6访问到内网设备,里面有提到ipv6地址变化的问题。这篇主要说说ipv6变化后如果通知,以及一部分nginx配置心得。

ip变化通知,同时更新路由防火墙规则

注意以下所说的ip都是指ipv6,因为ipv4内网地址可以直接和mac地址绑定,不用通知你。

我发现新固件在重启设备后,ip也不会变了,这算是一个好事吧,也不用经常更新ip地址。不过,以防正需用的时候ip地址变化。我使用的是python脚本,当检测到ip变化,就向我的邮箱发送一封email。(你也可以直接做DDNS,自己写api调用脚本或者ddns-go)。有几点要求:

  1. 你的邮箱开通smtp,smtp是一个用于发邮件的,一般在邮箱的设置页。
  2. 你的路由已经常开telnet,参考之前的文章,我因为找到了常开方式,直接常开了。
    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
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    # coding=utf-8

    import socket
    import smtplib
    import subprocess
    import os
    import telnetlib
    import time
    from email.mime.text import MIMEText
    from email.mime.multipart import MIMEMultipart

    # Telnet 连接信息
    HOST = "192.168.124.1" # 路由的ip
    PORT = 15000
    PASSWORD = "password" # 替换为实际密码

    # 设置发件人和收件人信息
    sender_email = '发件邮箱'
    password = 'smtp password' # 一般都有SMTP应用专用密码
    # 设置SMTP服务器地址和端口 我使用的是126,qq和网易都支持SSL,能避免密码明文传输
    smtp_server = 'smtp.126.com'
    smtp_port = 465 # 通常是587用于TLS或465用于SSL SMTP默认是25,但是25不加密,我们使用SSL,网易支持SSL
    receiver_email = '接收ip的邮箱'

    # 创建一个socket对象 主要是为了获取主机名,其实没什么用
    sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)

    save_ip = ''

    def save_ip_string_to_file(ip_string, filename="ip_string.txt"):
    with open(filename, "w") as file:
    file.write(ip_string)

    def check_ip_string_in_file(ip_string, filename="ip_string.txt"):
    if not os.path.exists(filename):
    return False
    else :
    with open(filename, "r") as file:
    file_content = file.read()
    return file_content == ip_string

    def get_host_name():
    # 获取主机名
    host_name = socket.gethostname()
    return host_name

    def get_ipv6_addresses():
    # 执行ip -6 addr命令获取IPv6地址信息
    result = subprocess.run(['ip', '-6', 'addr'], capture_output=True, text=True)
    #result = subprocess.run(['ip', '-6', 'addr'], stdout=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True) #python 3.6
    if result.returncode != 0:
    print("Error executing ip command")
    return []

    # 解析输出以获取IPv6地址
    lines = result.stdout.split('\n')
    ipv6_addresses = []
    for line in lines:
    if 'inet6' in line and 'dynamic mngtmpaddr noprefixroute' in line and ' deprecated ' not in line:
    # 查找inet6行中的IPv6地址
    address = line.split('inet6 ')[1].split('/')[0].strip()
    if address != '::1': # 忽略本地回环地址
    ipv6_addresses.append(address)
    # if ipv6_addresses.count() > 5 :
    # break;

    return ipv6_addresses

    def send_email(title, content) :
    # 创建邮件对象
    msg = MIMEMultipart()
    msg['From'] = sender_email
    msg['To'] = receiver_email
    msg['Subject'] = title

    # 添加邮件正文
    body = content
    msg.attach(MIMEText(body, 'plain'))

    # 创建SMTP对象并发送邮件
    with smtplib.SMTP_SSL(smtp_server, smtp_port) as server:
    #server.starttls() # 启动TLS加密
    server.login(sender_email, password) # 登录邮箱
    text = msg.as_string() # 将邮件对象转换为字符串
    server.sendmail(sender_email, receiver_email, text) # 发送邮件
    server.quit() # 关闭连接

    # print("邮件发送成功!")

    def change_ip6tables(ip6_addr):
    try:
    # 连接到目标主机
    tn = telnetlib.Telnet(HOST, 15000)
    print(f"Connected to {HOST}")

    # 等待并输入密码
    #tn.read_until(b"Password: ")
    time.sleep(3)
    tn.write(PASSWORD.encode('ascii') + b"\n")
    print("Password entered")

    # 执行 debugshell 命令
    tn.write(b"debugshell\n")
    print("Entered debugshell")

    # 执行 ip6tables -F forwarding_rule 命令
    time.sleep(2)
    tn.write(b"ip6tables -F forwarding_rule\n")
    print("Flushed forwarding_rule")

    # 执行 ip6tables -A forwarding_rule -d device_ipv6 -j ACCEPT 命令
    time.sleep(2)
    add_rule_command = f"ip6tables -A forwarding_rule -d {ip6_addr} -j ACCEPT\n"
    tn.write(add_rule_command.encode('ascii'))
    print(f"Added ACCEPT rule for {ip6_addr}")

    # 读取命令输出
    time.sleep(2)
    output = tn.read_very_eager().decode('ascii')
    #print("Command output:\n", output)

    # 关闭连接
    tn.write(b"exit\n")
    tn.close()
    print("Connection closed")

    except Exception as e:
    print(f"Error: {e}")

    def main():
    host_name = get_host_name()
    # 获取并打印IPv6地址
    ipv6_addrs = get_ipv6_addresses()
    result = '\n'.join(ipv6_addrs)

    print(f"IPv6地址: {result}")
    if not check_ip_string_in_file(result) :
    save_ip_string_to_file(result)
    send_email(host_name + ' ip ',result)
    change_ip6tables(result)
    if __name__ == "__main__":
    main()

    简单说一下上面的逻辑,获取ip地址,当前目录会保存一个ip_string.txt,用来保存上一次获取的ip,如果不一致,就发送email,更新路由防火墙规则,同时保存新ip。获取ip其实是执行了一条 ip -6 addr 的指令,这条指令能获取多条ip,大部分是temp的,我过滤ip的条件有点冗余,可以根据自己要求配置。

另外,我的脚本有一点点弊端,就是telnet联过路由后,后面是不用再输入密码的,但这里多输了一次,无伤大雅,毕竟你的密码不是一个可执行命令。

使用crontab -e,将你的脚本添加到定时任务自动执行,关于定时任务的配置,就不讲了。

nginx & alist

关于SSH访问及控制,参考之前的文章。

因为我主要是为了方便存储文件,跑了个alist,如果你没有域名,其实alist也是够用的,它支持otp动态密码,配合前面的email接收邮件,足够使用了。不过http毕竟是明文传输,我为了安全起见,还是装了ssl证书。我看alist的配置有ssl证书,但最后还是采用了nginx的反向代理,根据server控制更方便。

自己建服务器主要涉及以下几个问题:

  1. 你的服务不要搭建在常规端口上。(80 443 445端口封锁,这三个通常用于http https smb协议。)
  2. 域名在国外服务商注册,且不要使用国内dns加速服务 (可能会有上报,当然流量追踪也可能被查。)
  3. 添加ssl (http是明文传输,尽量使用https)

综上所述,大概配置要做到如下几点:

  1. alist的address配置为127.0.0.1,这样公网ip访问不到你的主alist服务。本来想再加内网ip,我尝试了一下,alist不能指定多个address,所以用反向代理。
  2. nginx配置一个ssl server,server_name可以绑定你的域名,也可以写_。
  3. nginx配置一个http server,端口可以是80,server_name使用你192.168.124.x的ipv4地址,供你内网访问。
  4. 以上两个nginx,全使用反向代理连接到alist,反向代理在alist的文档里有。

做完以上操作,能达到的效果是:外网通过https走加密通道访问(注意端口),内网可以直接通过192.168.124.x走http直接访问。

ssl & ddns

没关系的两个内容为什么放一起写,因为ssl签发证书,只能通过dns认证,其它的方式要求80端口开放。

ssl

  1. 使用certbot,或者acme.sh申请证书,有效期90天。
  2. 因为80被封,只能手动改dns认证。它会要求你加一条txt解析,续期值会不一样。
  3. 如果你的域名服务商是cloudflare,有插件支持,没插件的服务商需要自己申请一下key,发请求。顺带说一下,godaddy的dns api大陆访问不了。
  4. 如果你能做了dns自动认证,那就加到crontab -e上,定时自动续期,这里不要太频繁,因为有效期有90天,可以两个月续一次。

如果你脚本搞不定,90天手动更新一次也是可以的。

ddns

如果你上面dns的一步搞定了,推荐你使用你的脚本,结合之前获取ip,自己做ddns。小白就使用ddns-go吧。