#!/usr/bin/env bash
# Debian 13 VPS: Docker + Dockhand + Nginx Proxy Manager + wg-easy
# + File Browser + The Lounge + Beszel + Homarr
# Usage: sudo bash install-homarr-stack.sh
set -Eeuo pipefail
umask 077

CURRENT_STEP="indulás"
trap 'rc=$?; printf "\n\033[1;31m[HIBA]\033[0m A telepítés megszakadt (lépés: %s, sor: %s, kilépési kód: %s). A korábban létrehozott adatokat a script nem törli.\n" "$CURRENT_STEP" "$LINENO" "$rc" >&2; exit "$rc"' ERR

ROOT_DIR="/opt/docker"
STACK_DIR="${ROOT_DIR}/stack"
ENV_FILE="${STACK_DIR}/.env"
COMPOSE_FILE="${STACK_DIR}/compose.yaml"
TZ_VALUE="Europe/Budapest"

log()  { printf '\n\033[1;32m[INFO]\033[0m %s\n' "$*"; }
warn() { printf '\n\033[1;33m[FIGYELEM]\033[0m %s\n' "$*" >&2; }
die()  { printf '\n\033[1;31m[HIBA]\033[0m %s\n' "$*" >&2; exit 1; }
need_cmd() { command -v "$1" >/dev/null 2>&1 || die "Hiányzó parancs: $1"; }

if [[ "${EUID}" -ne 0 ]]; then
  die "Root jogosultság szükséges. Futtatás: sudo bash $0"
fi

[[ -r /etc/os-release ]] || die "Nem olvasható az /etc/os-release."
# shellcheck disable=SC1091
source /etc/os-release
[[ "${ID:-}" == "debian" && "${VERSION_ID%%.*}" == "13" ]] || \
  die "Ez a telepítő Debian 13-ra készült. Felismert rendszer: ${PRETTY_NAME:-ismeretlen}."
ARCH="$(dpkg --print-architecture)"
case "$ARCH" in
  amd64|arm64|armhf|ppc64el) ;;
  *) die "Nem támogatott Docker-architektúra: $ARCH" ;;
esac

if docker info >/dev/null 2>&1; then
  warn "Már működő Docker daemon található. A telepítő nem töröl meglévő adatot, de a 80/443-as portok ütközhetnek."
fi

printf '\nDebian 13 Docker-stack telepítő\n'
printf 'A telepítés a következő szolgáltatásokat telepíti: Docker, Dockhand, NPM, wg-easy, File Browser, The Lounge, Beszel, Homarr.\n'
printf 'A webes és admin portok publikus interfészen figyelnek; a szolgáltatói tűzfalon csak a szükséges portokat engedélyezd.\n\n'

read -r -p "A WireGuard kliensek által használt publikus IP vagy VPN-domain (pl. 203.0.113.10 vagy vpn.pelda.hu): " WG_HOST
[[ -n "$WG_HOST" ]] || die "A WireGuard publikus IP-címe vagy domainje kötelező."
if [[ "$WG_HOST" =~ [[:space:]] ]]; then die "A WireGuard host nem tartalmazhat szóközt."; fi

read -r -p "Telepítsem és engedélyezzem az OpenSSH-t, ha nincs telepítve? [I/n]: " SSH_ANSWER
SSH_ANSWER="${SSH_ANSWER:-I}"

CURRENT_STEP="alapcsomagok telepítése"
log "Alapcsomagok frissítése és telepítése..."
export DEBIAN_FRONTEND=noninteractive
apt-get update
apt-get install -y ca-certificates curl gnupg openssl jq nano python3 fail2ban unattended-upgrades

timedatectl set-timezone "$TZ_VALUE" || true

if [[ "$SSH_ANSWER" =~ ^([IiyY]|)$ ]]; then
  apt-get install -y openssh-server
  systemctl enable --now ssh
fi

