更新 setup-relay.sh

This commit is contained in:
i
2026-03-18 20:57:54 +08:00
parent 57db6ac82a
commit 753bdc0848
+76 -29
View File
@@ -56,7 +56,38 @@ ask_secret() {
done
}
generate_secret() {
parse_existing_env() {
# parse_existing_env <relay.env path>
# Sets EX_* variables from an existing relay.env file.
local envfile="$1"
[[ -f "$envfile" ]] || return 1
_get() { grep -m1 "^${1}=" "$envfile" 2>/dev/null | cut -d= -f2- || true; }
EX_LOG_LEVEL="$(_get NB_LOG_LEVEL)"
EX_AUTH_SECRET="$(_get NB_AUTH_SECRET)"
EX_LE_EMAIL="$(_get NB_LETSENCRYPT_EMAIL)"
EX_CERT_FILE="$(_get NB_TLS_CERT_FILE)"
EX_KEY_FILE="$(_get NB_TLS_KEY_FILE)"
EX_ENABLE_STUN="$(_get NB_ENABLE_STUN)"
EX_STUN_PORTS="$(_get NB_STUN_PORTS)"
# Parse domain and port from NB_EXPOSED_ADDRESS=rels://domain:port
local exposed; exposed="$(_get NB_EXPOSED_ADDRESS)"
EX_DOMAIN="${exposed#rels://}"; EX_DOMAIN="${EX_DOMAIN%%:*}"
EX_LISTEN_PORT="${exposed##*:}"
# Detect TLS mode
local le_domains; le_domains="$(_get NB_LETSENCRYPT_DOMAINS)"
if [[ -n "$le_domains" ]]; then
EX_TLS_MODE="1"
elif [[ -n "$EX_CERT_FILE" ]]; then
EX_TLS_MODE="2" # could be self-signed, but treat as existing cert
else
EX_TLS_MODE="1" # fallback
fi
}
if command -v openssl &>/dev/null; then
openssl rand -base64 32
else
@@ -104,7 +135,17 @@ header "Step 1 · Authentication Secret"
echo "All relay servers AND your main NetBird server must share the same secret."
echo ""
if ask_yn "Generate a new random secret automatically?" "y"; then
# Try to pre-read an existing secret from /opt/netbird-relay/relay.env
_PREREAD_SECRET=""
if [[ -f "/opt/netbird-relay/relay.env" ]]; then
_PREREAD_SECRET="$(grep -m1 '^NB_AUTH_SECRET=' /opt/netbird-relay/relay.env 2>/dev/null | cut -d= -f2- || true)"
fi
if [[ -n "$_PREREAD_SECRET" ]]; then
info "Found existing secret in /opt/netbird-relay/relay.env"
ask AUTH_SECRET "Keep existing secret or enter a new one" "$_PREREAD_SECRET"
success "Using secret."
elif ask_yn "Generate a new random secret automatically?" "y"; then
AUTH_SECRET="$(generate_secret)"
success "Generated secret: ${BOLD}${AUTH_SECRET}${RESET}"
warn "Save this — you'll need it for every relay and your main server config."
@@ -136,23 +177,36 @@ for (( i=1; i<=RELAY_COUNT; i++ )); do
header "Step 3.$i · Relay Server #${i}"
# ── Output directory (ask first so we can read existing config) ───────────
ask RELAY_DIR " Output directory for this relay's files" "/opt/netbird-relay"
# ── Load existing config as defaults if relay.env is present ─────────────
EX_DOMAIN=""; EX_LISTEN_PORT="443"; EX_LOG_LEVEL="info"
EX_AUTH_SECRET=""; EX_LE_EMAIL=""; EX_CERT_FILE=""; EX_KEY_FILE=""
EX_ENABLE_STUN="true"; EX_STUN_PORTS="3478"; EX_TLS_MODE="1"
_EXISTING_ENV="${RELAY_DIR}/relay.env"
if parse_existing_env "$_EXISTING_ENV"; then
info " Found existing config in ${_EXISTING_ENV} — using as defaults."
fi
# ── Domain ────────────────────────────────────────────────────────────────
while true; do
ask DOMAIN " Domain name (e.g. relay-us.example.com)" ""
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
done
RELAY_DOMAINS+=("$DOMAIN")
# ── Listen & exposed ports ────────────────────────────────────────────────
ask LISTEN_PORT " HTTPS listen port" "443"
ask LOG_LEVEL " Log level (debug/info/warn/error)" "info"
ask LISTEN_PORT " HTTPS listen port" "${EX_LISTEN_PORT:-443}"
ask LOG_LEVEL " Log level (debug/info/warn/error)" "${EX_LOG_LEVEL:-info}"
# ── STUN ──────────────────────────────────────────────────────────────────
echo ""
if ask_yn " Enable embedded STUN server?" "y"; then
_STUN_DEFAULT="y"; [[ "${EX_ENABLE_STUN}" == "false" ]] && _STUN_DEFAULT="n"
if ask_yn " Enable embedded STUN server?" "$_STUN_DEFAULT"; then
ENABLE_STUN=true
ask STUN_PORTS " STUN port(s) — comma-separated for multiple (e.g. 3478,3479)" "3478"
ask STUN_PORTS " STUN port(s) — comma-separated for multiple (e.g. 3478,3479)" "${EX_STUN_PORTS:-3478}"
else
ENABLE_STUN=false
STUN_PORTS=""
@@ -164,22 +218,28 @@ 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]" "1"
ask TLS_MODE " Choose [1/2/3]" "${EX_TLS_MODE:-1}"
if [[ "$TLS_MODE" == "1" ]]; then
ask LE_EMAIL " Let's Encrypt email" ""
ask LE_EMAIL " Let's Encrypt email" "${EX_LE_EMAIL}"
LE_DATA_DIR="/data/letsencrypt"
CERT_HOST_PATH=""; CERT_FILE=""; KEY_FILE=""; SELFSIGN_DAYS=""
CERT_HOST_PATH=""; CERT_FILE=""; KEY_FILE=""
elif [[ "$TLS_MODE" == "2" ]]; then
ask CERT_HOST_PATH " Host path to certs directory" "/opt/1panel/www/sites/${DOMAIN}/ssl"
ask CERT_FILE " Cert file path inside container" "/certs/fullchain.pem"
ask KEY_FILE " Key file path inside container" "/certs/privkey.pem"
LE_EMAIL=""; LE_DATA_DIR=""; SELFSIGN_DAYS=""
# Derive existing host path from cert file path stored in env (best-effort)
_EX_CERT_HOST=""
[[ -n "$EX_CERT_FILE" ]] && _EX_CERT_HOST="$(
grep -m1 'volumes:' -A5 "${RELAY_DIR}/docker-compose.yml" 2>/dev/null \
| grep -m1 ':/certs:ro\|:/certs ' \
| awk -F: '{print $1}' | sed 's/^ *- *//' || true
)"
ask CERT_HOST_PATH " Host path to certs directory" "${_EX_CERT_HOST:-/opt/1panel/www/sites/${DOMAIN}/ssl}"
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=""
else
echo ""
echo " ── Self-signed certificate details ──"
# Subject fields
ask SS_CN " Common Name (CN)" "${DOMAIN}"
ask SS_O " Organization (O)" ""
ask SS_OU " Organizational Unit (OU)" ""
@@ -187,7 +247,6 @@ for (( i=1; i<=RELAY_COUNT; i++ )); do
ask SS_ST " State / Province (ST)" ""
ask SS_L " Locality / City (L)" ""
# SANs — domain always included, allow adding more
SS_SANS="DNS:${DOMAIN}"
echo ""
echo " Subject Alternative Names (SANs):"
@@ -200,10 +259,8 @@ for (( i=1; i<=RELAY_COUNT; i++ )); do
SS_SANS+=",${_san}"
done
# Validity
ask SS_DAYS " Certificate validity (days)" "3650"
# Key type
echo ""
echo " Key type:"
echo " 1) RSA"
@@ -229,7 +286,6 @@ for (( i=1; i<=RELAY_COUNT; i++ )); do
esac
fi
# Build subject string (only include non-empty fields)
SS_SUBJ=""
[[ -n "$SS_C" ]] && SS_SUBJ+="/C=${SS_C}"
[[ -n "$SS_ST" ]] && SS_SUBJ+="/ST=${SS_ST}"
@@ -238,20 +294,11 @@ for (( i=1; i<=RELAY_COUNT; i++ )); do
[[ -n "$SS_OU" ]] && SS_SUBJ+="/OU=${SS_OU}"
SS_SUBJ+="/CN=${SS_CN}"
CERT_HOST_PATH="" # filled in after RELAY_DIR is known
CERT_HOST_PATH=""
CERT_FILE="/certs/fullchain.pem"
KEY_FILE="/certs/privkey.pem"
LE_EMAIL=""; LE_DATA_DIR=""
fi
# ── Output directory ──────────────────────────────────────────────────────
_DEFAULT_RELAY_DIR="/opt/netbird-relay"
# If the default dir already has relay files, surface it as the default so
# the user can confirm with Enter rather than retyping the path.
if [[ -f "${_DEFAULT_RELAY_DIR}/relay.env" || -f "${_DEFAULT_RELAY_DIR}/docker-compose.yml" ]]; then
warn " ${_DEFAULT_RELAY_DIR} already contains relay files (will be overwritten if confirmed)."
fi
ask RELAY_DIR " Output directory for this relay's files" "${_DEFAULT_RELAY_DIR}"
# For self-signed mode, certs live inside the relay dir
[[ "$TLS_MODE" == "3" ]] && CERT_HOST_PATH="${RELAY_DIR}/certs"
RELAY_DIRS+=("$RELAY_DIR")