

Github持续更新,通过训练 ChatGPT 不断打磨脚本工具,初衷是可以快捷运行某些常用命令和程序。看似当前功能不多,实则每个细节都需要反复推敲。
从最终脚本使用感受和终端交互体验来看,目前尚可中意。脚本每个细节交互逻辑层次、菜单上下先后顺序,这些都需要考虑到,每当新增菜单项目后,都需要确保尽可能无纰漏、无 BUG 问题。感觉还是很需要费些心力和时间。
项目地址,名称:【System Tools Collection】ㅤㅤ地址:https://github.com/iptsh/system_toolsㅤㅤ脚本:https://raw.githubusercontent.com/iptsh/system_tools/main/system_tools.shㅤㅤ安装使用方法:
|
1 2 3 |
curl -O https://raw.githubusercontent.com/iptsh/system_tools/main/system_tools.sh && \ chmod +x ./system_tools.sh && \ ./system_tools.sh |
|
1 2 3 4 |
wget "https://raw.githubusercontent.com/iptsh/system_tools/main/system_tools.sh?$(date +%s)" \ -O system_tools.sh && \ chmod +x system_tools.sh && \ ./system_tools.sh |
为什么会有这个脚本?日常中发现很多命令每次都需要手动输入,非常不方便,所以整合到脚本中,易于维护和查看。这是一个非常简易化的系统工具合集,目前是初步版本,方便自己使用。全部来自 ChatGPT 的训练结果,逐步添加更多常用功能,环境为 Debian 12/13 系统。
更新日志
【v1.1】 第一版,查看防火墙现有入站规则,包括 Docker 端口规则和转发规则。(2024.08.16午)
【v1.2】 第二版,防火墙 SSH 管理、更新菜单、更新日志、整合 ipset 地址、删除宿主规则。(2024.08.16夜)
【v1.3】 第三版,调整细节,优化色彩,增强易读性,关键信息突出显示,会话 screen 管理,修复选择 N/n 依然更新。(2024.08.17午)
【v1.4】 第四版,修复无法完成脚本更新问题,提醒删除更新临时文件,细节美观优化,作者网站添加显示。(2024.08.17夜)
【v1.5】 第五版,添加脚本显示语言切换功能,支持中文和英文切换,脚本外观显示优化。(2024.08.20夜)
【v1.6】 第六版,管理 Docker 防火墙规则,管理单纯支持 IPv4 访问的 Docker 服务,管理同时支持 IPv4 访问和 IPv6 访问的 Docker 服务,如果是后者,需要开启 Docker 自定义网络,并且配置 IPv6 转发和访问,本脚本不会强制去要求用户如何去完成这些配置,不过就目前来看,通过 Docker 项目 robbertkl/ipv6nat 实现 Docker 网络的 IPv6 转发和访问,是比较推荐的做法,当然也可以采取别的方法。这个脚本的 Docker 服务防火墙管理功能,其实也是作者制作这个脚本的最初目的,同时也是作者认为非常有必要实现脚本化的 Docker 维护策略。两个非常重要的事情,一个是限制外界对 Docker 搭建服务的访问,另一个是实现 Docker 服务的 IPv6 访问。(2024.08.21午)
【v1.7】 第七版,修正 Docker 防火墙管理选项逻辑错误,增加询问是否创建配置文件的判断环节,增加常用系统命令子菜单,主菜单增加显示 Docker 容器信息选项,显示容器名称、容器所在网络名称、IPv4地址、IPv6地址、容器运行状态、容器端口映射信息,优化 Docker 容器信息显示的可读性以及信息输出的美观性。(2024.08.22夜)
【v1.8】 第八版,变更 Docker 容器信息显示的容器状态内容为白色,以避免手机客户端代码自动换行后,视觉上与容器名称不好区分,变更 Docker 容器信息获取的内容为空时,能够显示字符 N/A ,以代表未获取到任何信息,防止可能会造成的信息列的错乱。(2024.08.23午)
【v1.9】 第九版,修正创建 Docker 防火墙配置文件时,未判断 ipset 是否已经安装的问题,优化以及变更管理 SSH 防火墙规则以及管理 Docker 防火墙和规则时终端交互的逻辑层次,当选择未创建配置时会首先判断系统中是否已经存在配置文件,这是一种质疑逻辑,避免选择失误进而造成直接进入创建配置文件的环节,显然直接进入下一环节并不是最佳的终端交互体验方式,另外,当选择修改相应的配置文件时,也会首先判断系统中是否已经存在对应的配置文件,同样也是质疑性质的逻辑,之前的版本中,在最终创建配置文件的之前才会检测系统是否已经存在配置文件,现在这种检测被提前到交互询问的环节,这一切都时为了在创建任何配置文件之前,都能确保系统中确实没有相应的配置文件,而不是直接盲目的创建任何文件,一切都需要在透明的逻辑环境下进行脚本的敏感操作,至于之前的检测环节,变更为相应的提示语。(2024.08.25夜)
【v2.0】 第十版,查看 iptables IPv4 Docker NAT 规则和查看 ip6tables IPv6 Docker NAT 规则,在最新的Debian版本中,无法通过POSTROUTING显示端口NAT转发明细,此版本增加DOCKER明细以显示转发。(2025.04.17午)
【v2.1】 第十一版,新版本哪吒监控服务端和被监控端共用相同的端口,本脚本设置的IP地址防火墙规则更新匹配方法,同时保留新旧版本的端口匹配。(2025.04.18午)
【v2.2】 第十二版,修正新建ssh防火墙规则脚本内容错误,原脚本没有定义丢弃规则,这属于严重功能错误,如果仅仅定义允许的规则,将毫无意义。(2025.04.21午)
【v2.3】 第十三版,删除首次创建以及修改ssh规则之后显示ip地址集相关的代码,原因是无法显示,属于无效代码。(2025.04.23午)
【v2.4】 第十四版,修复新建 ssh 脚本以及 docker ip 脚本时的三处核心关键错误,分别是网络名称获取的错误、获取容器名称的错误、ipset地址集合服务的错误。脚本作者迁移至新的 iptsh.com 网址。修复几处细节的显示颜色无效问题。(2025.05.06午)
【v2.5】第十五版,修复screen工具代码中包含sudo导致的错误,添加卸载脚本菜单选项,卸载脚本时也同时卸载快捷方式。(2026.05.21午)
以下内容是脚本形成之前的探索,按照时间倒序排列。
禁止〖 IP + 端口 〗访问〖 Docker 〗〖 规则优化版 〗
复盘所有规则过程中,发现有一个规则顺序有概率会在服务器重启后颠倒,这是严重的问题,会直接导致放行的地址无法访问到服务,询问 ChatGPT 多次后,没有真正解决,原因不明,然后就想着是否可以接着这个思路继续往前走走看,是否能够解决每次添加新的容器到各种脚本之后,都要重启服务器才能避免重复添加之前已经存在的规则,经过多次尝试之后,最终选择 ChatGPT 提供的循环删除已存在的规则这种方法,然后顺便莫名其妙的解决了刚才说的规则顺序颠倒的问题。同样的,适用于 SSH 、X-UI 的规则脚本。(2024.08.02)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
# 定义IPV4规则 ACCEPT_RULE_IPV4="-m set --match-set allowed_ips src -d $CONTAINER_IP -p tcp --dport $port -j ACCEPT" DROP_RULE_IPV4="-d $CONTAINER_IP -p tcp --dport $port -j DROP" # 删除可能存在的重复规则 while iptables -D DOCKER-USER $DROP_RULE_IPV4 2>/dev/null; do :; done while iptables -D DOCKER-USER $ACCEPT_RULE_IPV4 2>/dev/null; do :; done # 添加IPV4规则 iptables -I DOCKER-USER 1 $ACCEPT_RULE_IPV4 iptables -I DOCKER-USER 2 $DROP_RULE_IPV4 # 定义IPV6规则 ACCEPT_RULE_IPV6="-m set --match-set allowed_ipv6_ips src -d $CONTAINER_IPV6 -p tcp --dport $port -j ACCEPT" DROP_RULE_IPV6="-d $CONTAINER_IPV6 -p tcp --dport $port -j DROP" # 删除可能存在的重复规则 while ip6tables -D DOCKER-USER $DROP_RULE_IPV6 2>/dev/null; do :; done while ip6tables -D DOCKER-USER $ACCEPT_RULE_IPV6 2>/dev/null; do :; done # 添加IPV6规则 ip6tables -I DOCKER-USER 1 $ACCEPT_RULE_IPV6 ip6tables -I DOCKER-USER 2 $DROP_RULE_IPV6 |
禁止〖 IP + 端口 〗访问〖 Docker 〗〖 纯 IPv4 版 〗
这就又回到不可避免的情况,之前 Searxng 和 Seafile 就属于这种,无论怎么弄,都无法从本地服务器的 IPv6 地址把服务构建出去,只能通过另外一台服务器反向代理实现 IPv6 访问,当然反代服务器必须支持 IPv6 地址才行,通过 NAT 映射出去的 IPv6 可以通过反代 upstream 块的方式负载均衡到 IPv6 或者 IPv4 地址,而且不浪费本地服务器原生支持 IPv6 的现状,而且由于是 NAT 转发 IPv6 地址,自然安全方面更容易管理,通过〖 非纯 IPv6 版 〗方式的话,也可以负载均衡,也没有浪费原生现状,但是安全方面天生不具备优势,那么,〖 纯 IPv4 版 〗相比较而言,无法负载均衡,而且浪费原生现状,安全的话可以直接选择不去映射 IPv6 端口,也就是通过 "0.0.0.0:映射端口:容器端口" 的方式实现仅暴露 IPv4 地址的效果,从而避免可能存在的潜在安全隐患,这也算是唯一的可圈之处,防火墙规则的话,只需要设定 IPv4 iptables DOCKER-USER 规则即可,不用再去考虑 IPv6 规则,同时获取 IP 地址时,不需要再指定容器所在的网络,因为是直接默认网络启动的容器,这种情况,有可能容器启动后是 Docker 默认的 bridge 网络,也可能会自动创建一个基于 bridge 的网络,无论哪种情况,都只会造成容器启动后仅有一个网络,所以,不用在脚本中指定网络名称。但是话说回来,除非是特别中意的容器项目,否则真心不想这样使用,太浪费原生 IPv6 地址的支持。(2024.08.02)
|
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 |
#!/bin/bash # 获取容器的 IPv4 地址 get_container_ip() { local container_name=$1 docker inspect $container_name | jq -r '.[0].NetworkSettings.Networks | to_entries | .[0].value.IPAddress' } # 最大等待时间为 240 秒,每 1 秒检查一次 MAX_WAIT=240 INTERVAL=1 TIME_WAITED=0 # 定义容器名称和端口映射 declare -A CONTAINERS CONTAINERS=( ["容器名称-容器端口"]="容器端口" # 添加更多容器和端口 ) # 等待 iptables DOCKER-USER 链可用 while [ $TIME_WAITED -lt $MAX_WAIT ]; do if iptables -L DOCKER-USER &> /dev/null; then # 创建 ipset 地址合集(如果不存在) ipset list allowed_ipv4_ips &> /dev/null || ipset create allowed_ipv4_ips hash:ip # 手动添加 IP 地址到 ipset 合集 ipset add allowed_ipv4_ips 放行的 IPv4 地址 || true for key in "${!CONTAINERS[@]}"; do # 分离容器名称和端口 container_name=$(echo $key | sed 's/-[0-9]*$//') port=${CONTAINERS[$key]} # 获取容器的 IPv4 地址 CONTAINER_IP=$(get_container_ip $container_name) if [ -z "$CONTAINER_IP" ]; then continue fi # 定义规则 iptables -I DOCKER-USER 1 -m set --match-set allowed_ipv4_ips src -d $CONTAINER_IP -p tcp --dport $port -j ACCEPT iptables -I DOCKER-USER 2 -d $CONTAINER_IP -p tcp --dport $port -j DROP done exit 0 fi sleep $INTERVAL TIME_WAITED=$((TIME_WAITED + INTERVAL)) done exit 1 |
禁止〖 IP + 端口 〗访问〖 Docker 〗〖 非纯 IPv6 版 〗
之前提到过 Seafile 不支持原生形式的 IPv6 地址访问,类似的容器肯定不在少数,这些容器只能使用默认 Docker bridge 网络,然后借助服务器公网 IPv6 地址加端口的方式,可以实现 IPv6 访问,但是容器内部没有 IPv6 内网地址,这种方式,如果要实现禁止〖 IP + 端口 〗访问〖 Docker 〗之目的,就比较特殊,所以叫〖 非纯 IPv6 版 〗,因为尽管不是纯的,但是变相的可以通过 IPv6 访问。在定义规则时,需要把 IPv4 和 IPv6 分开处理,对于 IPv4 需要定义 iptables DOCKER-USER 规则,而 IPv6 需要直接定义 iptables INPUT 规则。关键点在于,需要定义容器的端口和宿主的端口,用来分别用于 DOCKER-USER 规则和 INPUT 规则。(2024.08.02)
|
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 |
#!/bin/bash # 获取容器的 IPv4 地址 get_container_ip() { local container_name=$1 docker inspect $container_name | jq -r '.[0].NetworkSettings.Networks["bridge"].IPAddress' } # 最大等待时间为 240 秒,每 1 秒检查一次 MAX_WAIT=240 INTERVAL=1 TIME_WAITED=0 # 定义容器名称和端口映射 declare -A CONTAINERS CONTAINERS=( ["容器名称"]="容器端口:宿主端口" # 添加更多容器和端口 ) # 等待 iptables DOCKER-USER 链可用 while [ $TIME_WAITED -lt $MAX_WAIT ]; do if iptables -L DOCKER-USER &> /dev/null; then # 创建 ipset 地址合集(如果不存在) ipset list allowed_bridge_ips &> /dev/null || ipset create allowed_bridge_ips hash:ip ipset list allowed_bridge_ipv6_ips &> /dev/null || ipset create allowed_bridge_ipv6_ips hash:ip family inet6 # 手动添加 IP 地址到 ipset 合集 ipset add allowed_bridge_ips IPv4地址 || true ipset add allowed_bridge_ipv6_ips IPv6地址 || true for container_name in "${!CONTAINERS[@]}"; do # 分离容器名称和端口 ports=${CONTAINERS[$container_name]} IFS=':' read -r container_port host_port <<< "$ports" # 获取容器的 IPv4 地址 CONTAINER_IP=$(get_container_ip $container_name) if [ -z "$CONTAINER_IP" ]; then continue fi # 定义规则 iptables -I DOCKER-USER 1 -m set --match-set allowed_bridge_ips src -d $CONTAINER_IP -p tcp --dport $container_port -j ACCEPT iptables -I DOCKER-USER 2 -d $CONTAINER_IP -p tcp --dport $container_port -j DROP ip6tables -A INPUT -p tcp -m multiport --dports $host_port \ -m set --match-set allowed_bridge_ipv6_ips src \ -m comment --comment "Allow access to port $host_port from allowed IPs" \ -j ACCEPT ip6tables -A INPUT -p tcp --dport $host_port \ -m comment --comment "Block access to port $host_port for all other sources" \ -j DROP done exit 0 fi sleep $INTERVAL TIME_WAITED=$((TIME_WAITED + INTERVAL)) done exit 1 |
禁止〖 IP + 端口 〗访问〖 Docker 〗〖 IPv6 优化版 〗
由于 Seafile 不能原生支持 IPv6 访问,决定不再使用,用了这么多年,终于还是说再见,通过尝试得知 Nextcloud 符合需求,通过第三方脚本里面的自动安装,是非常轻量,但是会提示数据库不推荐,最终决定使用 Nextcloud All-In-One 版本,这中间需要按照官方操作,反向代理在另外一台机子上,所以采取的是反代途径安装,经过一番周折搞定之后,发现,并不能固定自动安装容器的 IP 地址,除了第一个容器可以,其余几个,不知道如何去固定 IP 地址,因为是通过 WEB 端点击的安装,都是后台自动进行的,所以,就引出一个问题,无法通过防火墙去设定规则,经过反反复复磨合 ChatGPT 之后,最终优化出合适的脚本内容,通过自动获取各个容器的 IP 地址,然后自动设定容器防火墙的规则,由于是多个容器,需要设定名称和端口的键值合集,以解决 IPv6 规则有些容器不生效的问题,最大的难点,在于有一个容器,确切的说是 Nextcloud 反代的容器,无论怎么尝试,就是不能自动生效 IPv4 规则,排查原因,可是费了大力气,最后发现,之所以不生效,是因为同时连接两个容器网络导致,无法自动识别到底需要哪个 IP 地址,然后尝试退出容器默认网络,发现不行,必须得保留,只能想办法让脚本自动识别需要的那个 IP 地址,这个过程及其难受、及其折磨,通过不断训练磨合 ChatGPT 之后,得到了满意答案。目前的脚本版本,可以说非常满意。在没有遇到其他另类情况之前,这个脚本可以完美开机自动获取各个容器的 IP 地址,然后自动归类设定防火墙规则,以达到限制外界通过 IP + 端口的形式直接访问容器提供的各类服务。(2024.08.01)
|
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 |
#!/bin/bash # 日志文件和目录 LOG_DIR="/var/log/docker-iptables" LOG_FILE="$LOG_DIR/add_ips.log" # 创建日志目录(如果不存在) mkdir -p $LOG_DIR # 定义日志函数 log_message() { local message=$1 echo "$(date +"%Y-%m-%d %H:%M:%S") - $message" >> $LOG_FILE } # 获取容器的 IPv4 地址 get_container_ip() { local container_name=$1 docker inspect $container_name | jq -r '.[0].NetworkSettings.Networks["这里是容器所在的网络"].IPAddress' } # 获取容器的 IPv6 地址 get_container_ipv6() { local container_name=$1 docker inspect $container_name | jq -r '.[0].NetworkSettings.Networks["这里是容器所在的网络"].GlobalIPv6Address' } # 最大等待时间为 240 秒,每 1 秒检查一次 MAX_WAIT=240 INTERVAL=1 TIME_WAITED=0 # 定义容器名称和端口 declare -A CONTAINERS CONTAINERS=( ["容器名称1-端口1"]="端口1" ["容器名称2-端口2"]="端口2" ["容器名称3-端口3"]="端口3" # 添加更多容器和端口 ) # 等待 iptables DOCKER-USER 链可用 while [ $TIME_WAITED -lt $MAX_WAIT ]; do if iptables -L DOCKER-USER &> /dev/null; then # 创建 ipset 地址合集(如果不存在) ipset list allowed_ips &> /dev/null || ipset create allowed_ips hash:ip ipset list allowed_ipv6_ips &> /dev/null || ipset create allowed_ipv6_ips hash:ip family inet6 ipset list allowed_其他特殊规则_ips &> /dev/null || ipset create allowed_其他特殊规则_ips hash:ip ipset list allowed_其他特殊规则_ipv6_ips &> /dev/null || ipset create allowed_其他特殊规则_ipv6_ips hash:ip family inet6 # 手动添加 IP 地址到 ipset 合集 ipset add allowed_ips 需要放行的 IPv4 地址 || true ipset add allowed_ipv6_ips 需要放行的 IPv6 地址 || true ipset add allowed_其他特殊规则_ips 需要放行的 IPv4 地址 || true ipset add allowed_其他特殊规则_ipv6_ips 需要放行的 IPv6 地址 || true for key in "${!CONTAINERS[@]}"; do # 分离容器名称和端口 container_name=$(echo $key | sed 's/-[0-9]*$//') port=${CONTAINERS[$key]} # 获取容器的 IP 地址 CONTAINER_IP=$(get_container_ip $container_name) CONTAINER_IPV6=$(get_container_ipv6 $container_name) if [ -z "$CONTAINER_IP" ] || [ -z "$CONTAINER_IPV6" ]; then log_message "Container IP address or IPv6 address not found for $container_name." continue fi if [[ "$container_name" == "其他特殊规则容器名称" && "$port" == "端口" ]]; then # 定义 其他特殊 规则 log_message "Applying 其他特殊规则 IPv4 rules for $container_name on port $port" iptables -I DOCKER-USER 1 -m set --match-set allowed_其他特殊规则_ips src -d $CONTAINER_IP -p tcp --dport $port -j ACCEPT iptables -I DOCKER-USER 2 -d $CONTAINER_IP -p tcp --dport $port -j DROP log_message "Applying 其他特殊规则 IPv6 rules for $container_name on port $port" ip6tables -I DOCKER-USER 1 -m set --match-set allowed_其他特殊规则_ipv6_ips src -d $CONTAINER_IPV6 -p tcp --dport $port -j ACCEPT ip6tables -I DOCKER-USER 2 -d $CONTAINER_IPV6 -p tcp --dport $port -j DROP else # 定义常规规则 log_message "Applying general IPv4 rules for $container_name on port $port" iptables -I DOCKER-USER 1 -m set --match-set allowed_ips src -d $CONTAINER_IP -p tcp --dport $port -j ACCEPT iptables -I DOCKER-USER 2 -d $CONTAINER_IP -p tcp --dport $port -j DROP log_message "Applying general IPv6 rules for $container_name on port $port" ip6tables -I DOCKER-USER 1 -m set --match-set allowed_ipv6_ips src -d $CONTAINER_IPV6 -p tcp --dport $port -j ACCEPT ip6tables -I DOCKER-USER 2 -d $CONTAINER_IPV6 -p tcp --dport $port -j DROP fi log_message "Rules applied successfully for $container_name on port $port." done exit 0 fi sleep $INTERVAL TIME_WAITED=$((TIME_WAITED + INTERVAL)) done log_message "Error: DOCKER-USER chain not found after $MAX_WAIT seconds." exit 1 |
禁止〖 IP + 端口 〗访问〖 Docker 〗〖 汇总版 〗
分为以下几种情形。第一种,使用 host 网络模式,则直接通过 iptables INPUT 规则即可限制,缺点很明显,容器越来越多,则必然端口冲突。第二种,服务器厂家自带外置防火墙,例如 linode 防火墙,可以直接定义端口的规则,可以无视容器规则带来的控制问题,缺点的话,不是每一个厂家都提供这种服务。第三种,直接不暴露端口,改用 Nginx 容器所在网络,必须反代使用,缺点几乎没有,非常特殊的需求下会有冲突,例如这几天鼓捣的最终目的就是把反代迁移出去,因为 443 和 80 端口需要让位给 X-UI 使用。第四种,使用 bridge 网络模式,包括自定义 bridge 网络,需要定义 iptables DOCKER-USER 规则,特别重要的是屏蔽端口不能是映射到宿主的端口,必须是容器内部端口,这是核心关键点所在,还需要固定容器 IP 地址,不然的话多个容器同时存在时会开机打乱地址,而且开机自启动需要晚于系统创建 DOCKER-USER 规则链的时间,否则不生效,这一种可以说是最完美的方案,没有任何缺点,硬要说,也只有一点,就是必须手动创建规则,不过可以借助脚本,同时可以开机自动运行,因为每次重启,Docker 都会自动重新创建规则。大致无外乎就是这四种情形。第三种之前文章已经记录过,前两种不需要刻意记录,搜索即可看到大把教程。说是〖最终汇总版〗,其实重点就是记录最后一种情况的步骤,也算是这几天没有白忙活,翻遍各种网络教程,结合 ChatGPT 之助攻,感觉自己有所收获。下面开始记录,同时把 IPv6 一起涵盖记录。(2024.07.30)
第 1 步,由于把 IPv6 情形涵盖在内,首先部署 robbertkl/ipv6nat 容器,实现 IPv6 的 NAT 转发功能,分配内部 IPv6 地址,创建自定义 Docker 网络,把容器加入到这个自定义网络中。同时需要定义固定的 IP 地址,包括 IPv4 和 IPv6 两者。
|
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 |
# 部署 robbertkl/ipv6nat 容器 docker run -d --name ipv6nat --privileged --network host --restart unless-stopped -v /var/run/docker.sock:/var/run/docker.sock:ro -v /lib/modules:/lib/modules:ro robbertkl/ipv6nat # 创建自定义 Docker 网络 docker network create my-net-ipv6 --ipv6 --subnet="fd00:1::/80" --gateway="fd00:1::1" # 定义容器 IP 地址并加入到这个自定义网络中 docker run -d \ ······ -p 6789:8000 \ --net my-net-ipv6 \ --ip 172.22.0.3 \ --ip6 fd00:1::3 \ ······ 或者 version: '3' services: app: image: your_image_name ports: - 6789:8000 networks: my-net-ipv6: ipv4_address: 172.22.0.3 ipv6_address: fd00:1::3 # 其他参数 networks: my-net-ipv6: external: true |
第 2 步,创建规则脚本,并创建开机自启动服务,其中规则脚本开机自启动需要晚于系统创建 DOCKER-USER 规则链的时间,否则不生效。故需要定义脚本中循环等待检查的参数。另外 IPv4 和 IPv6 需要分别定义。屏蔽端口不能是映射到宿主的端口,必须是容器内部端口,这是核心关键点所在。同样是不定义本地 IP 地址,但是,通过 iptables INPUT 规则限制的端口,就算是本地节点,亦不能访问,而,通过 iptables DOCKER-USER 规则限制的端口,外界无法访问,本地节点可以访问,这类似于 linode 商家的外置防火墙给我的感觉。
|
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 |
# 安装 ipset 地址管理工具 apt-get install -y ipset # 新建 add_ips.sh 脚本 nano /root/add_ips.sh # 在 add_ips.sh 脚本中添加以下内容 #!/bin/bash # 创建 ipset allowed_ips #!/bin/bash # 最大等待时间为 60 秒,每 2 秒检查一次 MAX_WAIT=60 INTERVAL=2 TIME_WAITED=0 while [ $TIME_WAITED -lt $MAX_WAIT ]; do if iptables -L DOCKER-USER &> /dev/null; then # 创建 ipset 地址合集 ipset create allowed_ips hash:ip ipset create allowed_ipv6_ips hash:ip family inet6 # 添加 IP 地址到 ipset 合集 ipset add allowed_ips 地址 ipset add allowed_ips 地址 ipset add allowed_ips 地址 ipset add allowed_ipv6_ips 地址 ipset add allowed_ipv6_ips 地址 ipset add allowed_ipv6_ips 地址 # 定义 iptables 规则 iptables -I DOCKER-USER 1 -m set --match-set allowed_ips src -d 172.22.0.3 -p tcp --dport 8000 -j ACCEPT iptables -I DOCKER-USER 2 -d 172.22.0.3 -p tcp --dport 8000 -j DROP ip6tables -I DOCKER-USER 1 -m set --match-set allowed_ipv6_ips src -d fd00:1::3 -p tcp --dport 8000 -j ACCEPT ip6tables -I DOCKER-USER 2 -d fd00:1::3 -p tcp --dport 8000 -j DROP echo "Rules applied successfully." exit 0 fi sleep $INTERVAL TIME_WAITED=$((TIME_WAITED + INTERVAL)) done echo "Error: DOCKER-USER chain not found after $MAX_WAIT seconds." exit 1 # 赋予 add_ips.sh 执行权限 chmod +x ./add_ips.sh # 新建 add_ips.service 开机自动运行服务文件 nano /etc/systemd/system/add_ips.service # 在 add_ips.service 文件中添加以下内容 [Unit] Description=Add IP addresses to ipset and set iptables rules After=network.target [Service] Type=oneshot ExecStart=/root/add_ips.sh [Install] WantedBy=multi-user.target # 重新加载配置,设置开机自动运行,启动服务,查看运行状态。验证配置是否已经生效。 systemctl daemon-reload systemctl enable add_ips.service systemctl start add_ips.service systemctl status add_ips.service # 重启服务器,验证是否开机自动运行。 reboot iptables -L -n #验证是否 IPv4 规则自动成功运行 ip6tables -L -n #验证是否 IPv6 规则自动成功运行 |
命令备忘
|
1 2 3 4 5 6 7 8 |
iptables -L INPUT -n ip6tables -L INPUT -n iptables -L -n ip6tables -L -n iptables -t nat -L ip6tables -t nat -L docker network inspect bridge ipset list allowed_ips |
限定 IP 连接 SSH
一切出于安全,参照上一篇 仅允许特定 IP 访问特定端口 达到限定 IP 连接 SSH ,换言之,只有指定的 IP 地址才可以访问 SSH 服务。在原来基础上加了一道安全防线。(2024.07.13)
仅允许特定 IP 访问特定端口
尽管最终目标“禁止 IP + 端口访问”未实现,不过也算是已经变相满足安全诉求。这是第三种用来屏蔽外界直接访问特定服务之解决方案,之前两种,一种是直接不暴露 Docker 容器端口借助反代从根源上达到目的,另一种是通过自定义容器内配置文件以达到屏蔽外界通过 IP 地址直接访问服务之可能性,这第三种比较特殊,不能通过上述那两种方法达到目的,必须要暴露并映射端口才能使用,也无法通过自定义配置文件去屏蔽。具体策略就是,仅允许特定 IP 访问某个端口且开机自动运行,尽管无法通过反代访问,不过就算是没有 ssl 配置之安全加持,外界也无法访问特定端口之服务。最终,特定之服务,只能通过特定 IP 地址访问,其实就是代理地址。(2024.07.19)
第 1 步,安装ipset工具,并新建add_ips.sh脚本。
|
1 2 |
apt-get install -y ipset #安装 ipset 地址管理工具 nano /root/add_ips.sh #新建 add_ips.sh 脚本 |
第 2 步,在add_ips.sh脚本中添加以下内容。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#!/bin/bash # 创建 ipset allowed_ips 地址合集 ipset create allowed_ips hash:ip # 添加 IP 地址到 ipset allowed_ips 合集 ipset add allowed_ips 地址1 ipset add allowed_ips 地址2 ipset add allowed_ips 地址3 # 设置 iptables 规则 iptables -A INPUT -p tcp -m multiport --dports 端口 \ -m set --match-set allowed_ips src \ -m comment --comment "Allow access to port 端口 from allowed IPs" \ -j ACCEPT iptables -A INPUT -p tcp --dport 端口 \ -m comment --comment "Block access to port 端口 for all other sources" \ -j DROP |
第 3 步,赋予add_ips.sh执行权限,并新建add_ips.service开机自动运行服务文件。
|
1 2 |
chmod +x ./add_ips.sh #赋予权限 nano /etc/systemd/system/add_ips.service #新建开机自动运行服务文件 |
第 4 步,在add_ips.service文件中添加以下内容。
|
1 2 3 4 5 6 7 8 |
[Unit] Description=Add IP addresses to ipset and set iptables rules After=network.target [Service] Type=oneshot ExecStart=/root/add_ips.sh [Install] WantedBy=multi-user.target |
第 5 步,重新加载配置,设置开机自动运行,启动服务,查看运行状态。验证配置是否已经生效。
|
1 2 3 4 5 |
systemctl daemon-reload #重新加载配置 systemctl enable add_ips.service #设置开机自动运行 systemctl start add_ips.service #启动服务 systemctl status add_ips.service #查看运行状态 iptables -L INPUT -n #验证是否生效 |
第 6 步,重启服务器,验证是否开机自动运行。
|
1 2 |
reboot #重启服务器 iptables -L INPUT -n #验证是否自己自动成功运行 |
命令备忘
|
1 2 3 |
iptables -D INPUT 1 #清楚编号为 1 的防火墙入站规则 iptables -L -n #查看全部防火墙规则 ipset list allowed_ips #显示地址合集具体信息 |
鸣谢:所有解决思路和方案探讨,以及最终诉求达成,全部来自 ChatGPT 之建议。
禁止〖IP + 端口〗访问〖Docker〗〖不暴露端口〗(再续)
重新安装 Joplin 过程中,询问 ChayGPT 得知,定义 Docker YML 网络属性,需要单独定义。然后 app 和 db 分别引用定义的网络属性即可。(2024.06.18)
|
1 2 3 4 5 6 7 8 9 10 |
version: '3' services: app: image: your_image_name networks: - nginx_network #定义为 Ningx 所在网络 # 其他参数 networks: nginx_network: #定义为 Ningx 所在网络 external: true |
禁止〖IP + 端口〗访问〖Docker〗〖不暴露端口〗(续)
按照套路重新安装 recketchat 之后,发现并不能正常访问,经过排查,是 db 也需要定义网络参数,确保都在同一网络下,才可以。(2024.06.18)
禁止〖IP + 端口〗访问〖Docker〗〖不暴露端口〗
这一切诉求之来源,皆由 VPS 无防火墙造成。目的无非是,规避暴露端口,禁止外界直接访问 IP + 端口。各种防火墙方法,及各种咨询 ChatGPT 之后,均无效。可仍有执念。最终受一篇教程启发,当然关键还是 ChatGPT 立功,再稍作变通,如得所愿。幸甚,幸甚。关键就在于,既然要禁止外界通过 IP + 端口直接访问 Docker 内某项服务,那么从根源上来讲,启动 Docker 内某项服务时,不去定义 -p 参数,不去定义运行端口,转而由 --net 参数代替,定义 Docker 内 Ningx 所在网络,这样一来,在启动服务后,倘若不去反代,则无法访问此项服务,反代参数定义服务名称 + 所在 Docker 内端口。所有关键信息点均来自 ChatGPT 之答案,不过有所变通,答案告知定义新网络,服务和 Nginx 分别在启动时定义到这个新网络,然后反代。变通以后,直接让服务加入到现有 Nginx 之网络,进而反代出去。(2024.06.14)
|
1 2 3 4 5 |
#某 Docker 服务 docker run -d \ ······ --net nginx_network \ #定义为 Ningx 所在网络 ······ |
|
1 2 3 4 5 6 |
#配置 Docker 内 Nginx 反代 location / { ······ proxy_pass http://service_name:port; #定义服务名称和端口 ······ } |
配置 iptables 禁止 IP + 端口访问〖此方法无效〗
又又新入手一个 VPS 机子,之前,应该是很早之前就用过这家,现在算是又回归,反代之后想着禁止直接通过 IP +端口形式访问特定的 Docker 服务,但是这家没有后台防火墙,不像 LN 商家那么贴心周到。网上搜索很多途径没有成功,什么 UFW 也好,还是 firewalld 也好,都不能起到作用,最后通过和 ChatGPT 若干回合的过招,最终达到目的。就算是通过 ChatGPT 也是费好大劲才搞定,如果单纯靠网络搜索,不知何时才能搞定。总结,走了很多弯路,好在最后可以了,不过和 LN 直接在后台一分钟搞定结果不同,通过 ChatGPT 搞定后,只能通过域名访问服务,就连自己本地 IP 节点通过 IP + 端口的方式也不能访问。当然,我个人还是喜欢现在的方式。都不能访问就对了。正是我要的结果。提问,以下是我向 ChatGPT 询问的所有问题,问了这么多才找到正确答案。说明太小白。每一次回答之后,都要尝试一遍,然后没达到效果,就需要全部推倒重来,这整个过程非常需要耐心,好在我很有耐心。耐心的源动力来自兴趣使然。(2024.06.07)
|
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 |
#安装 iptables-persistent 以便在重启后保存和恢复 iptables 规则 apt install iptables-persistent # 清除现有规则 iptables -F iptables -X ip6tables -F ip6tables -X # 创建 DOCKER-USER 链 iptables -N DOCKER-USER ip6tables -N DOCKER-USER # 设置反向代理服务器 IP proxy_server_ipv4="IPV4地址" proxy_server_ipv6="IPV6地址" # 允许反向代理服务器的 IP 访问特定端口 iptables -I DOCKER-USER -p tcp -s $proxy_server_ipv4 --dport 端口 -j ACCEPT ip6tables -I DOCKER-USER -p tcp -s $proxy_server_ipv6 --dport 端口 -j ACCEPT # 拒绝其他所有来源的访问 iptables -I DOCKER-USER -p tcp --dport 端口 -j DROP ip6tables -I DOCKER-USER -p tcp --dport 端口 -j DROP # 确保 DOCKER-USER 链在 FORWARD 链前执行 iptables -I FORWARD -j DOCKER-USER ip6tables -I FORWARD -j DOCKER-USER # 保存规则 iptables-save > /etc/iptables/rules.v4 ip6tables-save > /etc/iptables/rules.v6 # 重启 Docker 服务 systemctl restart docker # 验证规则 iptables -L -v -n ip6tables -L -v -n |
|
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 |
1. firewalld禁止外部访问某个端口 2. firewalld 开放所有端口 3. 提示 Warning: INVALID_RULE: unknown element rejectfirewall-cmd 4. 提示 You're performing an operation over default zone ('public'), but your connections/interfaces are in zone 'docker' (see --get-active-zones)You most likely need to use --zone=docker option. 5. 我是在 root 用户,不要使用 sudo,现在 提示 Warning: NOT_ENABLED: 8020:tcp 6. 我使用这个方法以后,8020 端口仍然可以被外部访问 7. 并没有起到作用,在 docker 里面显示我需要禁用的端口具体情况是 Up 28 minutes 0.0.0.0:8020->8080/tcp, :::8020->8080/tcp 8. 如何禁用 firewalld,并且卸载它 9. debian12 自带的防火墙是什么 10. 如何查看 debian12 iptables 状态 11. 通过 iptables 禁止 8020 端口被外部访问 12. 是的我需要永久生效,应该怎么做 13. 给我一个完整的步骤,我的 docker 里面有一个服务 Up 28 minutes 0.0.0.0:8020->8080/tcp, :::8020->8080/tcp ,然后需要永久关闭 8020 端口被外部访问 14. 不考虑 docker,给我一个完整的步骤,永久禁止外部访问 8020 端口 15. 需要 ipv6 也要包含在内 16. 通过 iptables 允许所有端口访问 17. 提示 bash: /etc/iptables/rules.v4: No such file or directory 18. 如何查询 iptables 规则保存路径 19. 提示 touch: cannot touch '/etc/iptables/rules.v4': No such file or directory 20. 如何完整安装 iptables,在 debian12 21. 如何安装 iptables-persistent 包 22. 查看现有规则 23. 现在不能访问 8020 端口了已经,但是域名反向代理指向 8020 的服务也不行了,有什么方法,仅仅禁用 ip 加 8020 端口的访问,同时放行域名指向的 8020 服务 24. iptables -A INPUT -p tcp --dport 8020 -j DROP 25. 还有 ipv6 26. 以 root 身份 27. 同一个域名可以同时代理 ipv4 和 ipv6 吗 28. 如何查看当前 ip 地址,包括 iov4 和 ipv6 29. 查看现有规则 30. 你的方法没有作用,通过反向代理仍然无法访问 31. 如何清除现有规则 32. 我可以直接在下面的命令中替换为域名吗 iptables -A INPUT -p tcp -s proxy_server_ipv4 --dport 8020 -j ACCEPT 33. 现在通过本地 ip 可以访问 8020 端口,但是无法通过域名访问这个端口 34. 现在 docker 里面的 8020 端口服务无法启动 35. 不考虑 docker,给我一个完整的步骤,永久禁止外部访问 8020 端口 36. 现在所有开源都可以访问 8020,还是没有达到目的 37. ufw 呢 38. 你告诉我的需要安装一个服务才能保存规则,是什么,我忘了,你能告诉我吗 39. 我记得你刚才告诉的是 apt install 而不是 apt-get 40. 你能把我和你的对话,就是这个会话的内容,单独把我向你提问的内容,单独给我一份吗 |
文章评论