CURRENT_STEP="Docker és Compose telepítése"
log "Docker Engine és Docker Compose telepítése a Docker hivatalos kényelmi telepítőjével..."
# A get.docker.com script telepíti a Docker Engine-t és a Compose plugint.
curl -fsSL https://get.docker.com | sh
systemctl enable --now docker

docker run --rm hello-world >/dev/null
docker compose version >/dev/null

CURRENT_STEP="adatkönyvtárak és hálózat létrehozása"
log "Docker-hálózatok és tartós mappák létrehozása..."
mkdir -p \
  "${STACK_DIR}" \
  "${ROOT_DIR}/npm/data" "${ROOT_DIR}/npm/letsencrypt" \
  "${ROOT_DIR}/dockhand/data" \
  "${ROOT_DIR}/wg-easy" \
  "${ROOT_DIR}/filebrowser/srv" "${ROOT_DIR}/filebrowser/data/tmp" \
  "${ROOT_DIR}/thelounge/config" \
  "${ROOT_DIR}/beszel/data" \
  "${ROOT_DIR}/homarr/appdata"

# FileBrowser Quantum runs as UID/GID 1000. Prepare persistent app data and file root.
chown -R 1000:1000 "${ROOT_DIR}/filebrowser/data" "${ROOT_DIR}/filebrowser/srv"
chmod 711 "${ROOT_DIR}"
chmod 755 "${ROOT_DIR}/filebrowser" "${ROOT_DIR}/filebrowser/data" "${ROOT_DIR}/filebrowser/data/tmp" "${ROOT_DIR}/filebrowser/srv"

# Provide an initial Quantum v2 config only when one does not already exist.
if [[ ! -f "${ROOT_DIR}/filebrowser/data/config.yaml" ]]; then
  cat > "${ROOT_DIR}/filebrowser/data/config.yaml" <<'QUANTUM_CONFIG'
server:
  cacheDir: /home/filebrowser/data/tmp
  sources:
    - path: /srv
      name: Files
      config:
        defaultEnabled: true
QUANTUM_CONFIG
  chown 1000:1000 "${ROOT_DIR}/filebrowser/data/config.yaml"
  chmod 640 "${ROOT_DIR}/filebrowser/data/config.yaml"
fi

docker network inspect proxy >/dev/null 2>&1 || docker network create proxy

# Reuse credentials if rerunning the script; never overwrite existing secrets.
if [[ -f "$ENV_FILE" ]]; then
  warn "Már létező .env fájl található: megtartom a benne lévő titkokat."
  if ! grep -q '^WG_HOST=' "$ENV_FILE"; then printf 'WG_HOST=%s\n' "$WG_HOST" >> "$ENV_FILE"; fi
  if ! grep -q '^TZ=' "$ENV_FILE"; then printf 'TZ=%s\n' "$TZ_VALUE" >> "$ENV_FILE"; fi
  if ! grep -q '^HOMARR_SECRET=' "$ENV_FILE"; then printf 'HOMARR_SECRET=%s\n' "$(openssl rand -hex 32)" >> "$ENV_FILE"; fi
  if ! grep -q '^WG_ADMIN_PASSWORD=' "$ENV_FILE"; then printf 'WG_ADMIN_PASSWORD=%s\n' "$(openssl rand -hex 18)" >> "$ENV_FILE"; fi
else
  cat > "$ENV_FILE" <<EOF
TZ=${TZ_VALUE}
WG_HOST=${WG_HOST}
HOMARR_SECRET=$(openssl rand -hex 32)
WG_ADMIN_PASSWORD=$(openssl rand -hex 18)
EOF
fi
chmod 600 "$ENV_FILE"

# Meglévő Compose-fájlt nem írunk felül: így az újrafuttatás nem törli a kézi módosításokat.
if [[ -e "$COMPOSE_FILE" ]]; then
  warn "Már létezik $COMPOSE_FILE; megtartom, nem írom felül a meglévő stack-konfigurációt."
