mirror of
https://github.com/netbirdio/netbird.git
synced 2026-10-25 22:09:08 +01:00
Subnet docker conflict check; enterprice domain alias.
This commit is contained in:
@@ -12,7 +12,10 @@ SED_STRIP_PADDING='s/=//g'
|
||||
NETBIRD_EULA_URL="https://netbird.io/self-hosted-EULA"
|
||||
|
||||
# Static IP for Traefik inside the compose bridge network. The management
|
||||
# server trusts X-Forwarded-* headers from this address only.
|
||||
# server trusts X-Forwarded-* headers from this address only, so all three
|
||||
# values derive from the same /24. Override with NETBIRD_DOCKER_SUBNET.
|
||||
DOCKER_SUBNET="172.30.0.0/24"
|
||||
DOCKER_GATEWAY="172.30.0.1"
|
||||
TRAEFIK_IP="172.30.0.10"
|
||||
|
||||
check_docker_compose() {
|
||||
@@ -43,6 +46,90 @@ rand_b64_key() {
|
||||
openssl rand -base64 32
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Docker network subnet override and conflict check
|
||||
# (kept in sync with getting-started.sh; only the compose network
|
||||
# name differs)
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
ip_to_int() {
|
||||
local a b c d
|
||||
IFS=. read -r a b c d <<< "$1"
|
||||
echo $(( (10#$a << 24) + (10#$b << 16) + (10#$c << 8) + 10#$d ))
|
||||
}
|
||||
|
||||
# cidrs_overlap <cidr> <cidr> — succeeds if the networks overlap
|
||||
cidrs_overlap() {
|
||||
local net1="${1%/*}" len1="${1#*/}" net2="${2%/*}" len2="${2#*/}"
|
||||
local min_len=$(( len1 < len2 ? len1 : len2 ))
|
||||
local mask=0
|
||||
if [[ "$min_len" -gt 0 ]]; then
|
||||
mask=$(( (0xFFFFFFFF << (32 - min_len)) & 0xFFFFFFFF ))
|
||||
fi
|
||||
[[ $(( $(ip_to_int "$net1") & mask )) -eq $(( $(ip_to_int "$net2") & mask )) ]]
|
||||
}
|
||||
|
||||
# valid_ipv4_slash24 <cidr> — accepts a unicast IPv4 /24 like 10.123.45.0/24
|
||||
valid_ipv4_slash24() {
|
||||
local octet='(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])'
|
||||
local re="^${octet}\.${octet}\.${octet}\.0/24$"
|
||||
[[ "$1" =~ $re ]] || return 1
|
||||
# Reject non-unicast/reserved ranges: 0/8, loopback, link-local, 224+
|
||||
case "$1" in
|
||||
0.*|127.*|169.254.*|22[4-9].*|2[34][0-9].*|25[0-5].*) return 1 ;;
|
||||
esac
|
||||
return 0
|
||||
}
|
||||
|
||||
# Apply NETBIRD_DOCKER_SUBNET and derive the gateway (.1) and Traefik IP (.10)
|
||||
apply_docker_subnet_override() {
|
||||
if [[ -n "${NETBIRD_DOCKER_SUBNET:-}" ]]; then
|
||||
if ! valid_ipv4_slash24 "$NETBIRD_DOCKER_SUBNET"; then
|
||||
echo "NETBIRD_DOCKER_SUBNET must be a unicast IPv4 /24 network like 10.123.45.0/24 (0/8, 127/8, 169.254/16, and 224+ are not allowed), got: $NETBIRD_DOCKER_SUBNET" > /dev/stderr
|
||||
exit 1
|
||||
fi
|
||||
DOCKER_SUBNET="$NETBIRD_DOCKER_SUBNET"
|
||||
fi
|
||||
local base="${DOCKER_SUBNET%.0/24}"
|
||||
DOCKER_GATEWAY="${base}.1"
|
||||
TRAEFIK_IP="${base}.10"
|
||||
return 0
|
||||
}
|
||||
|
||||
# check_docker_subnet_conflicts <compose network name>
|
||||
# Fail early if an existing Docker network overlaps DOCKER_SUBNET, instead
|
||||
# of letting "docker compose up" fail later. Host routes are not checked;
|
||||
# NETBIRD_DOCKER_SUBNET covers those cases.
|
||||
check_docker_subnet_conflicts() {
|
||||
local expected_network="$1"
|
||||
command -v docker &> /dev/null || return 0
|
||||
|
||||
local name subnets subnet
|
||||
while IFS='|' read -r name subnets; do
|
||||
for subnet in $subnets; do
|
||||
[[ "$subnet" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/[0-9]+$ ]] || continue
|
||||
if [[ "$name" == "$expected_network" ]]; then
|
||||
# Our own leftover network: compose reuses it as-is, so its subnet
|
||||
# must match the one we render
|
||||
if [[ "$subnet" != "$DOCKER_SUBNET" ]]; then
|
||||
echo "ERROR: the Docker network '$name', left over from a previous NetBird install, uses $subnet instead of $DOCKER_SUBNET." > /dev/stderr
|
||||
echo "docker compose would reuse it as-is, and the generated configuration would not match it." > /dev/stderr
|
||||
echo "Remove it and run this script again:" > /dev/stderr
|
||||
echo " docker network rm $name" > /dev/stderr
|
||||
exit 1
|
||||
fi
|
||||
elif cidrs_overlap "$DOCKER_SUBNET" "$subnet"; then
|
||||
echo "ERROR: the existing Docker network '$name' ($subnet) overlaps $DOCKER_SUBNET, the subnet NetBird would use." > /dev/stderr
|
||||
echo "That network is not managed by this script and is left untouched." > /dev/stderr
|
||||
echo "Pick a free /24 for NetBird instead and run this script again:" > /dev/stderr
|
||||
echo " NETBIRD_DOCKER_SUBNET=10.123.45.0/24 ./getting-started-enterprise.sh" > /dev/stderr
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
done < <(docker network inspect --format '{{.Name}}|{{range .IPAM.Config}}{{.Subnet}} {{end}}' $(docker network ls -q 2>/dev/null) 2>/dev/null || true)
|
||||
return 0
|
||||
}
|
||||
|
||||
check_nb_domain() {
|
||||
local domain="$1"
|
||||
if [[ -z "$domain" ]]; then
|
||||
@@ -224,6 +311,9 @@ wait_postgres() {
|
||||
init_environment() {
|
||||
check_openssl
|
||||
DOCKER_COMPOSE_COMMAND=$(check_docker_compose)
|
||||
# Settle the subnet (and fail on conflicts) before the EULA and prompts
|
||||
apply_docker_subnet_override
|
||||
check_docker_subnet_conflicts "netbird"
|
||||
|
||||
if [[ -f .env ]] || [[ -f docker-compose.yml ]] || [[ -f config.yaml ]]; then
|
||||
echo "Generated files already exist in $(pwd)."
|
||||
@@ -272,6 +362,7 @@ init_environment() {
|
||||
echo " Traffic flow: ${NETBIRD_TRAFFIC_FLOW}"
|
||||
echo " Domain: ${NETBIRD_DOMAIN}"
|
||||
echo " ACME email: ${NETBIRD_LETSENCRYPT_EMAIL}"
|
||||
echo " Subnet: ${DOCKER_SUBNET} (Traefik at ${TRAEFIK_IP})"
|
||||
echo ""
|
||||
echo "Rendering files into $(pwd) ..."
|
||||
install -m 600 /dev/null .env
|
||||
@@ -333,7 +424,12 @@ NETBIRD_DOMAIN=${NETBIRD_DOMAIN}
|
||||
# Reverse proxy (Traefik)
|
||||
NETBIRD_LETSENCRYPT_EMAIL=${NETBIRD_LETSENCRYPT_EMAIL}
|
||||
NETBIRD_TRAEFIK_TAG=${NETBIRD_TRAEFIK_TAG:-v3.6}
|
||||
# These three must stay in step with the /32 trust pins in config.yaml
|
||||
# (reverseProxy.trustedPeers/trustedHTTPProxies). Shell env vars override
|
||||
# this file at compose time.
|
||||
NETBIRD_TRAEFIK_IP=${TRAEFIK_IP}
|
||||
NETBIRD_NETWORK_SUBNET=${DOCKER_SUBNET}
|
||||
NETBIRD_NETWORK_GATEWAY=${DOCKER_GATEWAY}
|
||||
|
||||
# Image tags. Default to "latest"
|
||||
NETBIRD_DASHBOARD_TAG=${NETBIRD_DASHBOARD_TAG:-latest}
|
||||
@@ -416,6 +512,9 @@ render_compose_common() {
|
||||
networks:
|
||||
netbird:
|
||||
ipv4_address: ${NETBIRD_TRAEFIK_IP}
|
||||
# Resolve the public domain inside this network (avoids hairpin NAT)
|
||||
aliases:
|
||||
- "${NETBIRD_DOMAIN}"
|
||||
command:
|
||||
# Logging
|
||||
- "--log.level=INFO"
|
||||
@@ -659,8 +758,8 @@ networks:
|
||||
driver: bridge
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 172.30.0.0/24
|
||||
gateway: 172.30.0.1
|
||||
- subnet: ${NETBIRD_NETWORK_SUBNET}
|
||||
gateway: ${NETBIRD_NETWORK_GATEWAY}
|
||||
EOF
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user