220 lines
8.4 KiB
Bash
220 lines
8.4 KiB
Bash
#!/usr/bin/env bash
|
|
# PlayBull Homelab-Installer — Ziel: ~/bestewebsite/bestewebsite
|
|
# DuckDNS + playbull.service + Cloudflare Tunnel (cloudflared service install)
|
|
set -euo pipefail
|
|
|
|
if [[ "${EUID}" -ne 0 ]]; then
|
|
echo "Bitte als root ausfuehren: sudo bash deploy/install-homelab.sh" >&2
|
|
exit 1
|
|
fi
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
|
|
|
if [[ ! -f "${SCRIPT_DIR}/env.homelab" ]]; then
|
|
cp "${SCRIPT_DIR}/env.homelab.example" "${SCRIPT_DIR}/env.homelab"
|
|
echo "deploy/env.homelab erstellt — Token eintragen und erneut starten." >&2
|
|
exit 1
|
|
fi
|
|
|
|
# shellcheck source=/dev/null
|
|
source <(sed 's/\r$//' "${SCRIPT_DIR}/env.homelab")
|
|
|
|
APP_PORT="${APP_PORT:-3080}"
|
|
APP_DIR="${APP_DIR:-/home/gizzler/bestewebsite/bestewebsite}"
|
|
APP_DIR="${APP_DIR//$'\r'/}"
|
|
APP_USER="${APP_USER:-gizzler}"
|
|
APP_USER="${APP_USER//$'\r'/}"
|
|
DUCKDNS_DOMAIN="${DUCKDNS_DOMAIN:-}"
|
|
DUCKDNS_DOMAIN="${DUCKDNS_DOMAIN//$'\r'/}"
|
|
DUCKDNS_TOKEN="${DUCKDNS_TOKEN:-}"
|
|
DUCKDNS_TOKEN="${DUCKDNS_TOKEN//$'\r'/}"
|
|
APP_DOMAIN="${APP_DOMAIN:-trilogyhub.de}"
|
|
APP_DOMAIN="${APP_DOMAIN//$'\r'/}"
|
|
CLOUDFLARE_API_TOKEN="${CLOUDFLARE_API_TOKEN:-}"
|
|
CLOUDFLARE_API_TOKEN="${CLOUDFLARE_API_TOKEN//$'\r'/}"
|
|
CLOUDFLARE_ZONE_ID="${CLOUDFLARE_ZONE_ID:-}"
|
|
CLOUDFLARE_ZONE_ID="${CLOUDFLARE_ZONE_ID//$'\r'/}"
|
|
CLOUDFLARE_TUNNEL_TOKEN="${CLOUDFLARE_TUNNEL_TOKEN:-}"
|
|
CLOUDFLARE_TUNNEL_TOKEN="${CLOUDFLARE_TUNNEL_TOKEN//$'\r'/}"
|
|
JWT_SECRET="${JWT_SECRET:-}"
|
|
JWT_SECRET="${JWT_SECRET//$'\r'/}"
|
|
FINNHUB_API_KEY="${FINNHUB_API_KEY:-}"
|
|
FINNHUB_API_KEY="${FINNHUB_API_KEY//$'\r'/}"
|
|
|
|
echo "==> PlayBull / Trilogy Hub Homelab Setup"
|
|
echo " Domain: ${APP_DOMAIN}"
|
|
echo " Port: ${APP_PORT}"
|
|
echo " Pfad: ${APP_DIR}"
|
|
echo ""
|
|
|
|
install_unit() {
|
|
local src="$1" dest="$2"
|
|
sed -e "s|__APP_DIR__|${APP_DIR}|g" \
|
|
-e "s|__APP_USER__|${APP_USER}|g" \
|
|
"${src}" > "${dest}"
|
|
}
|
|
|
|
need_pkg() { command -v "$1" >/dev/null 2>&1; }
|
|
|
|
if [[ "${SKIP_APT:-0}" != "1" ]] && command -v apt-get >/dev/null 2>&1; then
|
|
echo "==> Paketlisten aktualisieren..."
|
|
apt-get update -qq
|
|
PKGS=(curl ca-certificates rsync build-essential libvips-dev)
|
|
MISSING=()
|
|
for p in "${PKGS[@]}"; do need_pkg "$p" || MISSING+=("$p"); done
|
|
if ((${#MISSING[@]})); then
|
|
apt-get install -y "${MISSING[@]}"
|
|
fi
|
|
elif [[ "${SKIP_APT:-0}" != "1" ]] && command -v dnf >/dev/null 2>&1; then
|
|
dnf install -y curl ca-certificates rsync gcc-c++ make vips-devel
|
|
fi
|
|
|
|
if ! command -v cloudflared >/dev/null 2>&1; then
|
|
echo "==> cloudflared installieren"
|
|
ARCH="$(uname -m)"
|
|
case "${ARCH}" in
|
|
x86_64) CF_ARCH=amd64 ;;
|
|
aarch64|arm64) CF_ARCH=arm64 ;;
|
|
*) echo "Unsupported arch: ${ARCH}" >&2; exit 1 ;;
|
|
esac
|
|
curl -fsSL "https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-${CF_ARCH}" \
|
|
-o /usr/local/bin/cloudflared
|
|
chmod +x /usr/local/bin/cloudflared
|
|
ln -sf /usr/local/bin/cloudflared /usr/bin/cloudflared
|
|
fi
|
|
|
|
if ! command -v node >/dev/null 2>&1 || [[ "$(node -p "process.versions.node.split('.')[0]")" -lt 24 ]]; then
|
|
echo "==> Node.js 24 installieren (NodeSource)"
|
|
if command -v apt-get >/dev/null 2>&1; then
|
|
curl -fsSL https://deb.nodesource.com/setup_24.x | bash -
|
|
apt-get install -y nodejs
|
|
else
|
|
dnf install -y nodejs
|
|
fi
|
|
fi
|
|
|
|
mkdir -p "${APP_DIR}" "${APP_DIR}/data" "${APP_DIR}/public/uploads"
|
|
if [[ "${REPO_ROOT}" != "${APP_DIR}" ]]; then
|
|
echo "==> Dateien nach ${APP_DIR} synchronisieren"
|
|
rsync -a --delete \
|
|
--exclude node_modules \
|
|
--exclude data \
|
|
--exclude .git \
|
|
--exclude server.js \
|
|
--exclude server.py \
|
|
--exclude start.bat \
|
|
"${REPO_ROOT}/" "${APP_DIR}/"
|
|
fi
|
|
|
|
chown -R "${APP_USER}:${APP_USER}" "${APP_DIR}" 2>/dev/null || true
|
|
chmod +x "${APP_DIR}/deploy/duckdns-update.sh" \
|
|
"${APP_DIR}/deploy/cloudflare-ddns-update.sh" \
|
|
"${APP_DIR}/deploy/finish-on-server.sh" \
|
|
"${APP_DIR}/deploy/sync-user.sh" 2>/dev/null || true
|
|
|
|
# ---- .env (nur ergaenzen, nicht ueberschreiben) ----
|
|
ENV_FILE="${APP_DIR}/.env"
|
|
touch "${ENV_FILE}"
|
|
grep -q '^PORT=' "${ENV_FILE}" 2>/dev/null \
|
|
&& sed -i "s/^PORT=.*/PORT=${APP_PORT}/" "${ENV_FILE}" \
|
|
|| echo "PORT=${APP_PORT}" >> "${ENV_FILE}"
|
|
grep -q '^TRUST_PROXY=' "${ENV_FILE}" 2>/dev/null || echo "TRUST_PROXY=1" >> "${ENV_FILE}"
|
|
grep -q '^START_BALANCE=' "${ENV_FILE}" 2>/dev/null || echo "START_BALANCE=10000" >> "${ENV_FILE}"
|
|
grep -q '^JWT_SECRET=' "${ENV_FILE}" 2>/dev/null || { [[ -n "${JWT_SECRET:-}" ]] && echo "JWT_SECRET=${JWT_SECRET}" >> "${ENV_FILE}"; }
|
|
grep -q '^FINNHUB_API_KEY=' "${ENV_FILE}" 2>/dev/null || { [[ -n "${FINNHUB_API_KEY:-}" ]] && echo "FINNHUB_API_KEY=${FINNHUB_API_KEY}" >> "${ENV_FILE}"; }
|
|
|
|
if [[ "${APP_USER}" == "root" ]]; then
|
|
bash -c "cd '${APP_DIR}' && npm install --omit=dev"
|
|
else
|
|
sudo -u "${APP_USER}" bash -c "cd '${APP_DIR}' && npm install --omit=dev"
|
|
fi
|
|
|
|
# ---- Alten bestewebsite-Service abloesen ----
|
|
if systemctl is-active --quiet bestewebsite.service 2>/dev/null; then
|
|
echo "==> bestewebsite.service stoppen (Migration zu playbull)"
|
|
systemctl stop bestewebsite.service
|
|
fi
|
|
systemctl disable bestewebsite.service 2>/dev/null || true
|
|
|
|
# ---- Cloudflare Tunnel (wie bestewebsite: cloudflared service install) ----
|
|
if [[ -n "${CLOUDFLARE_TUNNEL_TOKEN:-}" ]]; then
|
|
echo "==> Cloudflare Tunnel"
|
|
systemctl stop cloudflared-playbull.service 2>/dev/null || true
|
|
systemctl disable cloudflared-playbull.service 2>/dev/null || true
|
|
cloudflared service uninstall 2>/dev/null || true
|
|
cloudflared service install "${CLOUDFLARE_TUNNEL_TOKEN}"
|
|
systemctl enable cloudflared
|
|
systemctl restart cloudflared || echo " Hinweis: cloudflared Neustart uebersprungen (laeuft evtl. schon)."
|
|
echo " cloudflared konfiguriert."
|
|
else
|
|
echo ""
|
|
echo ">>> CLOUDFLARE_TUNNEL_TOKEN fehlt in deploy/env.homelab"
|
|
echo " Zero Trust → Tunnel → Public Hostname: ${APP_DOMAIN} -> http://127.0.0.1:${APP_PORT}"
|
|
echo ""
|
|
fi
|
|
|
|
# ---- Cloudflare Dynamic DNS (ersetzt DuckDNS) ----
|
|
echo "==> Cloudflare DDNS Timer"
|
|
install_unit "${APP_DIR}/deploy/systemd/cloudflare-ddns-update.service" /etc/systemd/system/cloudflare-ddns-update.service
|
|
cp "${APP_DIR}/deploy/systemd/cloudflare-ddns-update.timer" /etc/systemd/system/
|
|
chmod 600 "${APP_DIR}/deploy/env.homelab"
|
|
if [[ -n "${CLOUDFLARE_API_TOKEN:-}" && -n "${CLOUDFLARE_ZONE_ID:-}" ]]; then
|
|
"${APP_DIR}/deploy/cloudflare-ddns-update.sh" || echo " Cloudflare-DDNS fehlgeschlagen (API/Zone pruefen)"
|
|
else
|
|
echo " Cloudflare-DDNS uebersprungen (CLOUDFLARE_API_TOKEN oder ZONE_ID leer)"
|
|
fi
|
|
|
|
# ---- DuckDNS (legacy, optional) ----
|
|
if [[ -n "${DUCKDNS_TOKEN:-}" ]]; then
|
|
echo "==> DuckDNS (legacy)"
|
|
install_unit "${APP_DIR}/deploy/systemd/duckdns-update.service" /etc/systemd/system/duckdns-update.service
|
|
cp "${APP_DIR}/deploy/systemd/duckdns-update.timer" /etc/systemd/system/
|
|
"${APP_DIR}/deploy/duckdns-update.sh" || true
|
|
fi
|
|
|
|
# ---- playbull systemd ----
|
|
echo "==> playbull.service"
|
|
install_unit "${APP_DIR}/deploy/systemd/playbull.service" /etc/systemd/system/playbull.service
|
|
|
|
systemctl daemon-reload
|
|
if [[ -n "${CLOUDFLARE_API_TOKEN:-}" && -n "${CLOUDFLARE_ZONE_ID:-}" ]]; then
|
|
systemctl enable --now cloudflare-ddns-update.timer
|
|
systemctl start cloudflare-ddns-update.service || true
|
|
else
|
|
systemctl disable cloudflare-ddns-update.timer 2>/dev/null || true
|
|
fi
|
|
if [[ -n "${DUCKDNS_TOKEN:-}" ]]; then
|
|
systemctl enable --now duckdns-update.timer
|
|
systemctl start duckdns-update.service || true
|
|
else
|
|
systemctl disable duckdns-update.timer 2>/dev/null || true
|
|
fi
|
|
systemctl enable --now playbull.service
|
|
systemctl restart playbull.service
|
|
|
|
# ---- Optional Nginx ----
|
|
if [[ "${USE_NGINX_VHOST:-0}" == "1" ]]; then
|
|
echo "==> Nginx VHost (optional)"
|
|
if command -v apt-get >/dev/null 2>&1; then
|
|
apt-get install -y nginx certbot python3-certbot-nginx
|
|
fi
|
|
cp "${APP_DIR}/deploy/nginx/playbull.conf" /etc/nginx/sites-available/playbull
|
|
ln -sf /etc/nginx/sites-available/playbull /etc/nginx/sites-enabled/playbull
|
|
certbot --nginx -d "${APP_DOMAIN}" -d "www.${APP_DOMAIN}" --non-interactive --agree-tos -m "admin@${APP_DOMAIN}" || true
|
|
nginx -t && systemctl reload nginx
|
|
fi
|
|
|
|
echo ""
|
|
echo "=== Fertig ==="
|
|
echo "Pfad: ${APP_DIR}"
|
|
echo "Intern: http://127.0.0.1:${APP_PORT}"
|
|
echo "DuckDNS: ${DUCKDNS_DOMAIN:-(deaktiviert)}"
|
|
echo "Status: systemctl status playbull cloudflared cloudflare-ddns-update.timer"
|
|
if [[ -n "${CLOUDFLARE_TUNNEL_TOKEN:-}" ]]; then
|
|
echo "HTTPS: https://${APP_DOMAIN}"
|
|
fi
|
|
echo ""
|
|
echo "Hinweis: JWT_SECRET und FINNHUB_API_KEY in ${ENV_FILE} pruefen, dann:"
|
|
echo " sudo systemctl restart playbull"
|