else
# Escape input for YAML scalar values by using env-file values and quoted interpolation.
cat > "$COMPOSE_FILE" <<'YAML' 
services:
  npm:
    image: jc21/nginx-proxy-manager:latest
    container_name: npm
    restart: unless-stopped
    environment:
      TZ: ${TZ}
    ports:
      - "80:80"
      - "443:443"
      - "81:81"
    volumes:
      - /opt/docker/npm/data:/data
      - /opt/docker/npm/letsencrypt:/etc/letsencrypt
    networks:
      - proxy

  dockhand:
    image: fnsys/dockhand:latest
    container_name: dockhand
    restart: unless-stopped
    ports:
      - "3000:3000"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /opt/docker/dockhand/data:/app/data
      - /opt/docker:/opt/docker
    environment:
      TZ: ${TZ}
    networks:
      - proxy

  wg-easy:
    image: ghcr.io/wg-easy/wg-easy:15
    container_name: wg-easy
    restart: unless-stopped
    environment:
      TZ: ${TZ}
      DISABLE_IPV6: "true"
      INIT_ENABLED: "true"
      INIT_USERNAME: "admin"
      INIT_PASSWORD: ${WG_ADMIN_PASSWORD}
      INIT_HOST: ${WG_HOST}
      INIT_PORT: "51820"
      INIT_DNS: "1.1.1.1,9.9.9.9"
    volumes:
      - /opt/docker/wg-easy:/etc/wireguard
    ports:
      - "51820:51820/udp"
      - "51821:51821/tcp"
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    sysctls:
      net.ipv4.conf.all.src_valid_mark: "1"
    networks:
      - proxy

  filebrowser:
    image: ghcr.io/gtsteffaniak/filebrowser:stable
    container_name: filebrowser
    restart: unless-stopped
    ports:
      - "8080:80"
    volumes:
      - /opt/docker/filebrowser/srv:/srv
      - /opt/docker/filebrowser/data:/home/filebrowser/data
    networks:
      - proxy

  thelounge:
    image: lscr.io/linuxserver/thelounge:latest
    container_name: thelounge
    restart: unless-stopped
    environment:
      PUID: "0"
      PGID: "0"
      TZ: ${TZ}
    volumes:
      - /opt/docker/thelounge/config:/config
    ports:
      - "9000:9000"
      - "113:113/tcp"
    networks:
      - proxy

  beszel:
    image: henrygd/beszel:latest
    container_name: beszel
    restart: unless-stopped
    environment:
      APP_URL: http://${WG_HOST}:8090
      TZ: ${TZ}
    ports:
      - "8090:8090"
    volumes:
      - /opt/docker/beszel/data:/beszel_data
      - /opt/docker/beszel/socket:/beszel_socket
    networks:
      - proxy

  homarr:
    image: ghcr.io/homarr-labs/homarr:latest
    container_name: homarr
    restart: unless-stopped
    environment:
      SECRET_ENCRYPTION_KEY: ${HOMARR_SECRET}
      TZ: ${TZ}
    ports:
      - "7575:7575"
    volumes:
      - /opt/docker/homarr/appdata:/appdata
      - /var/run/docker.sock:/var/run/docker.sock
    networks:
      - proxy

networks:
  proxy:
    external: true
YAML
fi

# Helper: run after creating a system in the Beszel Hub UI and copying its KEY/TOKEN.
cat > "${STACK_DIR}/configure-beszel-agent.sh" <<'AGENT_SCRIPT'
#!/usr/bin/env bash
set -Eeuo pipefail
umask 077

