Skip to content

Instantly share code, notes, and snippets.

@ran-dall
Created March 21, 2026 01:27
Show Gist options
  • Select an option

  • Save ran-dall/bb6581524da6b3e8fec1ce91acff9dce to your computer and use it in GitHub Desktop.

Select an option

Save ran-dall/bb6581524da6b3e8fec1ce91acff9dce to your computer and use it in GitHub Desktop.
Simple Bash script to verify and fix required host networking settings for Kubernetes on Arch-based systems.
#!/usr/bin/env bash
set -euo pipefail
# check-k8s-netfilter-arch.sh
#
# Checks common Kubernetes networking prerequisites on Arch-based systems:
# - br_netfilter module exists
# - br_netfilter module is loaded
# - net.bridge.bridge-nf-call-iptables = 1
# - net.bridge.bridge-nf-call-ip6tables = 1
# - net.ipv4.ip_forward = 1
#
# Modes:
# default Check only, print guidance if something is missing
# --fix Apply runtime fixes, ask before persisting
# --persist Apply runtime fixes and persist without prompting
# --help Show help
usage() {
cat <<'EOF'
Usage:
check-k8s-netfilter-arch.sh [--fix | --persist | --help]
Options:
--fix Apply runtime fixes. Ask before persisting.
--persist Apply runtime fixes and persist them without prompting.
--help Show this help text.
EOF
}
have_cmd() {
command -v "$1" >/dev/null 2>&1
}
get_sysctl_value() {
local key="$1"
sysctl -n "$key" 2>/dev/null || true
}
is_module_loaded() {
lsmod | awk '{print $1}' | grep -qx 'br_netfilter'
}
print_status() {
local status="$1"
shift
printf '%s: %s\n' "$status" "$*"
}
ask_yes_no() {
local prompt="$1"
local answer
read -r -p "$prompt [y/N]: " answer
[[ "$answer" =~ ^[Yy]$ ]]
}
apply_runtime_fixes() {
local need_module_load="$1"
local need_bridge_iptables="$2"
local need_bridge_ip6tables="$3"
local need_ip_forward="$4"
if [[ "$need_module_load" == "true" ]]; then
print_status "INFO" "Loading br_netfilter"
sudo modprobe br_netfilter
fi
if [[ "$need_bridge_iptables" == "true" ]]; then
print_status "INFO" "Setting net.bridge.bridge-nf-call-iptables=1"
sudo sysctl -w net.bridge.bridge-nf-call-iptables=1 >/dev/null
fi
if [[ "$need_bridge_ip6tables" == "true" ]]; then
print_status "INFO" "Setting net.bridge.bridge-nf-call-ip6tables=1"
sudo sysctl -w net.bridge.bridge-nf-call-ip6tables=1 >/dev/null
fi
if [[ "$need_ip_forward" == "true" ]]; then
print_status "INFO" "Setting net.ipv4.ip_forward=1"
sudo sysctl -w net.ipv4.ip_forward=1 >/dev/null
fi
}
persist_fixes() {
print_status "INFO" "Writing /etc/modules-load.d/br_netfilter.conf"
echo br_netfilter | sudo tee /etc/modules-load.d/br_netfilter.conf >/dev/null
print_status "INFO" "Writing /etc/sysctl.d/99-kubernetes.conf"
sudo tee /etc/sysctl.d/99-kubernetes.conf >/dev/null <<'EOF'
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
print_status "INFO" "Reloading sysctl settings"
sudo sysctl --system >/dev/null
}
mode="check"
case "${1:-}" in
"")
;;
--fix)
mode="fix"
;;
--persist)
mode="persist"
;;
--help|-h)
usage
exit 0
;;
*)
usage >&2
exit 2
;;
esac
if ! have_cmd modinfo; then
print_status "FAIL" "modinfo is not available"
exit 1
fi
if ! have_cmd lsmod; then
print_status "FAIL" "lsmod is not available"
exit 1
fi
if ! have_cmd sysctl; then
print_status "FAIL" "sysctl is not available"
exit 1
fi
need_fix=false
need_module_load=false
need_bridge_iptables=false
need_bridge_ip6tables=false
need_ip_forward=false
if modinfo br_netfilter >/dev/null 2>&1; then
print_status "OK" "br_netfilter module exists"
else
print_status "FAIL" "br_netfilter module was not found in the running kernel"
cat <<'EOF'
This kernel does not appear to provide br_netfilter.
On Arch-based systems, use a kernel/modules package that includes it.
EOF
exit 1
fi
if is_module_loaded; then
print_status "OK" "br_netfilter module is loaded"
else
print_status "FAIL" "br_netfilter module is not loaded"
need_fix=true
need_module_load=true
fi
bridge_iptables="$(get_sysctl_value net.bridge.bridge-nf-call-iptables)"
if [[ "$bridge_iptables" == "1" ]]; then
print_status "OK" "net.bridge.bridge-nf-call-iptables = 1"
else
print_status "FAIL" "net.bridge.bridge-nf-call-iptables = ${bridge_iptables:-missing}"
need_fix=true
need_bridge_iptables=true
fi
bridge_ip6tables="$(get_sysctl_value net.bridge.bridge-nf-call-ip6tables)"
if [[ "$bridge_ip6tables" == "1" ]]; then
print_status "OK" "net.bridge.bridge-nf-call-ip6tables = 1"
else
print_status "FAIL" "net.bridge.bridge-nf-call-ip6tables = ${bridge_ip6tables:-missing}"
need_fix=true
need_bridge_ip6tables=true
fi
ip_forward="$(get_sysctl_value net.ipv4.ip_forward)"
if [[ "$ip_forward" == "1" ]]; then
print_status "OK" "net.ipv4.ip_forward = 1"
else
print_status "FAIL" "net.ipv4.ip_forward = ${ip_forward:-missing}"
need_fix=true
need_ip_forward=true
fi
if [[ "$need_fix" == false ]]; then
printf '\n'
print_status "OK" "All Kubernetes networking prerequisites are satisfied"
exit 0
fi
printf '\n'
case "$mode" in
check)
print_status "INFO" "This host is missing one or more Kubernetes networking prerequisites"
cat <<'EOF'
To apply runtime fixes now:
sudo modprobe br_netfilter
sudo sysctl -w net.bridge.bridge-nf-call-iptables=1
sudo sysctl -w net.bridge.bridge-nf-call-ip6tables=1
sudo sysctl -w net.ipv4.ip_forward=1
To persist these settings:
echo br_netfilter | sudo tee /etc/modules-load.d/br_netfilter.conf
sudo tee /etc/sysctl.d/99-kubernetes.conf >/dev/null <<'EOT'
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOT
sudo sysctl --system
Or rerun this script with:
--fix
--persist
EOF
exit 1
;;
fix)
apply_runtime_fixes \
"$need_module_load" \
"$need_bridge_iptables" \
"$need_bridge_ip6tables" \
"$need_ip_forward"
printf '\n'
print_status "OK" "Runtime fixes applied"
if ask_yes_no "Persist these settings across reboot?"; then
persist_fixes
print_status "OK" "Persistent configuration written"
else
print_status "INFO" "Persistent configuration not written"
fi
;;
persist)
apply_runtime_fixes \
"$need_module_load" \
"$need_bridge_iptables" \
"$need_bridge_ip6tables" \
"$need_ip_forward"
persist_fixes
printf '\n'
print_status "OK" "Runtime and persistent fixes applied"
;;
esac
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment