Initial PlayBull release with Trilogy Hub integration.
Includes homelab deploy tooling, image position/zoom manifest persistence, and full trading/casino stack. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
212
deploy/install-homelab.sh
Normal file
212
deploy/install-homelab.sh
Normal file
@@ -0,0 +1,212 @@
|
||||
#!/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//$'\r'/}"
|
||||
DUCKDNS_TOKEN="${DUCKDNS_TOKEN//$'\r'/}"
|
||||
APP_DOMAIN="${APP_DOMAIN:-trilogyhub.de}"
|
||||
APP_DOMAIN="${APP_DOMAIN//$'\r'/}"
|
||||
CLOUDFLARE_API_TOKEN="${CLOUDFLARE_API_TOKEN//$'\r'/}"
|
||||
CLOUDFLARE_ZONE_ID="${CLOUDFLARE_ZONE_ID//$'\r'/}"
|
||||
CLOUDFLARE_TUNNEL_TOKEN="${CLOUDFLARE_TUNNEL_TOKEN//$'\r'/}"
|
||||
JWT_SECRET="${JWT_SECRET//$'\r'/}"
|
||||
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 " cloudflared gestartet."
|
||||
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"
|
||||
Reference in New Issue
Block a user