AGENT_DIR="/opt/docker/beszel-agent"
mkdir -p "$AGENT_DIR/data"
read -r -p "Beszel Add System ablakból kimásolt KEY: " BESZEL_KEY
read -r -s -p "Beszel TOKEN (beírás rejtve): " BESZEL_TOKEN
printf '\n'
[[ -n "$BESZEL_KEY" && -n "$BESZEL_TOKEN" ]] || { echo "A KEY és TOKEN kötelező."; exit 1; }
read -r -p "Hub URL [http://127.0.0.1:8090]: " BESZEL_HUB_URL
BESZEL_HUB_URL="${BESZEL_HUB_URL:-http://127.0.0.1:8090}"
cat > "$AGENT_DIR/.env" <<EOF
BESZEL_KEY=$BESZEL_KEY
BESZEL_TOKEN=$BESZEL_TOKEN
BESZEL_HUB_URL=$BESZEL_HUB_URL
EOF
chmod 600 "$AGENT_DIR/.env"
cat > "$AGENT_DIR/compose.yaml" <<'YAML'
services:
  beszel-agent:
    image: henrygd/beszel-agent:latest
    container_name: beszel-agent
    restart: unless-stopped
    network_mode: host
    volumes:
      - /opt/docker/beszel-agent/data:/var/lib/beszel-agent
      - /var/run/docker.sock:/var/run/docker.sock:ro
    environment:
      LISTEN: "45876"
      KEY: ${BESZEL_KEY}
      HUB_URL: ${BESZEL_HUB_URL}
      TOKEN: ${BESZEL_TOKEN}
YAML
cd "$AGENT_DIR"
docker compose --env-file .env -f compose.yaml config -q
docker compose --env-file .env -f compose.yaml up -d
echo
docker ps --filter name=beszel-agent
echo "Agent elindítva. A Beszel Hubban fejezd be az Add System folyamatot."
echo "A szolgáltatói tűzfalon engedélyezd a TCP 45876 portot, ha a Hub nem helyi Unix socketen kapcsolódik."
AGENT_SCRIPT
chmod 700 "${STACK_DIR}/configure-beszel-agent.sh"

CURRENT_STEP="Compose-konfiguráció ellenőrzése"
log "Compose-konfiguráció ellenőrzése..."
cd "$STACK_DIR"
docker compose --env-file "$ENV_FILE" -f "$COMPOSE_FILE" config -q

CURRENT_STEP="konténerek letöltése és indítása"
log "Konténerek letöltése és indítása..."
docker compose --env-file "$ENV_FILE" -f "$COMPOSE_FILE" pull
docker compose --env-file "$ENV_FILE" -f "$COMPOSE_FILE" up -d

log "Várakozás a wg-easy első inicializálására (legfeljebb 90 másodperc)..."
WG_INIT_OK=0
for i in $(seq 1 18); do
  if docker logs wg-easy 2>&1 | grep -q 'Wireguard Interface wg0 started successfully'; then
    WG_INIT_OK=1
    break
  fi
  if [[ "$(docker inspect -f '{{.State.Status}}' wg-easy 2>/dev/null || true)" == "exited" ]]; then
    break
  fi
  sleep 5
done

# Remove one-time bootstrap credentials only after wg-easy confirms successful initialization.
if [[ "$WG_INIT_OK" -eq 1 ]] && grep -q 'INIT_ENABLED:' "$COMPOSE_FILE"; then
  python3 - "$COMPOSE_FILE" <<'PY'
from pathlib import Path
import sys
p = Path(sys.argv[1])
s = p.read_text()
lines = []
for line in s.splitlines(True):
    if any(x in line for x in ("INIT_ENABLED:", "INIT_USERNAME:", "INIT_PASSWORD:", "INIT_HOST:", "INIT_PORT:", "INIT_DNS:")):
        continue
    lines.append(line)
p.write_text("".join(lines))
PY
  # The bootstrap password remains in wg-easy's database; recreate without one-time secrets.
  docker compose --env-file "$ENV_FILE" -f "$COMPOSE_FILE" up -d --force-recreate wg-easy
