#!/bin/bash # Minecraft Server Modul für gameadm # Vollständige Implementierung mit intelligenten Features # Konfigurationsdatei CONFIG_FILE="/etc/minecraft-server.conf" # Installation/Konfiguration für Minecraft Server cmd_install() { local force_install="$1" log "INFO" "Minecraft Server Installation/Konfiguration gestartet" # Prüfe ob bereits konfiguriert if [[ -f "$CONFIG_FILE" ]]; then log "WARN" "Minecraft bereits konfiguriert in: $CONFIG_FILE" # Force-Installation oder interaktive Abfrage if [[ "$force_install" == "--force" ]] || [[ "$force_install" == "-f" ]]; then log "INFO" "Force-Installation: Überschreibe Konfiguration" else read -p "Überschreiben? [y/N]: " -n 1 -r echo if [[ ! $REPLY =~ ^[Yy]$ ]]; then log "INFO" "Installation abgebrochen." return 0 fi fi fi # Erstelle Konfiguration log "INFO" "Erstelle Minecraft Server Konfiguration..." mkdir -p "$(dirname "$CONFIG_FILE")" cat > "$CONFIG_FILE" << 'EOF' # Minecraft Server Konfiguration für gameadm # Automatisch erstellt - kann angepasst werden # Container Einstellungen CONTAINER_NAME="minecraft-server" IMAGE="docker.io/itzg/minecraft-server:latest" DATA_DIR="/srv/minecraft" PORT="25565" # Server Einstellungen MEMORY_LIMIT="2g" VERSION="LATEST" EULA="TRUE" DIFFICULTY="normal" GAMEMODE="survival" MAX_PLAYERS="20" MOTD="§6PP1L Minecraft Server §r§7- Powered by gameadm" LEVEL_NAME="world" ONLINE_MODE="true" # Performance Optimierungen ENABLE_AUTOPAUSE="true" AUTOPAUSE_TIMEOUT_EST="3600" AUTOPAUSE_TIMEOUT_KN="120" USE_AIKAR_FLAGS="true" # Sicherheit (optional - Pfade zu Secret-Dateien) RCON_PASSWORD_FILE="/root/secrets/minecraft_rcon_password" SERVER_PASSWORD_FILE="/root/secrets/minecraft_server_password" EOF log "INFO" "Konfiguration erstellt: $CONFIG_FILE" # Erstelle Datenverzeichnis mkdir -p "/srv/minecraft" log "INFO" "Datenverzeichnis erstellt: /srv/minecraft" # EULA akzeptieren echo "eula=TRUE" > "/srv/minecraft/eula.txt" log "INFO" "EULA akzeptiert: /srv/minecraft/eula.txt" # Erstelle Secret-Verzeichnis (optional) mkdir -p "/root/secrets" if [[ ! -f "/root/secrets/minecraft_rcon_password" ]]; then # Generiere zufälliges RCON Passwort openssl rand -base64 32 2>/dev/null > "/root/secrets/minecraft_rcon_password" || echo "rcon$(date +%s)" > "/root/secrets/minecraft_rcon_password" chmod 600 "/root/secrets/minecraft_rcon_password" log "INFO" "RCON Passwort generiert: /root/secrets/minecraft_rcon_password" fi log "INFO" "Minecraft Server erfolgreich konfiguriert!" log "INFO" "" log "INFO" "Nächste Schritte:" log "INFO" " 1. Konfiguration anpassen: $CONFIG_FILE" log "INFO" " 2. Server starten: gameadm mc start" log "INFO" " 3. Status prüfen: gameadm mc status" log "INFO" " 4. Logs anzeigen: gameadm mc logs" log "INFO" "" log "INFO" "Server läuft auf Port 25565" log "INFO" "Daten gespeichert in: /srv/minecraft" return 0 } # Konfiguration laden (nur wenn Datei existiert) if [[ -f "$CONFIG_FILE" ]]; then # shellcheck disable=SC1090 source "$CONFIG_FILE" else # Fallback-Werte für andere Befehle wenn keine Konfiguration existiert CONTAINER_NAME="minecraft-server" IMAGE="docker.io/itzg/minecraft-server:latest" DATA_DIR="/srv/minecraft" PORT="25565" MEMORY_LIMIT="2g" VERSION="LATEST" EULA="TRUE" fi # Standardwerte (mit intelligenten Defaults) CONTAINER_NAME=${CONTAINER_NAME:-minecraft-server} IMAGE=${IMAGE:-docker.io/itzg/minecraft-server:latest} DATA_DIR=${DATA_DIR:-/srv/minecraft} PORT=${PORT:-25565} MEMORY_LIMIT=${MEMORY_LIMIT:-"2g"} VERSION=${VERSION:-"LATEST"} EULA=${EULA:-"TRUE"} DIFFICULTY=${DIFFICULTY:-"normal"} GAMEMODE=${GAMEMODE:-"survival"} MAX_PLAYERS=${MAX_PLAYERS:-10} MOTD=${MOTD:-"§6PP1L Minecraft Server §r§7- Powered by gameadm"} LEVEL_NAME=${LEVEL_NAME:-"world"} ONLINE_MODE=${ONLINE_MODE:-"true"} ENABLE_AUTOPAUSE=${ENABLE_AUTOPAUSE:-"true"} AUTOPAUSE_TIMEOUT_EST=${AUTOPAUSE_TIMEOUT_EST:-3600} AUTOPAUSE_TIMEOUT_KN=${AUTOPAUSE_TIMEOUT_KN:-120} USE_AIKAR_FLAGS=${USE_AIKAR_FLAGS:-"true"} RCON_PASSWORD_FILE=${RCON_PASSWORD_FILE:-/root/secrets/minecraft_rcon_password} SERVER_PASSWORD_FILE=${SERVER_PASSWORD_FILE:-/root/secrets/minecraft_server_password} # Intelligente Hilfsfunktionen ensure_prereqs() { log "INFO" "Prüfe Minecraft Server Voraussetzungen..." # Datenverzeichnis erstellen mkdir -p "$DATA_DIR" # EULA akzeptieren if [[ ! -f "$DATA_DIR/eula.txt" ]]; then echo "eula=$EULA" > "$DATA_DIR/eula.txt" log "INFO" "EULA akzeptiert: $DATA_DIR/eula.txt" fi # Berechtigungen setzen chown -R root:root "$DATA_DIR" chmod 755 "$DATA_DIR" # Memory Check local available_mem=$(free -m | awk '/^Mem:/{print $7}') local requested_mem=$(echo "$MEMORY_LIMIT" | sed 's/[gG]//' | sed 's/[mM]//') if [[ "$MEMORY_LIMIT" =~ [gG]$ ]]; then requested_mem=$((requested_mem * 1024)) fi if [[ $available_mem -lt $requested_mem ]]; then log "WARN" "Wenig verfügbarer RAM: ${available_mem}MB verfügbar, ${requested_mem}MB angefordert" fi log "INFO" "Voraussetzungen erfüllt ✓" } is_running() { podman inspect -f '{{.State.Running}}' "$CONTAINER_NAME" 2>/dev/null | grep -q true } get_container_status() { if is_running; then echo "RUNNING" elif podman inspect "$CONTAINER_NAME" >/dev/null 2>&1; then local state=$(podman inspect -f '{{.State.Status}}' "$CONTAINER_NAME" 2>/dev/null) echo "${state^^}" else echo "NOT_FOUND" fi } get_server_info() { if ! is_running; then return 1 fi local stats=$(podman stats --no-stream --format "{{.MemUsage}}" "$CONTAINER_NAME" 2>/dev/null) echo "Memory: $stats" } perform_backup() { if [[ ! -d "$DATA_DIR" ]]; then log "ERROR" "Datenverzeichnis nicht gefunden: $DATA_DIR" return 1 fi local backup_dir="/srv/backups/minecraft" local timestamp=$(date '+%Y%m%d_%H%M%S') local backup_file="$backup_dir/minecraft_backup_$timestamp.tar.gz" mkdir -p "$backup_dir" log "INFO" "Erstelle Backup: $backup_file" if tar -czf "$backup_file" -C "$(dirname "$DATA_DIR")" "$(basename "$DATA_DIR")"; then log "INFO" "Backup erfolgreich erstellt ✓" # Alte Backups aufräumen (behalte nur die letzten 7) find "$backup_dir" -name "minecraft_backup_*.tar.gz" -type f -mtime +7 -delete 2>/dev/null || true return 0 else log "ERROR" "Backup fehlgeschlagen" return 1 fi } # Erweiterte Befehle cmd_start() { ensure_prereqs if is_running; then log "INFO" "Bereits gestartet: $CONTAINER_NAME" cmd_status exit 0 fi # Beendeten Container entfernen falls vorhanden if podman inspect "$CONTAINER_NAME" >/dev/null 2>&1; then log "INFO" "Entferne alten Container..." podman rm -f "$CONTAINER_NAME" >/dev/null 2>&1 || true fi log "INFO" "Starte Minecraft Server..." log "INFO" "Memory Limit: $MEMORY_LIMIT | Version: $VERSION | Port: $PORT" # Intelligente Container-Erstellung local podman_args=( "run" "-d" "--name" "$CONTAINER_NAME" "--restart=always" "--memory=$MEMORY_LIMIT" "--memory-swap=$MEMORY_LIMIT" "--oom-kill-disable" "-p" "${PORT}:25565" "-v" "$DATA_DIR:/data" "-e" "EULA=$EULA" "-e" "VERSION=$VERSION" "-e" "MEMORY=$MEMORY_LIMIT" "-e" "DIFFICULTY=$DIFFICULTY" "-e" "GAMEMODE=$GAMEMODE" "-e" "MAX_PLAYERS=$MAX_PLAYERS" "-e" "MOTD=$MOTD" "-e" "LEVEL=$LEVEL_NAME" "-e" "ONLINE_MODE=$ONLINE_MODE" "-e" "ENABLE_AUTOPAUSE=$ENABLE_AUTOPAUSE" "-e" "AUTOPAUSE_TIMEOUT_EST=$AUTOPAUSE_TIMEOUT_EST" "-e" "AUTOPAUSE_TIMEOUT_KN=$AUTOPAUSE_TIMEOUT_KN" ) # Aikar Flags für Performance (wenn aktiviert) if [[ "$USE_AIKAR_FLAGS" == "true" ]]; then podman_args+=("-e" "USE_AIKAR_FLAGS=true") log "INFO" "Aikar Performance Flags aktiviert ✓" fi # RCON aktivieren wenn Passwort-Datei existiert if [[ -f "$RCON_PASSWORD_FILE" ]]; then podman_args+=("-e" "ENABLE_RCON=true") podman_args+=("-e" "RCON_PASSWORD=$(cat "$RCON_PASSWORD_FILE")") podman_args+=("-p" "25575:25575") log "INFO" "RCON aktiviert ✓" fi podman_args+=("$IMAGE") if podman "${podman_args[@]}" >/dev/null; then log "INFO" "Minecraft Server gestartet ✓" log "INFO" "Warte auf Server-Initialisierung..." sleep 5 cmd_status else log "ERROR" "Fehler beim Starten des Servers" exit 1 fi } cmd_stop() { if ! podman inspect "$CONTAINER_NAME" >/dev/null 2>&1; then log "INFO" "Container existiert nicht: $CONTAINER_NAME" exit 0 fi if is_running; then log "INFO" "Stoppe Minecraft Server gracefully..." # Graceful shutdown über RCON falls möglich if [[ -f "$RCON_PASSWORD_FILE" ]]; then local rcon_pass=$(cat "$RCON_PASSWORD_FILE") timeout 30 podman exec "$CONTAINER_NAME" rcon-cli --password "$rcon_pass" say "Server wird in 10 Sekunden heruntergefahren..." 2>/dev/null || true sleep 2 timeout 30 podman exec "$CONTAINER_NAME" rcon-cli --password "$rcon_pass" stop 2>/dev/null || true sleep 8 fi # Fallback: Standard Stop podman stop -t 30 "$CONTAINER_NAME" >/dev/null 2>&1 || true fi podman rm "$CONTAINER_NAME" >/dev/null 2>&1 || true log "INFO" "Minecraft Server gestoppt ✓" } cmd_restart() { log "INFO" "Starte Minecraft Server neu..." cmd_stop || true sleep 2 cmd_start } cmd_status() { local status=$(get_container_status) local color="" case "$status" in "RUNNING") color="$GREEN" ;; "EXITED"|"STOPPED") color="$YELLOW" ;; "NOT_FOUND") color="$RED" ;; *) color="$NC" ;; esac echo -e "${color}Status: $status${NC}" if [[ "$status" == "RUNNING" ]]; then podman ps --filter name="^${CONTAINER_NAME}$" --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}' # Server Info anzeigen local info=$(get_server_info) if [[ -n "$info" ]]; then echo "Server Info: $info" fi # Online Spieler (falls RCON verfügbar) if [[ -f "$RCON_PASSWORD_FILE" ]] && is_running; then local rcon_pass=$(cat "$RCON_PASSWORD_FILE") local players=$(timeout 5 podman exec "$CONTAINER_NAME" rcon-cli --password "$rcon_pass" list 2>/dev/null | head -1 || echo "RCON nicht verfügbar") echo "Spieler: $players" fi fi } cmd_logs() { if ! podman inspect "$CONTAINER_NAME" >/dev/null 2>&1; then log "ERROR" "Container $CONTAINER_NAME existiert nicht" exit 1 fi local lines=${1:-200} podman logs --tail="$lines" "$CONTAINER_NAME" } cmd_follow() { if ! podman inspect "$CONTAINER_NAME" >/dev/null 2>&1; then log "ERROR" "Container $CONTAINER_NAME existiert nicht" exit 1 fi log "INFO" "Folge Minecraft Server Logs (Ctrl+C zum Beenden)..." podman logs -f "$CONTAINER_NAME" } cmd_update() { log "INFO" "Aktualisiere Minecraft Server Image..." local old_id=$(podman images --format "{{.ID}}" "$IMAGE" 2>/dev/null | head -1) if podman pull "$IMAGE"; then local new_id=$(podman images --format "{{.ID}}" "$IMAGE" 2>/dev/null | head -1) if [[ "$old_id" != "$new_id" ]]; then log "INFO" "Neues Image verfügbar. Server-Neustart empfohlen." log "INFO" "Führe 'gameadm mc restart' aus um das neue Image zu verwenden." else log "INFO" "Image bereits aktuell ✓" fi else log "ERROR" "Fehler beim Aktualisieren des Images" exit 1 fi } cmd_backup() { log "INFO" "Erstelle Minecraft Server Backup..." if is_running; then log "INFO" "Server läuft - erstelle Live-Backup..." # Für Live-Backup könnten wir save-all über RCON ausführen if [[ -f "$RCON_PASSWORD_FILE" ]]; then local rcon_pass=$(cat "$RCON_PASSWORD_FILE") timeout 30 podman exec "$CONTAINER_NAME" rcon-cli --password "$rcon_pass" save-all 2>/dev/null || true sleep 2 fi fi perform_backup } cmd_console() { if ! is_running; then log "ERROR" "Server ist nicht gestartet" exit 1 fi if [[ ! -f "$RCON_PASSWORD_FILE" ]]; then log "ERROR" "RCON nicht konfiguriert" exit 1 fi local rcon_pass=$(cat "$RCON_PASSWORD_FILE") log "INFO" "Minecraft Server Konsole (RCON) - 'quit' zum Beenden" while true; do read -r -p "minecraft> " command case "$command" in "quit"|"exit"|"q") break ;; "") continue ;; *) timeout 10 podman exec "$CONTAINER_NAME" rcon-cli --password "$rcon_pass" "$command" 2>/dev/null || log "ERROR" "RCON Befehl fehlgeschlagen" ;; esac done } cmd_players() { if ! is_running; then log "ERROR" "Server ist nicht gestartet" exit 1 fi if [[ ! -f "$RCON_PASSWORD_FILE" ]]; then log "ERROR" "RCON nicht konfiguriert" exit 1 fi local rcon_pass=$(cat "$RCON_PASSWORD_FILE") timeout 5 podman exec "$CONTAINER_NAME" rcon-cli --password "$rcon_pass" list 2>/dev/null || log "ERROR" "Kann Spielerliste nicht abrufen" } cmd_help() { cat < [optionen] Verfügbare Befehle: start - Startet Minecraft Server (mit intelligenten Optimierungen) stop - Stoppt Server gracefully (mit RCON-Warnung wenn verfügbar) restart - Startet Server neu status - Zeigt detaillierten Server-Status und Spieler-Info logs [n] - Zeigt Server-Logs (Standard: 200 Zeilen) follow - Folgt Logs in Echtzeit update - Aktualisiert Server-Image backup - Erstellt Server-Backup console - Interaktive Server-Konsole (RCON) players - Zeigt Online-Spieler help - Zeigt diese Hilfe Features: ✓ 2GB Memory Limit mit intelligenter Überwachung ✓ Aikar Performance Flags für optimale JVM-Performance ✓ Auto-Pause bei Inaktivität (spart Ressourcen) ✓ RCON-Support für Remote-Verwaltung ✓ Automatische Backups mit Rotation ✓ Graceful Shutdown mit Spieler-Benachrichtigung ✓ Live-Status und Memory-Monitoring ✓ Sichere Passwort-Verwaltung Konfiguration: $CONFIG_FILE Container: $CONTAINER_NAME Port: $PORT (TCP) Memory: $MEMORY_LIMIT Version: $VERSION Daten: $DATA_DIR Beispiele: gameadm mc start # Server starten gameadm mc status # Status mit Spieler-Info gameadm mc console # Interaktive Konsole gameadm mc backup # Backup erstellen gameadm mc logs 50 # Letzte 50 Log-Zeilen EOF }