Server setup: Tailscale address instead of a domain, and a no-questions mode
- setup.sh offers the computer's Tailscale address (HTTPS from tailscale serve, Caddy not started, nothing open to the internet) — docker-compose.tailscale.yml - ANYBOT_SETUP_USER / ANYBOT_SETUP_PASSWORD [/ ANYBOT_SETUP_DOMAIN] answer the questions, for scripts and deployment tools; install.sh server passes them through Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Uirha3oEtWeHh58zA7ErHa
This commit is contained in:
parent
472a004f87
commit
6d6461e4f3
|
|
@ -0,0 +1,9 @@
|
||||||
|
# Tailscale instead of a public domain: only devices in your tailnet reach this server, and
|
||||||
|
# Tailscale gives it HTTPS (`tailscale serve`), so Caddy isn't started and ports 80/443 stay closed.
|
||||||
|
# setup.sh turns this on (COMPOSE_FILE in .env) when you pick 「用 Tailscale」.
|
||||||
|
services:
|
||||||
|
caddy:
|
||||||
|
profiles: ["caddy"]
|
||||||
|
relay:
|
||||||
|
ports:
|
||||||
|
- "127.0.0.1:8780:8080"
|
||||||
|
|
@ -5,10 +5,17 @@
|
||||||
# ./setup.sh --dry-run ask and write the files, but don't start anything
|
# ./setup.sh --dry-run ask and write the files, but don't start anything
|
||||||
#
|
#
|
||||||
# Run it again any time: it offers to keep the current settings (to update and restart).
|
# Run it again any time: it offers to keep the current settings (to update and restart).
|
||||||
|
#
|
||||||
|
# Without questions (scripts, Ansible…): give the answers as environment variables.
|
||||||
|
# ANYBOT_SETUP_USER=me ANYBOT_SETUP_PASSWORD=… ANYBOT_SETUP_DOMAIN=anybot.example.com ./setup.sh
|
||||||
|
# leave out ANYBOT_SETUP_DOMAIN on a computer with Tailscale to use its Tailscale address.
|
||||||
|
# An existing setup is kept (updated and restarted).
|
||||||
set -u
|
set -u
|
||||||
cd "$(dirname "$0")"
|
cd "$(dirname "$0")"
|
||||||
DRY=0
|
DRY=0
|
||||||
[ "${1:-}" = "--dry-run" ] && DRY=1
|
[ "${1:-}" = "--dry-run" ] && DRY=1
|
||||||
|
AUTO=0
|
||||||
|
[ -n "${ANYBOT_SETUP_USER:-}" ] && [ -n "${ANYBOT_SETUP_PASSWORD:-}" ] && AUTO=1
|
||||||
|
|
||||||
# ---------- looks ----------
|
# ---------- looks ----------
|
||||||
if [ -t 1 ]; then
|
if [ -t 1 ]; then
|
||||||
|
|
@ -64,6 +71,8 @@ ask() {
|
||||||
|
|
||||||
# choose VAR "問題" "選項|說明" ... (↑↓ and Enter)
|
# choose VAR "問題" "選項|說明" ... (↑↓ and Enter)
|
||||||
choose() {
|
choose() {
|
||||||
|
# Without questions: the first choice (keep the setup, use Tailscale).
|
||||||
|
if [ "$AUTO" = 1 ]; then printf -v "$1" '%s' 0; return; fi
|
||||||
local __v=$1 title=$2; shift 2
|
local __v=$1 title=$2; shift 2
|
||||||
local opts=("$@") sel=0 n=$# key rest i
|
local opts=("$@") sel=0 n=$# key rest i
|
||||||
while :; do
|
while :; do
|
||||||
|
|
@ -105,7 +114,7 @@ spin() { # spin "做什麼" command… : runs it, shows a spinner and the newest
|
||||||
return $rc
|
return $rc
|
||||||
}
|
}
|
||||||
|
|
||||||
pause() { printf ' %s%s%s' "$D" "${1:-按 Enter 繼續}" "$N"; IFS= read -r _; }
|
pause() { [ "$AUTO" = 1 ] && return; printf ' %s%s%s' "$D" "${1:-按 Enter 繼續}" "$N"; IFS= read -r _; }
|
||||||
die() { card_close; printf '\n'; exit 1; }
|
die() { card_close; printf '\n'; exit 1; }
|
||||||
|
|
||||||
# ---------- 0. this server ----------
|
# ---------- 0. this server ----------
|
||||||
|
|
@ -141,8 +150,20 @@ fi
|
||||||
|
|
||||||
if [ "${SKIP:-0}" != 1 ]; then
|
if [ "${SKIP:-0}" != 1 ]; then
|
||||||
# ---------- 1. the address ----------
|
# ---------- 1. the address ----------
|
||||||
AT=1; MSG=""
|
AT=1; MSG=""; TS=0
|
||||||
while :; do
|
# On a tailnet: offer its address (HTTPS from Tailscale, no domain, nothing open to the internet).
|
||||||
|
TSNAME=$(tailscale status --json 2>/dev/null | sed -n 's/.*"DNSName": *"\([^"]*\)\.".*/\1/p' | head -1)
|
||||||
|
if [ "$AUTO" = 1 ] && [ -n "${ANYBOT_SETUP_DOMAIN:-}" ]; then DOMAIN=${ANYBOT_SETUP_DOMAIN#https://}; TSNAME=""; TS=2; fi
|
||||||
|
if [ "$AUTO" = 1 ] && [ "$TS" = 0 ] && [ -z "$TSNAME" ]; then
|
||||||
|
header; card_open "網址"; bad "這台沒有 Tailscale:請加上 ANYBOT_SETUP_DOMAIN=你的網域"; die
|
||||||
|
fi
|
||||||
|
if [ -n "$TSNAME" ]; then
|
||||||
|
choose HOW "手機和其他電腦用哪個網址連到這台?" \
|
||||||
|
"用 Tailscale:https://$TSNAME|只有你 Tailscale 裡的手機和電腦連得到。不用網域,也不用開 80、443 埠" \
|
||||||
|
"用自己的網域|任何地方都連得到(網域要先指到這台)"
|
||||||
|
if [ "$HOW" = 0 ]; then DOMAIN=$TSNAME; TS=1; fi
|
||||||
|
fi
|
||||||
|
while [ "$TS" = 0 ]; do
|
||||||
header; card_open "手機和其他電腦用哪個網址連到這台?"
|
header; card_open "手機和其他電腦用哪個網址連到這台?"
|
||||||
note "網域要先指到這台伺服器(DNS 的 A 紀錄)。HTTPS 憑證會自動申請、自動更新。"
|
note "網域要先指到這台伺服器(DNS 的 A 紀錄)。HTTPS 憑證會自動申請、自動更新。"
|
||||||
line ""
|
line ""
|
||||||
|
|
@ -164,9 +185,11 @@ if [ "${SKIP:-0}" != 1 ]; then
|
||||||
break
|
break
|
||||||
done
|
done
|
||||||
|
|
||||||
|
[ "$TS" = 2 ] && TS=0
|
||||||
# ---------- 2. the account ----------
|
# ---------- 2. the account ----------
|
||||||
AT=2; MSG=""
|
AT=2; MSG=""
|
||||||
while :; do
|
if [ "$AUTO" = 1 ]; then USERNAME=$ANYBOT_SETUP_USER; PW1=$ANYBOT_SETUP_PASSWORD; BRAIN="雲端大腦"; fi
|
||||||
|
while [ "$AUTO" = 0 ]; do
|
||||||
header; card_open "你的 AnyBot 帳號"
|
header; card_open "你的 AnyBot 帳號"
|
||||||
note "手機、電腦都用這個帳號登入。第一次啟動時會自動建立。"
|
note "手機、電腦都用這個帳號登入。第一次啟動時會自動建立。"
|
||||||
line ""
|
line ""
|
||||||
|
|
@ -199,6 +222,10 @@ if [ "${SKIP:-0}" != 1 ]; then
|
||||||
q ANTHROPIC_API_KEY "$ANT"
|
q ANTHROPIC_API_KEY "$ANT"
|
||||||
q OPENAI_API_KEY "$OAI"
|
q OPENAI_API_KEY "$OAI"
|
||||||
q GEMINI_API_KEY "$GEM"
|
q GEMINI_API_KEY "$GEM"
|
||||||
|
if [ "$TS" = 1 ]; then
|
||||||
|
q ANYBOT_TAILSCALE 1
|
||||||
|
q COMPOSE_FILE "docker-compose.yml:docker-compose.tailscale.yml"
|
||||||
|
fi
|
||||||
} >.env
|
} >.env
|
||||||
chmod 600 .env
|
chmod 600 .env
|
||||||
umask 022
|
umask 022
|
||||||
|
|
@ -223,6 +250,16 @@ if [ -z "${ANYBOT_BUILD_JOBS:-}" ] && [ -r /proc/meminfo ]; then
|
||||||
[ "$mem" -lt 3000 ] && warn "記憶體只有 ${mem} MB:編譯會比較久。被中斷的話先加 2 GB swap(見 docs/install.md)"
|
[ "$mem" -lt 3000 ] && warn "記憶體只有 ${mem} MB:編譯會比較久。被中斷的話先加 2 GB swap(見 docs/install.md)"
|
||||||
fi
|
fi
|
||||||
spin "建置並啟動(第一次約 5–15 分鐘)" docker compose up -d --build || die
|
spin "建置並啟動(第一次約 5–15 分鐘)" docker compose up -d --build || die
|
||||||
|
[ "${ANYBOT_TAILSCALE:-}" = 1 ] && TS=1
|
||||||
|
if [ "${TS:-0}" = 1 ]; then
|
||||||
|
# Tailscale gives the address HTTPS and passes it to the account server (remembered across reboots).
|
||||||
|
if tailscale serve --bg --https=443 http://127.0.0.1:8780 >/dev/null 2>&1 \
|
||||||
|
|| sudo tailscale serve --bg --https=443 http://127.0.0.1:8780 >/dev/null 2>&1; then
|
||||||
|
ok "Tailscale:https://$DOMAIN → 帳號伺服器"
|
||||||
|
else
|
||||||
|
bad "沒辦法設定 tailscale serve。請執行:sudo tailscale serve --bg --https=443 http://127.0.0.1:8780"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# The brain joins the account (and makes it, the first time).
|
# The brain joins the account (and makes it, the first time).
|
||||||
f=0; c=("⠋" "⠙" "⠹" "⠸" "⠼" "⠴" "⠦" "⠧" "⠇" "⠏"); joined=""
|
f=0; c=("⠋" "⠙" "⠹" "⠸" "⠼" "⠴" "⠦" "⠧" "⠇" "⠏"); joined=""
|
||||||
|
|
@ -246,7 +283,9 @@ for _ in $(seq 1 120); do
|
||||||
printf '\r\e[K %s│%s %s%s%s 等 HTTPS 憑證…' "$D" "$N" "$A" "${c[$((f % 10))]}" "$N"; f=$((f + 1)); sleep 1
|
printf '\r\e[K %s│%s %s%s%s 等 HTTPS 憑證…' "$D" "$N" "$A" "${c[$((f % 10))]}" "$N"; f=$((f + 1)); sleep 1
|
||||||
done
|
done
|
||||||
printf '\r\e[K'
|
printf '\r\e[K'
|
||||||
if [ -n "$https" ]; then ok "https://$DOMAIN 可以連"; else warn "https://$DOMAIN 還連不到(DNS 還沒生效,或 80/443 埠被防火牆擋住)。看紀錄:docker compose logs caddy"; fi
|
if [ -n "$https" ]; then ok "https://$DOMAIN 可以連"
|
||||||
|
elif [ "${TS:-0}" = 1 ]; then warn "https://$DOMAIN 還連不到。Tailscale 的 HTTPS 要在管理頁打開(DNS › HTTPS Certificates),看設定:tailscale serve status"
|
||||||
|
else warn "https://$DOMAIN 還連不到(DNS 還沒生效,或 80/443 埠被防火牆擋住)。看紀錄:docker compose logs caddy"; fi
|
||||||
card_close
|
card_close
|
||||||
|
|
||||||
printf '\n'
|
printf '\n'
|
||||||
|
|
|
||||||
|
|
@ -263,9 +263,11 @@ case $MODE in
|
||||||
find_source
|
find_source
|
||||||
step "設定和啟動"
|
step "設定和啟動"
|
||||||
info "接下來會問網域、帳號、密碼。"
|
info "接下來會問網域、帳號、密碼。"
|
||||||
[ -n "$TTY" ] || die "需要一個終端機回答問題。" "在伺服器上直接執行:cd $SRC && ./install.sh server"
|
|
||||||
cd "$SRC/deploy/server"
|
cd "$SRC/deploy/server"
|
||||||
if [ "${DOCKER_SUDO:-0}" = 1 ]; then exec $SUDO -E ./setup.sh "$@" <"$TTY"; else exec ./setup.sh "$@" <"$TTY"; fi
|
IN=$TTY
|
||||||
|
if [ -n "${ANYBOT_SETUP_USER:-}" ] && [ -n "${ANYBOT_SETUP_PASSWORD:-}" ]; then IN=/dev/null # 免問模式
|
||||||
|
else [ -n "$TTY" ] || die "需要一個終端機回答問題。" "在伺服器上直接執行:cd $SRC && ./install.sh server(或用 ANYBOT_SETUP_USER、ANYBOT_SETUP_PASSWORD 免問)"; fi
|
||||||
|
if [ "${DOCKER_SUDO:-0}" = 1 ]; then exec $SUDO -E ./setup.sh "$@" <"$IN"; else exec ./setup.sh "$@" <"$IN"; fi
|
||||||
;;
|
;;
|
||||||
|
|
||||||
app|hands)
|
app|hands)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue