@minecraft-docker/mcctl 1.6.13 → 1.6.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -0
- package/dist/commands/backup.d.ts +1 -0
- package/dist/commands/backup.d.ts.map +1 -1
- package/dist/commands/backup.js +28 -2
- package/dist/commands/backup.js.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/package.json +7 -4
- package/scripts/backup.sh +569 -0
- package/scripts/create-server.sh +580 -0
- package/scripts/delete-server.sh +266 -0
- package/scripts/init.sh +390 -0
- package/scripts/lib/common.sh +248 -0
- package/scripts/lock.sh +448 -0
- package/scripts/logs.sh +283 -0
- package/scripts/mcctl.sh +543 -0
- package/scripts/migrate-nip-io.sh +258 -0
- package/scripts/player.sh +329 -0
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# =============================================================================
|
|
3
|
+
# delete-server.sh - Delete a Minecraft server
|
|
4
|
+
# =============================================================================
|
|
5
|
+
# Usage: ./scripts/delete-server.sh <server-name> [options]
|
|
6
|
+
#
|
|
7
|
+
# This script removes a server created by create-server.sh:
|
|
8
|
+
# - Stops and removes the Docker container
|
|
9
|
+
# - Removes server from servers/compose.yml
|
|
10
|
+
# - Removes hostname from avahi-daemon
|
|
11
|
+
# - Deletes server directory (servers/<server-name>/)
|
|
12
|
+
#
|
|
13
|
+
# IMPORTANT: World data in worlds/ directory is PRESERVED.
|
|
14
|
+
#
|
|
15
|
+
# Options:
|
|
16
|
+
# -f, --force Skip confirmation prompt
|
|
17
|
+
# -y, --yes Same as --force
|
|
18
|
+
# --keep-avahi Don't remove avahi hostname entry
|
|
19
|
+
#
|
|
20
|
+
# Examples:
|
|
21
|
+
# ./scripts/delete-server.sh myserver
|
|
22
|
+
# ./scripts/delete-server.sh myserver --force
|
|
23
|
+
# =============================================================================
|
|
24
|
+
|
|
25
|
+
set -e
|
|
26
|
+
|
|
27
|
+
# Colors for output
|
|
28
|
+
RED='\033[0;31m'
|
|
29
|
+
GREEN='\033[0;32m'
|
|
30
|
+
YELLOW='\033[1;33m'
|
|
31
|
+
BLUE='\033[0;34m'
|
|
32
|
+
NC='\033[0m' # No Color
|
|
33
|
+
|
|
34
|
+
# Get script/platform directories
|
|
35
|
+
# Support both direct execution and npm package execution (mcctl CLI)
|
|
36
|
+
if [[ -n "${MCCTL_ROOT:-}" ]]; then
|
|
37
|
+
# Running via npm package
|
|
38
|
+
PLATFORM_DIR="$MCCTL_ROOT"
|
|
39
|
+
SCRIPT_DIR="${MCCTL_SCRIPTS:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
|
40
|
+
else
|
|
41
|
+
# Running directly (development mode)
|
|
42
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
43
|
+
PLATFORM_DIR="$(dirname "$SCRIPT_DIR")"
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
# Source common functions
|
|
47
|
+
source "$SCRIPT_DIR/lib/common.sh"
|
|
48
|
+
|
|
49
|
+
SERVERS_DIR="$PLATFORM_DIR/servers"
|
|
50
|
+
SERVERS_COMPOSE="$SERVERS_DIR/compose.yml"
|
|
51
|
+
MAIN_COMPOSE="$PLATFORM_DIR/docker-compose.yml"
|
|
52
|
+
AVAHI_HOSTS="/etc/avahi/hosts"
|
|
53
|
+
|
|
54
|
+
# Default values
|
|
55
|
+
FORCE_DELETE="false"
|
|
56
|
+
KEEP_AVAHI="false"
|
|
57
|
+
|
|
58
|
+
# Show usage
|
|
59
|
+
show_usage() {
|
|
60
|
+
echo "Usage: $0 <server-name> [options]"
|
|
61
|
+
echo ""
|
|
62
|
+
echo "Delete a Minecraft server (worlds are preserved)."
|
|
63
|
+
echo ""
|
|
64
|
+
echo "Options:"
|
|
65
|
+
echo " -f, --force Skip confirmation prompt"
|
|
66
|
+
echo " -y, --yes Same as --force"
|
|
67
|
+
echo " --keep-avahi Don't remove avahi hostname entry"
|
|
68
|
+
echo ""
|
|
69
|
+
echo "Examples:"
|
|
70
|
+
echo " $0 myserver"
|
|
71
|
+
echo " $0 myserver --force"
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
# Check if first argument exists
|
|
75
|
+
if [ -z "$1" ]; then
|
|
76
|
+
echo -e "${RED}Error: Server name is required${NC}"
|
|
77
|
+
echo ""
|
|
78
|
+
show_usage
|
|
79
|
+
exit 1
|
|
80
|
+
fi
|
|
81
|
+
|
|
82
|
+
# Check for help flag first
|
|
83
|
+
if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
|
|
84
|
+
show_usage
|
|
85
|
+
exit 0
|
|
86
|
+
fi
|
|
87
|
+
|
|
88
|
+
# First argument is server name
|
|
89
|
+
SERVER_NAME="$1"
|
|
90
|
+
shift
|
|
91
|
+
|
|
92
|
+
# Parse remaining arguments
|
|
93
|
+
while [[ $# -gt 0 ]]; do
|
|
94
|
+
case $1 in
|
|
95
|
+
-f|--force|-y|--yes)
|
|
96
|
+
FORCE_DELETE="true"
|
|
97
|
+
shift
|
|
98
|
+
;;
|
|
99
|
+
--keep-avahi)
|
|
100
|
+
KEEP_AVAHI="true"
|
|
101
|
+
shift
|
|
102
|
+
;;
|
|
103
|
+
-h|--help)
|
|
104
|
+
show_usage
|
|
105
|
+
exit 0
|
|
106
|
+
;;
|
|
107
|
+
*)
|
|
108
|
+
echo -e "${RED}Error: Unknown option: $1${NC}"
|
|
109
|
+
echo ""
|
|
110
|
+
show_usage
|
|
111
|
+
exit 1
|
|
112
|
+
;;
|
|
113
|
+
esac
|
|
114
|
+
done
|
|
115
|
+
|
|
116
|
+
# Validate server name
|
|
117
|
+
SERVER_DIR="$SERVERS_DIR/$SERVER_NAME"
|
|
118
|
+
if [ ! -d "$SERVER_DIR" ]; then
|
|
119
|
+
echo -e "${RED}Error: Server '$SERVER_NAME' not found at $SERVER_DIR${NC}"
|
|
120
|
+
exit 1
|
|
121
|
+
fi
|
|
122
|
+
|
|
123
|
+
# Confirmation prompt
|
|
124
|
+
if [ "$FORCE_DELETE" != "true" ]; then
|
|
125
|
+
echo -e "${YELLOW}WARNING: This will delete server '$SERVER_NAME'${NC}"
|
|
126
|
+
echo ""
|
|
127
|
+
echo "The following will be removed:"
|
|
128
|
+
echo " - Docker container: mc-$SERVER_NAME"
|
|
129
|
+
echo " - Server directory: servers/$SERVER_NAME/"
|
|
130
|
+
echo " - servers/compose.yml entry"
|
|
131
|
+
if [ "$KEEP_AVAHI" != "true" ]; then
|
|
132
|
+
echo " - avahi hostname: $SERVER_NAME.local"
|
|
133
|
+
fi
|
|
134
|
+
echo ""
|
|
135
|
+
echo -e "${GREEN}World data in worlds/ will be PRESERVED.${NC}"
|
|
136
|
+
echo ""
|
|
137
|
+
read -p "Are you sure? (y/N): " confirm
|
|
138
|
+
if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
|
|
139
|
+
echo "Cancelled."
|
|
140
|
+
exit 0
|
|
141
|
+
fi
|
|
142
|
+
fi
|
|
143
|
+
|
|
144
|
+
echo ""
|
|
145
|
+
echo -e "${RED}Deleting server: $SERVER_NAME${NC}"
|
|
146
|
+
echo ""
|
|
147
|
+
|
|
148
|
+
# =============================================================================
|
|
149
|
+
# Step 1: Stop Docker container
|
|
150
|
+
# =============================================================================
|
|
151
|
+
echo -e "${BLUE}[1/4]${NC} Stopping Docker container..."
|
|
152
|
+
cd "$PLATFORM_DIR"
|
|
153
|
+
if docker compose ps "mc-$SERVER_NAME" 2>/dev/null | grep -q "mc-$SERVER_NAME"; then
|
|
154
|
+
docker compose stop "mc-$SERVER_NAME" 2>/dev/null || true
|
|
155
|
+
docker compose rm -f "mc-$SERVER_NAME" 2>/dev/null || true
|
|
156
|
+
echo " Container mc-$SERVER_NAME stopped and removed"
|
|
157
|
+
else
|
|
158
|
+
# Check if container exists but not managed by compose (exited state)
|
|
159
|
+
if docker ps -a --format '{{.Names}}' | grep -q "^mc-$SERVER_NAME$"; then
|
|
160
|
+
docker rm -f "mc-$SERVER_NAME" 2>/dev/null || true
|
|
161
|
+
echo " Container mc-$SERVER_NAME removed"
|
|
162
|
+
else
|
|
163
|
+
echo " Container mc-$SERVER_NAME not found"
|
|
164
|
+
fi
|
|
165
|
+
fi
|
|
166
|
+
|
|
167
|
+
# =============================================================================
|
|
168
|
+
# Step 2: Update servers/compose.yml
|
|
169
|
+
# =============================================================================
|
|
170
|
+
echo -e "${BLUE}[2/4]${NC} Updating servers/compose.yml..."
|
|
171
|
+
|
|
172
|
+
if [ -f "$SERVERS_COMPOSE" ]; then
|
|
173
|
+
# Backup original
|
|
174
|
+
cp "$SERVERS_COMPOSE" "$SERVERS_COMPOSE.bak"
|
|
175
|
+
|
|
176
|
+
# Remove include entry
|
|
177
|
+
if grep -q "$SERVER_NAME/docker-compose.yml" "$SERVERS_COMPOSE"; then
|
|
178
|
+
sed -i "\|$SERVER_NAME/docker-compose.yml|d" "$SERVERS_COMPOSE"
|
|
179
|
+
echo " Removed from include section"
|
|
180
|
+
|
|
181
|
+
# If no more includes, remove the include: line
|
|
182
|
+
if ! grep -q "^ - " "$SERVERS_COMPOSE"; then
|
|
183
|
+
sed -i '/^include:/d' "$SERVERS_COMPOSE"
|
|
184
|
+
echo " Removed empty include section"
|
|
185
|
+
fi
|
|
186
|
+
else
|
|
187
|
+
echo " Server not found in compose.yml"
|
|
188
|
+
fi
|
|
189
|
+
|
|
190
|
+
# Verify the changes
|
|
191
|
+
if docker compose -f "$MAIN_COMPOSE" config --quiet 2>/dev/null; then
|
|
192
|
+
echo -e " ${GREEN}Configuration validated successfully${NC}"
|
|
193
|
+
rm -f "$SERVERS_COMPOSE.bak"
|
|
194
|
+
else
|
|
195
|
+
echo -e "${RED} Error: Configuration validation failed!${NC}"
|
|
196
|
+
echo " Restoring backup..."
|
|
197
|
+
mv "$SERVERS_COMPOSE.bak" "$SERVERS_COMPOSE"
|
|
198
|
+
echo " Please check the configuration manually."
|
|
199
|
+
exit 1
|
|
200
|
+
fi
|
|
201
|
+
else
|
|
202
|
+
echo " servers/compose.yml not found (nothing to update)"
|
|
203
|
+
fi
|
|
204
|
+
|
|
205
|
+
# =============================================================================
|
|
206
|
+
# Step 3: Remove from avahi-daemon
|
|
207
|
+
# =============================================================================
|
|
208
|
+
echo -e "${BLUE}[3/4]${NC} Removing mDNS hostname..."
|
|
209
|
+
if [ "$KEEP_AVAHI" = "true" ]; then
|
|
210
|
+
echo " Skipped (--keep-avahi specified)"
|
|
211
|
+
elif [ -f "$AVAHI_HOSTS" ]; then
|
|
212
|
+
if grep -q "$SERVER_NAME.local" "$AVAHI_HOSTS" 2>/dev/null; then
|
|
213
|
+
if run_with_sudo sed -i "/$SERVER_NAME\.local/d" "$AVAHI_HOSTS" 2>/dev/null; then
|
|
214
|
+
run_with_sudo systemctl restart avahi-daemon 2>/dev/null || true
|
|
215
|
+
echo -e " ${GREEN}Removed $SERVER_NAME.local from avahi${NC}"
|
|
216
|
+
else
|
|
217
|
+
echo -e "${YELLOW} Warning: Failed to update avahi (sudo required)${NC}"
|
|
218
|
+
if has_sudo_password; then
|
|
219
|
+
echo " Check if MCCTL_SUDO_PASSWORD is correct"
|
|
220
|
+
else
|
|
221
|
+
echo " Set MCCTL_SUDO_PASSWORD env var or remove manually: sudo sed -i '/$SERVER_NAME.local/d' $AVAHI_HOSTS"
|
|
222
|
+
fi
|
|
223
|
+
fi
|
|
224
|
+
else
|
|
225
|
+
echo " Hostname not found in avahi"
|
|
226
|
+
fi
|
|
227
|
+
else
|
|
228
|
+
echo " avahi not configured"
|
|
229
|
+
fi
|
|
230
|
+
|
|
231
|
+
# =============================================================================
|
|
232
|
+
# Step 4: Delete server directory
|
|
233
|
+
# =============================================================================
|
|
234
|
+
echo -e "${BLUE}[4/4]${NC} Deleting server directory..."
|
|
235
|
+
|
|
236
|
+
# Check for symlinked worlds and warn
|
|
237
|
+
if [ -d "$SERVER_DIR/data" ]; then
|
|
238
|
+
for link in "$SERVER_DIR/data"/*; do
|
|
239
|
+
if [ -L "$link" ]; then
|
|
240
|
+
target=$(readlink "$link")
|
|
241
|
+
echo " Note: Symlink found: $(basename "$link") -> $target (preserved in worlds/)"
|
|
242
|
+
fi
|
|
243
|
+
done
|
|
244
|
+
fi
|
|
245
|
+
|
|
246
|
+
rm -rf "$SERVER_DIR"
|
|
247
|
+
echo -e " ${GREEN}Deleted servers/$SERVER_NAME/${NC}"
|
|
248
|
+
|
|
249
|
+
# =============================================================================
|
|
250
|
+
# Summary
|
|
251
|
+
# =============================================================================
|
|
252
|
+
echo ""
|
|
253
|
+
echo -e "${GREEN}========================================${NC}"
|
|
254
|
+
echo -e "${GREEN}Server '$SERVER_NAME' deleted successfully!${NC}"
|
|
255
|
+
echo -e "${GREEN}========================================${NC}"
|
|
256
|
+
echo ""
|
|
257
|
+
echo "Removed:"
|
|
258
|
+
echo " - Container: mc-$SERVER_NAME"
|
|
259
|
+
echo " - Directory: servers/$SERVER_NAME/"
|
|
260
|
+
echo " - servers/compose.yml entry"
|
|
261
|
+
if [ "$KEEP_AVAHI" != "true" ]; then
|
|
262
|
+
echo " - avahi hostname: $SERVER_NAME.local"
|
|
263
|
+
fi
|
|
264
|
+
echo ""
|
|
265
|
+
echo -e "${GREEN}World data in worlds/ has been preserved.${NC}"
|
|
266
|
+
echo ""
|
package/scripts/init.sh
ADDED
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# =============================================================================
|
|
3
|
+
# init.sh - Initialize Minecraft Platform for First Run
|
|
4
|
+
# =============================================================================
|
|
5
|
+
# This script prepares the platform for initial operation:
|
|
6
|
+
# 1. Validates Docker and Docker Compose installation
|
|
7
|
+
# 2. Validates avahi-daemon for mDNS support
|
|
8
|
+
# 3. Creates/validates .env configuration
|
|
9
|
+
# 4. Creates required directories
|
|
10
|
+
# 5. Creates Docker network and volumes
|
|
11
|
+
# 6. Performs initial docker-compose config validation
|
|
12
|
+
#
|
|
13
|
+
# Usage:
|
|
14
|
+
# ./scripts/init.sh [options]
|
|
15
|
+
#
|
|
16
|
+
# Options:
|
|
17
|
+
# --create-server NAME [TYPE] Create initial server after setup
|
|
18
|
+
# --skip-validation Skip Docker/Compose validation
|
|
19
|
+
# --skip-avahi Skip avahi-daemon validation
|
|
20
|
+
# --skip-compose-up Only initialize, don't start services
|
|
21
|
+
# -h, --help Show this help
|
|
22
|
+
#
|
|
23
|
+
# Example:
|
|
24
|
+
# ./scripts/init.sh
|
|
25
|
+
# ./scripts/init.sh --create-server myserver PAPER
|
|
26
|
+
# =============================================================================
|
|
27
|
+
|
|
28
|
+
set -e
|
|
29
|
+
|
|
30
|
+
# Colors for output
|
|
31
|
+
RED='\033[0;31m'
|
|
32
|
+
GREEN='\033[0;32m'
|
|
33
|
+
YELLOW='\033[1;33m'
|
|
34
|
+
BLUE='\033[0;34m'
|
|
35
|
+
MAGENTA='\033[0;35m'
|
|
36
|
+
NC='\033[0m' # No Color
|
|
37
|
+
|
|
38
|
+
# Get script/platform directories
|
|
39
|
+
# Support both direct execution and npm package execution (mcctl CLI)
|
|
40
|
+
if [[ -n "${MCCTL_ROOT:-}" ]]; then
|
|
41
|
+
# Running via npm package
|
|
42
|
+
PLATFORM_DIR="$MCCTL_ROOT"
|
|
43
|
+
SCRIPT_DIR="${MCCTL_SCRIPTS:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)}"
|
|
44
|
+
TEMPLATE_DIR="${MCCTL_TEMPLATES:-$PLATFORM_DIR/servers/_template}/servers/_template"
|
|
45
|
+
else
|
|
46
|
+
# Running directly (development mode)
|
|
47
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
48
|
+
PLATFORM_DIR="$(dirname "$SCRIPT_DIR")"
|
|
49
|
+
TEMPLATE_DIR="$PLATFORM_DIR/servers/_template"
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
ENV_FILE="$PLATFORM_DIR/.env"
|
|
53
|
+
ENV_EXAMPLE="$PLATFORM_DIR/.env.example"
|
|
54
|
+
|
|
55
|
+
# Default options
|
|
56
|
+
VALIDATE_DOCKER=true
|
|
57
|
+
VALIDATE_AVAHI=true
|
|
58
|
+
START_SERVICES=true
|
|
59
|
+
CREATE_SERVER_NAME=""
|
|
60
|
+
CREATE_SERVER_TYPE="PAPER"
|
|
61
|
+
|
|
62
|
+
# Parse arguments
|
|
63
|
+
while [[ $# -gt 0 ]]; do
|
|
64
|
+
case $1 in
|
|
65
|
+
--create-server)
|
|
66
|
+
CREATE_SERVER_NAME="$2"
|
|
67
|
+
CREATE_SERVER_TYPE="${3:-PAPER}"
|
|
68
|
+
shift 3
|
|
69
|
+
;;
|
|
70
|
+
--skip-validation)
|
|
71
|
+
VALIDATE_DOCKER=false
|
|
72
|
+
shift
|
|
73
|
+
;;
|
|
74
|
+
--skip-avahi)
|
|
75
|
+
VALIDATE_AVAHI=false
|
|
76
|
+
shift
|
|
77
|
+
;;
|
|
78
|
+
--skip-compose-up)
|
|
79
|
+
START_SERVICES=false
|
|
80
|
+
shift
|
|
81
|
+
;;
|
|
82
|
+
-h|--help)
|
|
83
|
+
sed -n '/^# Usage:/,/^$/p' "$0" | sed 's/^# *//'
|
|
84
|
+
exit 0
|
|
85
|
+
;;
|
|
86
|
+
*)
|
|
87
|
+
echo -e "${RED}Error: Unknown option $1${NC}"
|
|
88
|
+
exit 1
|
|
89
|
+
;;
|
|
90
|
+
esac
|
|
91
|
+
done
|
|
92
|
+
|
|
93
|
+
# =============================================================================
|
|
94
|
+
# Helper Functions
|
|
95
|
+
# =============================================================================
|
|
96
|
+
|
|
97
|
+
print_header() {
|
|
98
|
+
echo ""
|
|
99
|
+
echo -e "${MAGENTA}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
100
|
+
echo -e "${MAGENTA} $1${NC}"
|
|
101
|
+
echo -e "${MAGENTA}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
102
|
+
echo ""
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
print_step() {
|
|
106
|
+
echo -e "${BLUE}▶ $1${NC}"
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
print_success() {
|
|
110
|
+
echo -e "${GREEN}✓ $1${NC}"
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
print_warning() {
|
|
114
|
+
echo -e "${YELLOW}⚠ $1${NC}"
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
print_error() {
|
|
118
|
+
echo -e "${RED}✗ $1${NC}"
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
# =============================================================================
|
|
122
|
+
# 1. Validate Docker and Docker Compose
|
|
123
|
+
# =============================================================================
|
|
124
|
+
|
|
125
|
+
if [ "$VALIDATE_DOCKER" = true ]; then
|
|
126
|
+
print_header "Step 1: Validating Docker and Docker Compose"
|
|
127
|
+
|
|
128
|
+
print_step "Checking Docker installation..."
|
|
129
|
+
if ! command -v docker &> /dev/null; then
|
|
130
|
+
print_error "Docker not found. Please install Docker Engine 20.10+"
|
|
131
|
+
exit 1
|
|
132
|
+
fi
|
|
133
|
+
DOCKER_VERSION=$(docker --version | grep -oP '\d+\.\d+' | head -1)
|
|
134
|
+
print_success "Docker $DOCKER_VERSION found"
|
|
135
|
+
|
|
136
|
+
print_step "Checking Docker Compose installation..."
|
|
137
|
+
if ! command -v docker compose &> /dev/null && ! command -v docker-compose &> /dev/null; then
|
|
138
|
+
print_error "Docker Compose not found. Please install Docker Compose v2.0+"
|
|
139
|
+
exit 1
|
|
140
|
+
fi
|
|
141
|
+
if command -v docker compose &> /dev/null; then
|
|
142
|
+
COMPOSE_VERSION=$(docker compose version 2>&1 | grep -oP '\d+\.\d+' | head -1 || echo "unknown")
|
|
143
|
+
DOCKER_COMPOSE_CMD="docker compose"
|
|
144
|
+
else
|
|
145
|
+
COMPOSE_VERSION=$(docker-compose --version 2>&1 | grep -oP '\d+\.\d+' | head -1 || echo "unknown")
|
|
146
|
+
DOCKER_COMPOSE_CMD="docker-compose"
|
|
147
|
+
fi
|
|
148
|
+
print_success "Docker Compose $COMPOSE_VERSION found"
|
|
149
|
+
|
|
150
|
+
print_step "Checking Docker daemon..."
|
|
151
|
+
if ! docker info &> /dev/null; then
|
|
152
|
+
print_error "Cannot connect to Docker daemon. Please ensure Docker is running"
|
|
153
|
+
exit 1
|
|
154
|
+
fi
|
|
155
|
+
print_success "Docker daemon is running"
|
|
156
|
+
fi
|
|
157
|
+
|
|
158
|
+
# =============================================================================
|
|
159
|
+
# 2. Validate avahi-daemon (mDNS support)
|
|
160
|
+
# =============================================================================
|
|
161
|
+
|
|
162
|
+
if [ "$VALIDATE_AVAHI" = true ]; then
|
|
163
|
+
print_header "Step 2: Validating avahi-daemon (mDNS)"
|
|
164
|
+
|
|
165
|
+
print_step "Checking avahi-daemon installation..."
|
|
166
|
+
if command -v avahi-daemon &> /dev/null; then
|
|
167
|
+
print_success "avahi-daemon found"
|
|
168
|
+
else
|
|
169
|
+
print_warning "avahi-daemon not found"
|
|
170
|
+
echo ""
|
|
171
|
+
echo -e "${YELLOW}To install avahi-daemon:${NC}"
|
|
172
|
+
echo " Debian/Ubuntu: sudo apt install avahi-daemon"
|
|
173
|
+
echo " CentOS/RHEL: sudo dnf install avahi"
|
|
174
|
+
echo " Arch Linux: sudo pacman -S avahi nss-mdns"
|
|
175
|
+
echo " Alpine Linux: apk add avahi"
|
|
176
|
+
echo ""
|
|
177
|
+
fi
|
|
178
|
+
|
|
179
|
+
print_step "Checking avahi-daemon status..."
|
|
180
|
+
if systemctl is-active --quiet avahi-daemon 2>/dev/null; then
|
|
181
|
+
print_success "avahi-daemon is running"
|
|
182
|
+
elif rc-service avahi-daemon status &>/dev/null; then
|
|
183
|
+
print_success "avahi-daemon is running (OpenRC)"
|
|
184
|
+
else
|
|
185
|
+
print_warning "avahi-daemon is not running"
|
|
186
|
+
echo ""
|
|
187
|
+
echo -e "${YELLOW}To start avahi-daemon:${NC}"
|
|
188
|
+
echo " Systemd: sudo systemctl enable --now avahi-daemon"
|
|
189
|
+
echo " OpenRC: rc-update add avahi-daemon default && rc-service avahi-daemon start"
|
|
190
|
+
echo ""
|
|
191
|
+
fi
|
|
192
|
+
|
|
193
|
+
print_step "Checking /etc/avahi/hosts write permission..."
|
|
194
|
+
if [ -w /etc/avahi/hosts ] || sudo test -w /etc/avahi/hosts 2>/dev/null; then
|
|
195
|
+
print_success "/etc/avahi/hosts is writable"
|
|
196
|
+
else
|
|
197
|
+
print_warning "/etc/avahi/hosts may require sudo for hostname registration"
|
|
198
|
+
fi
|
|
199
|
+
fi
|
|
200
|
+
|
|
201
|
+
# =============================================================================
|
|
202
|
+
# 3. Setup Environment File
|
|
203
|
+
# =============================================================================
|
|
204
|
+
|
|
205
|
+
print_header "Step 3: Setting up environment configuration"
|
|
206
|
+
|
|
207
|
+
if [ ! -f "$ENV_FILE" ]; then
|
|
208
|
+
print_step "Creating .env from template..."
|
|
209
|
+
if [ -f "$ENV_EXAMPLE" ]; then
|
|
210
|
+
cp "$ENV_EXAMPLE" "$ENV_FILE"
|
|
211
|
+
print_success ".env created from .env.example"
|
|
212
|
+
else
|
|
213
|
+
print_warning ".env.example not found, creating minimal .env"
|
|
214
|
+
cat > "$ENV_FILE" << 'EOF'
|
|
215
|
+
# Multi-Server Minecraft Management
|
|
216
|
+
MINECRAFT_NETWORK=minecraft-net
|
|
217
|
+
MINECRAFT_SUBNET=172.28.0.0/16
|
|
218
|
+
DEFAULT_MEMORY=4G
|
|
219
|
+
DEFAULT_VERSION=1.20.4
|
|
220
|
+
TZ=Asia/Seoul
|
|
221
|
+
RCON_PASSWORD=changeme
|
|
222
|
+
COMPOSE_PROJECT_NAME=minecraft
|
|
223
|
+
EOF
|
|
224
|
+
print_success "Minimal .env created"
|
|
225
|
+
fi
|
|
226
|
+
print_warning "Please review and update .env with your settings"
|
|
227
|
+
else
|
|
228
|
+
print_success ".env already exists"
|
|
229
|
+
fi
|
|
230
|
+
|
|
231
|
+
# =============================================================================
|
|
232
|
+
# 4. Create Required Directories
|
|
233
|
+
# =============================================================================
|
|
234
|
+
|
|
235
|
+
print_header "Step 4: Creating required directories"
|
|
236
|
+
|
|
237
|
+
DIRS=(
|
|
238
|
+
"$PLATFORM_DIR/servers"
|
|
239
|
+
"$PLATFORM_DIR/shared/plugins"
|
|
240
|
+
"$PLATFORM_DIR/shared/mods"
|
|
241
|
+
"$PLATFORM_DIR/worlds"
|
|
242
|
+
"$PLATFORM_DIR/worlds/.locks"
|
|
243
|
+
"$PLATFORM_DIR/backups/servers"
|
|
244
|
+
"$PLATFORM_DIR/backups/worlds"
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
for dir in "${DIRS[@]}"; do
|
|
248
|
+
if [ ! -d "$dir" ]; then
|
|
249
|
+
mkdir -p "$dir"
|
|
250
|
+
print_step "Created: $dir"
|
|
251
|
+
fi
|
|
252
|
+
done
|
|
253
|
+
|
|
254
|
+
print_success "All directories validated/created"
|
|
255
|
+
|
|
256
|
+
# =============================================================================
|
|
257
|
+
# 5. Validate docker-compose.yml
|
|
258
|
+
# =============================================================================
|
|
259
|
+
|
|
260
|
+
print_header "Step 5: Validating Docker Compose configuration"
|
|
261
|
+
|
|
262
|
+
print_step "Validating $PLATFORM_DIR/docker-compose.yml..."
|
|
263
|
+
cd "$PLATFORM_DIR"
|
|
264
|
+
if ! $DOCKER_COMPOSE_CMD config > /dev/null 2>&1; then
|
|
265
|
+
print_error "Docker Compose configuration is invalid"
|
|
266
|
+
$DOCKER_COMPOSE_CMD config
|
|
267
|
+
exit 1
|
|
268
|
+
fi
|
|
269
|
+
print_success "Docker Compose configuration is valid"
|
|
270
|
+
|
|
271
|
+
# =============================================================================
|
|
272
|
+
# 6. Create/Verify Docker Network
|
|
273
|
+
# =============================================================================
|
|
274
|
+
|
|
275
|
+
print_header "Step 6: Setting up Docker network"
|
|
276
|
+
|
|
277
|
+
# Source .env to get network settings
|
|
278
|
+
set -a
|
|
279
|
+
source <(grep -v '^\s*#' "$ENV_FILE" | grep -v '^\s*$') 2>/dev/null || true
|
|
280
|
+
set +a
|
|
281
|
+
|
|
282
|
+
NETWORK_NAME="${MINECRAFT_NETWORK:-minecraft-net}"
|
|
283
|
+
print_step "Checking network: $NETWORK_NAME"
|
|
284
|
+
|
|
285
|
+
if ! docker network ls | grep -q "^[^ ]*${NETWORK_NAME}"; then
|
|
286
|
+
print_step "Creating network: $NETWORK_NAME"
|
|
287
|
+
docker network create \
|
|
288
|
+
--driver bridge \
|
|
289
|
+
--subnet "${MINECRAFT_SUBNET:-172.28.0.0/16}" \
|
|
290
|
+
"$NETWORK_NAME" 2>/dev/null || true
|
|
291
|
+
print_success "Network created/verified"
|
|
292
|
+
else
|
|
293
|
+
print_success "Network already exists"
|
|
294
|
+
fi
|
|
295
|
+
|
|
296
|
+
# =============================================================================
|
|
297
|
+
# 7. Create Initial Server (Optional)
|
|
298
|
+
# =============================================================================
|
|
299
|
+
|
|
300
|
+
if [ -n "$CREATE_SERVER_NAME" ]; then
|
|
301
|
+
print_header "Step 7: Creating initial server"
|
|
302
|
+
print_step "Creating server: $CREATE_SERVER_NAME ($CREATE_SERVER_TYPE)"
|
|
303
|
+
|
|
304
|
+
if [ -x "$SCRIPT_DIR/create-server.sh" ]; then
|
|
305
|
+
"$SCRIPT_DIR/create-server.sh" "$CREATE_SERVER_NAME" -t "$CREATE_SERVER_TYPE" --no-start
|
|
306
|
+
print_success "Server created: $CREATE_SERVER_NAME"
|
|
307
|
+
else
|
|
308
|
+
print_error "create-server.sh not found or not executable"
|
|
309
|
+
exit 1
|
|
310
|
+
fi
|
|
311
|
+
else
|
|
312
|
+
print_header "Step 7: Initial server creation"
|
|
313
|
+
print_warning "No initial server requested (use --create-server NAME [TYPE] to create one)"
|
|
314
|
+
fi
|
|
315
|
+
|
|
316
|
+
# =============================================================================
|
|
317
|
+
# 8. Start Services (Optional)
|
|
318
|
+
# =============================================================================
|
|
319
|
+
|
|
320
|
+
if [ "$START_SERVICES" = true ]; then
|
|
321
|
+
print_header "Step 8: Starting platform services"
|
|
322
|
+
|
|
323
|
+
print_step "Starting Docker Compose services..."
|
|
324
|
+
cd "$PLATFORM_DIR"
|
|
325
|
+
$DOCKER_COMPOSE_CMD up -d router 2>&1 | grep -E '(Creating|Created|Starting|Started)' || true
|
|
326
|
+
|
|
327
|
+
print_success "mc-router started"
|
|
328
|
+
|
|
329
|
+
# Wait for router to be ready
|
|
330
|
+
print_step "Waiting for router to be ready..."
|
|
331
|
+
for i in {1..30}; do
|
|
332
|
+
if docker exec mc-router nc -zv localhost 25565 &> /dev/null; then
|
|
333
|
+
print_success "Router is ready"
|
|
334
|
+
break
|
|
335
|
+
fi
|
|
336
|
+
if [ $i -eq 30 ]; then
|
|
337
|
+
print_warning "Router startup timeout (may still be initializing)"
|
|
338
|
+
fi
|
|
339
|
+
sleep 1
|
|
340
|
+
done
|
|
341
|
+
else
|
|
342
|
+
print_header "Step 8: Services not started"
|
|
343
|
+
print_warning "Use 'docker compose up -d' to start services manually"
|
|
344
|
+
fi
|
|
345
|
+
|
|
346
|
+
# =============================================================================
|
|
347
|
+
# 9. Summary
|
|
348
|
+
# =============================================================================
|
|
349
|
+
|
|
350
|
+
print_header "Initialization Complete ✓"
|
|
351
|
+
|
|
352
|
+
cat << EOF
|
|
353
|
+
|
|
354
|
+
${GREEN}Platform Status:${NC}
|
|
355
|
+
|
|
356
|
+
📁 Configuration: $ENV_FILE
|
|
357
|
+
🐳 Network: $NETWORK_NAME
|
|
358
|
+
📂 Directories: Created
|
|
359
|
+
🌐 mDNS: avahi-daemon (system service)
|
|
360
|
+
|
|
361
|
+
${GREEN}Next Steps:${NC}
|
|
362
|
+
|
|
363
|
+
1. Create your first server:
|
|
364
|
+
cd $PLATFORM_DIR
|
|
365
|
+
./scripts/create-server.sh myserver -t PAPER
|
|
366
|
+
|
|
367
|
+
2. Connect to server (mDNS):
|
|
368
|
+
Open Minecraft and connect to: myserver.local:25565
|
|
369
|
+
|
|
370
|
+
3. View server status:
|
|
371
|
+
docker compose ps
|
|
372
|
+
|
|
373
|
+
4. View logs:
|
|
374
|
+
docker logs -f mc-myserver
|
|
375
|
+
|
|
376
|
+
${YELLOW}Environment Reminder:${NC}
|
|
377
|
+
|
|
378
|
+
⚠️ Default RCON_PASSWORD is 'changeme' - change in .env for production!
|
|
379
|
+
⚠️ Ensure avahi-daemon is running for mDNS auto-discovery
|
|
380
|
+
|
|
381
|
+
${BLUE}Documentation:${NC}
|
|
382
|
+
|
|
383
|
+
📖 Getting Started: Read README.md
|
|
384
|
+
📖 mDNS Setup: See README.md#mdns-setup-guide
|
|
385
|
+
📖 Full Docs: See docs/doc-list.md
|
|
386
|
+
|
|
387
|
+
EOF
|
|
388
|
+
|
|
389
|
+
print_success "Platform ready to use!"
|
|
390
|
+
exit 0
|