else
  warn "A wg-easy inicializálását nem sikerült megerősíteni. Az INIT_* beállításokat megtartottam, hogy a hiba diagnosztizálható legyen."
fi

log "Várakozás az alkalmazások indulására (legfeljebb 90 másodperc)..."
for i in $(seq 1 18); do
  wg_state="$(docker inspect -f '{{.State.Health.Status}}' wg-easy 2>/dev/null || true)"
  fb_state="$(docker inspect -f '{{.State.Health.Status}}' filebrowser 2>/dev/null || true)"
  if [[ "$wg_state" == "healthy" && "$fb_state" == "healthy" ]]; then break; fi
  sleep 5
done

log "Konténerek indulásának ellenőrzése..."
SERVICES=(npm dockhand wg-easy filebrowser thelounge beszel homarr)
FAILED_CONTAINERS=()
for service in "${SERVICES[@]}"; do
  printf '  %-14s' "$service"
  state="$(docker inspect -f '{{.State.Status}}' "$service" 2>/dev/null || true)"
  if [[ "$state" == "running" ]]; then
    printf '\033[1;32mRUNNING\033[0m\n'
  else
    printf '\033[1;31m%s\033[0m\n' "${state:-NEM TALÁLHATÓ}"
    FAILED_CONTAINERS+=("$service")
  fi
done

log "HTTP-végpontok gyors ellenőrzése..."
declare -A CHECK_URLS=(
  [npm]="http://127.0.0.1:81"
  [dockhand]="http://127.0.0.1:3000"
  [wg-easy]="http://127.0.0.1:51821"
  [filebrowser]="http://127.0.0.1:8080"
  [thelounge]="http://127.0.0.1:9000"
  [beszel]="http://127.0.0.1:8090"
  [homarr]="http://127.0.0.1:7575"
)
declare -A CHECK_RESULTS=()
for service in "${SERVICES[@]}"; do
  code="$(curl --connect-timeout 3 --max-time 8 -sS -o /dev/null -w '%{http_code}' "${CHECK_URLS[$service]}" 2>/dev/null || true)"
  if [[ "$code" =~ ^[1-5][0-9][0-9]$ ]]; then
    CHECK_RESULTS["$service"]="$code"
    printf '  %-14s HTTP %s\n' "$service" "$code"
  else
    CHECK_RESULTS["$service"]="NINCS VÁLASZ"
    printf '  %-14s NINCS HTTP-válasz\n' "$service"
  fi
done

CURRENT_STEP="biztonsági szolgáltatások beállítása"
log "Fail2ban és automatikus biztonsági frissítések engedélyezése..."
systemctl enable --now fail2ban
systemctl enable --now unattended-upgrades

# UFW is intentionally not enabled here: Docker-published ports can bypass UFW rules.
# Configure the VPS provider firewall deliberately. This script publishes service ports directly.
# Suggested TCP ports: 22, 80, 81, 113, 443, 3000, 51821, 7575, 8080, 8090, 9000; UDP: 51820.
# Prefer HTTPS through NPM for web apps; direct HTTP ports are unencrypted.
cat > /etc/fail2ban/jail.d/sshd.local <<'EOF'
[sshd]
enabled = true
backend = systemd
maxretry = 5
findtime = 10m
bantime = 1h
EOF
systemctl restart fail2ban

# Restrict the secrets file and compose file.
chmod 600 "$ENV_FILE"
chmod 640 "$COMPOSE_FILE"

WG_PASS="$(grep '^WG_ADMIN_PASSWORD=' "$ENV_FILE" | cut -d= -f2-)"
WG_ADDR="$(grep '^WG_HOST=' "$ENV_FILE" | cut -d= -f2-)"
SERVER_IP="$(hostname -I | awk '{print $1}')"

cat > "${STACK_DIR}/TELEPITESI-ADATOK.txt" <<EOF
Docker-stack telepítő összefoglaló
==================================

Szerver helyi címe: ${SERVER_IP}
WireGuard publikus host: ${WG_ADDR}
Időzóna: ${TZ_VALUE}

Konténerállapotok és HTTP-ellenőrzés:
EOF
for service in "${SERVICES[@]}"; do
  state="$(docker inspect -f '{{.State.Status}}' "$service" 2>/dev/null || echo "NEM TALÁLHATÓ")"
  printf '%-14s konténer=%s, HTTP=%s\n' "$service" "$state" "${CHECK_RESULTS[$service]:-nem ellenőrzött}" >> "${STACK_DIR}/TELEPITESI-ADATOK.txt"
done
cat >> "${STACK_DIR}/TELEPITESI-ADATOK.txt" <<EOF

Publikus webes elérések (HTTP, amíg nincs HTTPS beállítva):
- Nginx Proxy Manager admin: http://${WG_ADDR}:81
- Dockhand:                  http://${WG_ADDR}:3000
- wg-easy:                   http://${WG_ADDR}:51821
- FileBrowser Quantum:       http://${WG_ADDR}:8080
- The Lounge:                http://${WG_ADDR}:9000
- Beszel:                    http://${WG_ADDR}:8090
- Homarr:                    http://${WG_ADDR}:7575

A fenti közvetlen HTTP elérések titkosítatlanok. Éles használathoz állíts be külön domaineket az NPM-ben, és Let's Encrypt HTTPS-t.
Az adminfelületeket erős, egyedi jelszóval védd; amit nem muszáj közvetlenül publikálni, azt inkább csak NPM-en keresztül tedd elérhetővé.
wg-easy első adminfelhasználó: admin
wg-easy kezdeti jelszó: ${WG_PASS}

Fontos:
- A wg-easy jelszavát az első belépés után változtasd meg.
- A fájl a wg-easy kezdeti jelszavát tartalmazza. Védd, ne oszd meg, majd töröld biztonságos helyre mentés után.
- NPM-ben a Proxy Hostokhoz a Docker szolgáltatásneveket és belső portokat használd:
  homarr:7575, dockhand:3000, wg-easy:51821, filebrowser:80,
  thelounge:9000, beszel:8090.
- Domain és DNS nélkül a Let's Encrypt-tanúsítvány még nem kérhető.
- A Beszel Hubban hozz létre felhasználót, majd Add System segítségével generálj agent-kulcsot és tokent. Ezután futtasd: ${STACK_DIR}/configure-beszel-agent.sh
- The Lounge felhasználót a konténerben kell létrehozni; a parancsot lásd a telepítés végén.
- A FileBrowser Quantum első induláskor véletlen adminjelszót generálhat; keresd a konténer naplójában, mentsd el biztonságosan és változtasd meg. A Quantum v2 saját adatbázis-formátumot használ; a régi File Browser adatbázisát ne csatold be közvetlenül.
- A Homarr első indításkor a /init oldalra irányíthat (HTTP 307); ez normális, a webes kezdeti beállítást el kell végezni.
- A Dockhand és Homarr Docker socketet kap; ez teljes Docker-admin jogosultságnak felel meg.
- A VPS szolgáltatói tűzfalán engedélyezd TCP 22, 80, 443 és UDP 51820 portokat.
- A 81/3000/51821/tcp/8080/9000/8090/7575 host portok minden interfészen publikusan elérhetők.
EOF
chmod 600 "${STACK_DIR}/TELEPITESI-ADATOK.txt"

printf '\n'
docker compose --env-file "$ENV_FILE" -f "$COMPOSE_FILE" ps
printf '\n\033[1;32m============================================\033[0m\n'
if [[ "${#FAILED_CONTAINERS[@]}" -eq 0 ]]; then
  printf '\033[1;32m A KONTÉNEREK FUTNAK\033[0m\n'
else
  printf '\033[1;31m FIGYELEM: NEM MINDEN KONTÉNER FUT\033[0m\n'
  printf 'Nem futó konténerek: %s\n' "${FAILED_CONTAINERS[*]}"
