禁止〖 IP + 端口 〗访问〖 Docker 〗〖 IPv6 优化版 〗
摘要
由于 Seafile 不能原生支持 IPv6 访问,决定不再使用,用了这么多年,终于还是说再见,通过尝试得知 Nextcloud 符合需求,通过第三方脚本里面的自动安装,是非常轻量,但是会提示数据库不推荐,最终决定使用 Nextcloud All-In-One 版本,这中间需要按照官方操作,反向代理在另外一台机子上,所以采取的是反代途径安装,经过一番周折搞定之后,发现,并不能固定自动安装容器的 IP 地址,除了第一个容器可以,其余几个,不知道如何去固定 IP 地址,因为是通过 WEB 端点击的安装,都是后台自动进行的,所以,就引出一个问题,无法通过防火墙去设定规则,经过反反复复磨合 ChatGPT 之后,最终优化出合适的脚本内容,通过自动获取各个容器的 IP 地址,然后自动设定容器防火墙的规则,由于是多个容器,需要设定名称和端口的键值合集,以解决 IPv6 规则有些容器不生效的问题,最大的难点,在于有一个容器,确切的说是 Nextcloud 反代的容器,无论怎么尝试,就是不能自动生效 IPv4 规则,排查原因,可是费了大力气,最后发现,之所以不生效,是因为同时连接两个容器网络导致,无法自动识别到底需要哪个 IP 地址,然后尝试退出容器默认网络,发现不行,必须得保留,只能想办法让脚本自动识别需要的那个 IP 地址,这个过程及其难受、及其折磨,通过不断训练磨合 ChatGPT 之后,得到了满意答案。目前的脚本版本,可以说非常满意。在没有遇到其他另类情况之前,这个脚本可以完美开机自动获取各个容器的 IP 地址,然后自动归类设定防火墙规则,以达到限制外界通过 IP + 端口的形式直接访问容器提供的各类服务。
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 |
THE END