Add IP and pasted certificate support
This commit is contained in:
+97
-12
@@ -101,6 +101,38 @@ validate_domain() {
|
||||
[[ "$1" =~ ^[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?)*\.[a-zA-Z]{2,}$ ]]
|
||||
}
|
||||
|
||||
validate_ipv4() {
|
||||
local IFS=.
|
||||
local octet
|
||||
local -a octets
|
||||
|
||||
read -ra octets <<< "$1"
|
||||
[[ "${#octets[@]}" -eq 4 ]] || return 1
|
||||
|
||||
for octet in "${octets[@]}"; do
|
||||
[[ "$octet" =~ ^[0-9]+$ ]] || return 1
|
||||
(( octet >= 0 && octet <= 255 )) || return 1
|
||||
done
|
||||
}
|
||||
|
||||
validate_domain_or_ip() {
|
||||
validate_domain "$1" || validate_ipv4 "$1"
|
||||
}
|
||||
|
||||
read_multiline_block() {
|
||||
# read_multiline_block <var_name> <prompt> [terminator]
|
||||
local var="$1" prompt="$2" terminator="${3:-END}"
|
||||
local line block=""
|
||||
|
||||
echo -e "${BOLD}${prompt}${RESET}"
|
||||
echo " Paste the content below. Finish with a line containing only: ${terminator}"
|
||||
while IFS= read -r line; do
|
||||
[[ "$line" == "$terminator" ]] && break
|
||||
block+="$line"$'\n'
|
||||
done
|
||||
printf -v "$var" '%s' "$block"
|
||||
}
|
||||
|
||||
# ── Arg parsing ───────────────────────────────────────────────────────────────
|
||||
DRY_RUN=false
|
||||
OUTPUT_DIR="."
|
||||
@@ -120,9 +152,9 @@ mkdir -p "$OUTPUT_DIR"
|
||||
|
||||
# ── Banner ────────────────────────────────────────────────────────────────────
|
||||
echo -e "${BOLD}${CYAN}"
|
||||
echo "╔══════════════════════════════════════════════════════════╗"
|
||||
echo "║ NetBird External Relay Server Setup Wizard ║"
|
||||
echo "╚══════════════════════════════════════════════════════════╝${RESET}"
|
||||
echo "============================================================"
|
||||
echo " NetBird External Relay Server Setup Wizard"
|
||||
echo "============================================================${RESET}"
|
||||
echo ""
|
||||
echo "This script generates relay.env and docker-compose.yml"
|
||||
echo "for one or more NetBird relay servers."
|
||||
@@ -210,9 +242,9 @@ for (( i=1; i<=RELAY_COUNT; i++ )); do
|
||||
|
||||
# ── Domain ────────────────────────────────────────────────────────────────
|
||||
while true; do
|
||||
ask DOMAIN " Domain name (e.g. relay-us.example.com)" "${EX_DOMAIN}"
|
||||
if validate_domain "$DOMAIN"; then break
|
||||
else warn " That doesn't look like a valid domain. Try again."; fi
|
||||
ask DOMAIN " Domain name or IP (e.g. relay-us.example.com / 203.0.113.10)" "${EX_DOMAIN}"
|
||||
if validate_domain_or_ip "$DOMAIN"; then break
|
||||
else warn " That doesn't look like a valid domain or IPv4 address. Try again."; fi
|
||||
done
|
||||
RELAY_DOMAINS+=("$DOMAIN")
|
||||
|
||||
@@ -237,7 +269,14 @@ for (( i=1; i<=RELAY_COUNT; i++ )); do
|
||||
echo " 1) Let's Encrypt (automatic — server needs port 80/tcp open)"
|
||||
echo " 2) Existing certificates (wildcard / own CA)"
|
||||
echo " 3) Self-signed certificate (generated by this script)"
|
||||
ask TLS_MODE " Choose [1/2/3]" "${EX_TLS_MODE:-1}"
|
||||
echo " 4) Paste certificate and private key"
|
||||
ask TLS_MODE " Choose [1/2/3/4]" "${EX_TLS_MODE:-1}"
|
||||
|
||||
if [[ "$TLS_MODE" == "1" ]] && validate_ipv4 "$DOMAIN"; then
|
||||
warn " Let's Encrypt does not issue certificates for raw IP addresses."
|
||||
warn " Choose mode 2, 3, or 4 for IP-based deployments."
|
||||
ask TLS_MODE " Re-choose TLS mode [2/3/4]" "3"
|
||||
fi
|
||||
|
||||
if [[ "$TLS_MODE" == "1" ]]; then
|
||||
ask LE_EMAIL " Let's Encrypt email" "${EX_LE_EMAIL}"
|
||||
@@ -255,6 +294,15 @@ for (( i=1; i<=RELAY_COUNT; i++ )); do
|
||||
ask CERT_FILE " Cert file path inside container" "${EX_CERT_FILE:-/certs/fullchain.pem}"
|
||||
ask KEY_FILE " Key file path inside container" "${EX_KEY_FILE:-/certs/privkey.pem}"
|
||||
LE_EMAIL=""; LE_DATA_DIR=""
|
||||
elif [[ "$TLS_MODE" == "4" ]]; then
|
||||
echo ""
|
||||
echo " ── Pasted certificate details ──"
|
||||
CERT_HOST_PATH="${RELAY_DIR}/certs"
|
||||
CERT_FILE="/certs/fullchain.pem"
|
||||
KEY_FILE="/certs/privkey.pem"
|
||||
LE_EMAIL=""; LE_DATA_DIR=""
|
||||
read_multiline_block PASTED_CERT " Paste the certificate PEM" "END_CERT"
|
||||
read_multiline_block PASTED_KEY " Paste the private key PEM" "END_KEY"
|
||||
else
|
||||
echo ""
|
||||
echo " ── Self-signed certificate details ──"
|
||||
@@ -266,10 +314,18 @@ for (( i=1; i<=RELAY_COUNT; i++ )); do
|
||||
ask SS_ST " State / Province (ST)" ""
|
||||
ask SS_L " Locality / City (L)" ""
|
||||
|
||||
SS_SANS="DNS:${DOMAIN}"
|
||||
if validate_ipv4 "$DOMAIN"; then
|
||||
SS_SANS="IP:${DOMAIN}"
|
||||
else
|
||||
SS_SANS="DNS:${DOMAIN}"
|
||||
fi
|
||||
echo ""
|
||||
echo " Subject Alternative Names (SANs):"
|
||||
echo " DNS:${DOMAIN} is included automatically."
|
||||
if validate_ipv4 "$DOMAIN"; then
|
||||
echo " IP:${DOMAIN} is included automatically."
|
||||
else
|
||||
echo " DNS:${DOMAIN} is included automatically."
|
||||
fi
|
||||
echo " Add extra SANs one by one (IP:x.x.x.x or DNS:other.example.com)."
|
||||
echo " Press Enter on an empty line when done."
|
||||
while true; do
|
||||
@@ -318,14 +374,22 @@ for (( i=1; i<=RELAY_COUNT; i++ )); do
|
||||
KEY_FILE="/certs/privkey.pem"
|
||||
LE_EMAIL=""; LE_DATA_DIR=""
|
||||
fi
|
||||
# For self-signed mode, certs live inside the relay dir
|
||||
[[ "$TLS_MODE" == "3" ]] && CERT_HOST_PATH="${RELAY_DIR}/certs"
|
||||
# For generated or pasted certs, certs live inside the relay dir
|
||||
[[ "$TLS_MODE" == "3" || "$TLS_MODE" == "4" ]] && CERT_HOST_PATH="${RELAY_DIR}/certs"
|
||||
RELAY_DIRS+=("$RELAY_DIR")
|
||||
RELAY_LISTEN_PORTS+=("$LISTEN_PORT")
|
||||
RELAY_STUN_PORTS_LIST+=("$STUN_PORTS")
|
||||
RELAY_TLS_MODES+=("$TLS_MODE")
|
||||
RELAY_ENABLE_STUN+=("$ENABLE_STUN")
|
||||
|
||||
if [[ "$TLS_MODE" == "3" ]]; then
|
||||
TLS_LABEL="Self-signed certificate"
|
||||
elif [[ "$TLS_MODE" == "4" ]]; then
|
||||
TLS_LABEL="Pasted certificate"
|
||||
else
|
||||
TLS_LABEL="Existing certificates"
|
||||
fi
|
||||
|
||||
# ── Build relay.env ───────────────────────────────────────────────────────
|
||||
ENV_FILE="${RELAY_DIR}/relay.env"
|
||||
COMPOSE_FILE="${RELAY_DIR}/docker-compose.yml"
|
||||
@@ -349,7 +413,7 @@ NB_LETSENCRYPT_DATA_DIR=${LE_DATA_DIR}
|
||||
"
|
||||
else
|
||||
ENV_CONTENT+="
|
||||
# TLS — $([ "$TLS_MODE" == "3" ] && echo "Self-signed certificate" || echo "Existing certificates")
|
||||
# TLS — ${TLS_LABEL}
|
||||
NB_TLS_CERT_FILE=${CERT_FILE}
|
||||
NB_TLS_KEY_FILE=${KEY_FILE}
|
||||
"
|
||||
@@ -442,6 +506,18 @@ volumes:
|
||||
echo " -subj \"${SS_SUBJ}\" \\"
|
||||
echo " -addext \"subjectAltName=${SS_SANS}\""
|
||||
fi
|
||||
if [[ "$TLS_MODE" == "4" ]]; then
|
||||
echo ""
|
||||
echo -e "${BOLD}▶ Pasted certificate (would write):${RESET}"
|
||||
echo "────────────────────────────────────────"
|
||||
echo "mkdir -p ${CERT_HOST_PATH}"
|
||||
echo "cat > ${CERT_HOST_PATH}/fullchain.pem <<'EOF_CERT'"
|
||||
echo "$PASTED_CERT"
|
||||
echo "EOF_CERT"
|
||||
echo "cat > ${CERT_HOST_PATH}/privkey.pem <<'EOF_KEY'"
|
||||
echo "$PASTED_KEY"
|
||||
echo "EOF_KEY"
|
||||
fi
|
||||
else
|
||||
mkdir -p "$RELAY_DIR"
|
||||
printf '%s' "$ENV_CONTENT" > "$ENV_FILE"
|
||||
@@ -492,6 +568,15 @@ volumes:
|
||||
info " SANs : ${SS_SANS}"
|
||||
info " Valid for : ${SS_DAYS} days"
|
||||
fi
|
||||
if [[ "$TLS_MODE" == "4" ]]; then
|
||||
info " Writing pasted certificate ..."
|
||||
mkdir -p "${CERT_HOST_PATH}"
|
||||
printf '%s' "${PASTED_CERT}" > "${CERT_HOST_PATH}/fullchain.pem"
|
||||
printf '%s' "${PASTED_KEY}" > "${CERT_HOST_PATH}/privkey.pem"
|
||||
chmod 600 "${CERT_HOST_PATH}/privkey.pem"
|
||||
success " Certificate : ${CERT_HOST_PATH}/fullchain.pem"
|
||||
success " Private key : ${CERT_HOST_PATH}/privkey.pem"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
Reference in New Issue
Block a user