fi
printf '\033[1;32m============================================\033[0m\n\n'
printf 'HTTP-ellenőrzések:\n'
for service in "${SERVICES[@]}"; do
  printf '  %-14s %s\n' "$service" "${CHECK_RESULTS[$service]:-nem ellenőrzött}"
done
printf '\nA RUNNING állapot önmagában nem bizonyítja, hogy minden alkalmazás teljesen konfigurált.\n'
printf 'Szerver publikus cím / WireGuard host: %s\n' "$WG_ADDR"
printf 'Időzóna: %s\n\n' "$TZ_VALUE"

printf 'PUBLIKUS ELÉRÉSEK (HTTP, amíg NPM-ben nincs HTTPS beállítva):\n'
printf '  Nginx Proxy Manager: http://%s:81\n' "$WG_ADDR"
printf '  Dockhand:            http://%s:3000\n' "$WG_ADDR"
printf '  wg-easy:             http://%s:51821\n' "$WG_ADDR"
printf '  FileBrowser Quantum: http://%s:8080\n' "$WG_ADDR"
printf '  The Lounge:          http://%s:9000\n' "$WG_ADDR"
printf '  Beszel:              http://%s:8090\n' "$WG_ADDR"
printf '  Homarr:              http://%s:7575\n' "$WG_ADDR"
printf '  WireGuard VPN:       %s:51820/UDP\n\n' "$WG_ADDR"

printf 'FONTOS FÁJLOK:\n'
printf '  Compose:       %s\n' "$COMPOSE_FILE"
printf '  Titkok (.env): %s\n' "$ENV_FILE"
printf '  Összefoglaló:  %s\n\n' "${STACK_DIR}/TELEPITESI-ADATOK.txt"

printf 'KÖVETKEZŐ LÉPÉSEK:\n'
printf '  1. A VPS szolgáltatói tűzfalán engedélyezd a TCP 22, 80, 81, 113, 443, 3000, 51821, 7575, 8080, 8090, 9000 és UDP 51820 portokat.\n'
printf '  2. NPM-ben állítsd be a DNS-domainjeidet és a Let'\''s Encrypt tanúsítványokat.\n'
printf '  3. Változtasd meg az alapértelmezett / kezdeti jelszavakat, ahol szükséges.\n'
printf '  4. A Beszel Hubban hozz létre fiókot és Add System kulcsot, majd futtasd: %s/configure-beszel-agent.sh\n' "$STACK_DIR"
printf '  5. Hozz létre The Lounge felhasználót:\n'
printf '     docker exec -it thelounge s6-setuidgid abc thelounge add sajatfelhasznalonev\n'
printf '  6. Ellenőrizd a FileBrowser Quantum adminbelépést, majd változtasd meg a jelszót.\n\n'

printf 'HASZNOS PARANCSOK:\n'
printf '  Állapot: cd %s && docker compose --env-file .env -f compose.yaml ps\n' "$STACK_DIR"
printf '  Naplók:  cd %s && docker compose --env-file .env -f compose.yaml logs -f\n' "$STACK_DIR"
printf '  Újraindítás: cd %s && docker compose --env-file .env -f compose.yaml restart\n\n' "$STACK_DIR"
printf 'BIZTONSÁG: a közvetlen HTTP-portok titkosítatlanok. Éles használathoz HTTPS-t állíts be NPM-ben.\n'
printf 'A publikus adminfelületeket erős, egyedi jelszóval védd. A .env és az összefoglaló fájl titkokat tartalmazhat.\n'

if [[ "${#FAILED_CONTAINERS[@]}" -gt 0 ]]; then
  die "Egy vagy több konténer nem fut: ${FAILED_CONTAINERS[*]}. Nézd meg a naplókat a fenti parancsokkal."
fi
CURRENT_STEP="befejezés"

