Proof of concept: Container management with FastAPI backend
- FastAPI backend with REST API endpoints - SQLite database for container metadata - Docker/Podman SDK integration with label filtering - Frontend: Server creation form and management page - Container operations: create, list, start, stop, delete - Single container deployment (nginx + Python + supervisor) - Support for Docker and Podman (rootless) - Volume management for persistent data
This commit is contained in:
commit
c31e48e2b1
25 changed files with 3382 additions and 0 deletions
7
.dockerignore
Normal file
7
.dockerignore
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
node_modules
|
||||
.git
|
||||
references
|
||||
docs
|
||||
*.md
|
||||
!README.md
|
||||
|
||||
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
data/
|
||||
*.db
|
||||
__pycache__/
|
||||
*.pyc
|
||||
*.pyo
|
||||
.env
|
||||
|
||||
71
Dockerfile
Normal file
71
Dockerfile
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
FROM python:3.11-slim
|
||||
|
||||
# Install nginx
|
||||
RUN apt-get update && apt-get install -y nginx supervisor && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /app
|
||||
|
||||
# Create data directory
|
||||
RUN mkdir -p /app/data && chmod 777 /app/data
|
||||
|
||||
# Copy backend requirements and install
|
||||
COPY backend/requirements.txt /app/backend/
|
||||
RUN pip install --no-cache-dir -r backend/requirements.txt
|
||||
|
||||
# Copy backend code
|
||||
COPY backend/ /app/backend/
|
||||
|
||||
# Copy frontend files
|
||||
COPY index.html manage.html /usr/share/nginx/html/
|
||||
|
||||
# Configure nginx
|
||||
RUN echo 'server {\n\
|
||||
listen 80;\n\
|
||||
server_name localhost;\n\
|
||||
root /usr/share/nginx/html;\n\
|
||||
index index.html;\n\
|
||||
\n\
|
||||
location / {\n\
|
||||
try_files $uri $uri/ /index.html;\n\
|
||||
}\n\
|
||||
\n\
|
||||
location /api {\n\
|
||||
proxy_pass http://127.0.0.1:8000;\n\
|
||||
proxy_set_header Host $host;\n\
|
||||
proxy_set_header X-Real-IP $remote_addr;\n\
|
||||
}\n\
|
||||
}' > /etc/nginx/sites-available/default
|
||||
|
||||
# Configure supervisor
|
||||
RUN echo '[supervisord]\n\
|
||||
nodaemon=true\n\
|
||||
logfile=/dev/stdout\n\
|
||||
logfile_maxbytes=0\n\
|
||||
pidfile=/var/run/supervisord.pid\n\
|
||||
\n\
|
||||
[program:nginx]\n\
|
||||
command=nginx -g "daemon off;"\n\
|
||||
autostart=true\n\
|
||||
autorestart=true\n\
|
||||
stdout_logfile=/dev/stdout\n\
|
||||
stdout_logfile_maxbytes=0\n\
|
||||
stderr_logfile=/dev/stderr\n\
|
||||
stderr_logfile_maxbytes=0\n\
|
||||
\n\
|
||||
[program:fastapi]\n\
|
||||
command=uvicorn backend.main:app --host 127.0.0.1 --port 8000\n\
|
||||
directory=/app\n\
|
||||
environment=PYTHONPATH=/app\n\
|
||||
autostart=true\n\
|
||||
autorestart=true\n\
|
||||
stdout_logfile=/dev/stdout\n\
|
||||
stdout_logfile_maxbytes=0\n\
|
||||
stderr_logfile=/dev/stderr\n\
|
||||
stderr_logfile_maxbytes=0\n\
|
||||
' > /etc/supervisor/conf.d/supervisord.conf
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]
|
||||
57
README.md
Normal file
57
README.md
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
# Stronghold
|
||||
|
||||
A web ui to manage minecraft server using the itzg docker container
|
||||
https://github.com/itzg/docker-minecraft-server
|
||||
|
||||
Also manage proxy servers like velocity, bungeecord
|
||||
|
||||
## Development
|
||||
See design.md for design notes
|
||||
|
||||
## Quick Start (Proof of Concept)
|
||||
|
||||
Stronghold is a web UI for managing Minecraft servers using Docker/Podman containers.
|
||||
|
||||
### Running the POC
|
||||
|
||||
**Using Docker Compose (Docker users)**
|
||||
```bash
|
||||
docker-compose up -d --build
|
||||
```
|
||||
|
||||
**Using Podman Compose (Podman users)**
|
||||
```bash
|
||||
podman-compose up -d --build
|
||||
```
|
||||
|
||||
**Note**: The container needs access to your Docker/Podman socket to manage containers. The compose file mounts:
|
||||
- `/var/run/docker.sock` (Docker)
|
||||
- `/run/podman/podman.sock` (Podman)
|
||||
|
||||
Then open http://localhost:8080 in your browser.
|
||||
|
||||
### Features
|
||||
|
||||
**Current POC Features:**
|
||||
- ✅ Generate docker-compose.yml files
|
||||
- ✅ Create Minecraft server containers directly
|
||||
- ✅ List and manage containers
|
||||
- ✅ Start/Stop/Delete containers
|
||||
- ✅ Support for Docker and Podman
|
||||
- ✅ SQLite database for container metadata
|
||||
- ✅ Multiple server types (Vanilla, Paper, Forge, Fabric, etc.)
|
||||
- ✅ Modpack support (CurseForge, Modrinth, URL, Local)
|
||||
- ✅ Advanced configuration options
|
||||
|
||||
**Pages:**
|
||||
- `/` (index.html) - Create new servers
|
||||
- `/manage.html` - Manage existing servers
|
||||
|
||||
### Architecture
|
||||
|
||||
- **Frontend**: Static HTML/CSS/JavaScript
|
||||
- **Backend**: Python FastAPI
|
||||
- **Database**: SQLite (stored in `./data/stronghold.db`)
|
||||
- **Container Engine**: Docker SDK (works with both Docker and Podman)
|
||||
|
||||
All containers created by Stronghold are labeled with `stronghold.managed=true` to isolate them from other containers.
|
||||
37
backend/database.py
Normal file
37
backend/database.py
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
from sqlalchemy import create_engine, Column, String, Integer, Text, Boolean, DateTime
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
from datetime import datetime
|
||||
|
||||
Base = declarative_base()
|
||||
|
||||
class Container(Base):
|
||||
__tablename__ = "containers"
|
||||
|
||||
id = Column(Integer, primary_key=True, index=True)
|
||||
container_id = Column(String, unique=True, index=True) # Docker container ID
|
||||
name = Column(String, unique=True, index=True)
|
||||
image = Column(String)
|
||||
status = Column(String) # running, stopped, etc.
|
||||
config_json = Column(Text) # Full config as JSON string
|
||||
created_at = Column(DateTime, default=datetime.utcnow)
|
||||
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
||||
|
||||
import os
|
||||
|
||||
# Create engine at module level
|
||||
# Use /app/data for database storage (mounted volume)
|
||||
data_dir = '/app/data'
|
||||
os.makedirs(data_dir, exist_ok=True)
|
||||
db_path = os.path.join(data_dir, 'stronghold.db')
|
||||
engine = create_engine(f"sqlite:///{db_path}")
|
||||
Base.metadata.create_all(bind=engine)
|
||||
|
||||
def get_db():
|
||||
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
||||
db = SessionLocal()
|
||||
try:
|
||||
yield db
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
116
backend/docker_manager.py
Normal file
116
backend/docker_manager.py
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
import docker
|
||||
import os
|
||||
import json
|
||||
|
||||
LABEL_MANAGED = "stronghold.managed"
|
||||
LABEL_VALUE = "true"
|
||||
|
||||
def get_docker_client():
|
||||
"""Get Docker client, automatically detecting Docker or Podman"""
|
||||
try:
|
||||
# Try Docker socket first
|
||||
if os.path.exists('/var/run/docker.sock'):
|
||||
return docker.DockerClient(base_url='unix://var/run/docker.sock')
|
||||
|
||||
# Try Podman rootful
|
||||
if os.path.exists('/run/podman/podman.sock'):
|
||||
return docker.DockerClient(base_url='unix://run/podman/podman.sock')
|
||||
|
||||
# Try Podman rootless
|
||||
xdg_runtime = os.environ.get('XDG_RUNTIME_DIR', '')
|
||||
podman_sock = f'{xdg_runtime}/podman/podman.sock'
|
||||
if xdg_runtime and os.path.exists(podman_sock):
|
||||
return docker.DockerClient(base_url=f'unix://{podman_sock}')
|
||||
|
||||
# Fallback to default
|
||||
return docker.DockerClient(base_url='unix://var/run/docker.sock')
|
||||
except Exception as e:
|
||||
raise Exception(f"Failed to connect to Docker/Podman: {e}")
|
||||
|
||||
def list_containers(client):
|
||||
"""List all Stronghold-managed containers"""
|
||||
filters = {"label": f"{LABEL_MANAGED}={LABEL_VALUE}"}
|
||||
return client.containers.list(all=True, filters=filters)
|
||||
|
||||
def create_container(client, name, config):
|
||||
"""Create a new container with Stronghold label"""
|
||||
# Build environment variables from config
|
||||
environment = {
|
||||
"EULA": "TRUE" if config.get("acceptEULA") else "FALSE",
|
||||
"TYPE": config.get("serverType", "PAPER"),
|
||||
}
|
||||
|
||||
# Add optional environment variables
|
||||
if config.get("version") and config.get("version") != "LATEST":
|
||||
environment["VERSION"] = config["version"]
|
||||
if config.get("memory"):
|
||||
environment["MEMORY"] = config["memory"]
|
||||
if config.get("difficulty"):
|
||||
environment["DIFFICULTY"] = config["difficulty"]
|
||||
if config.get("gamemode"):
|
||||
environment["MODE"] = config["gamemode"]
|
||||
if config.get("levelType"):
|
||||
environment["LEVEL_TYPE"] = config["levelType"]
|
||||
if config.get("motd"):
|
||||
environment["MOTD"] = config["motd"]
|
||||
if config.get("maxPlayers"):
|
||||
environment["MAX_PLAYERS"] = str(config["maxPlayers"])
|
||||
if config.get("viewDistance"):
|
||||
environment["VIEW_DISTANCE"] = str(config["viewDistance"])
|
||||
if not config.get("pvpEnabled", True):
|
||||
environment["PVP"] = "false"
|
||||
if config.get("allowFlight"):
|
||||
environment["ALLOW_FLIGHT"] = "true"
|
||||
if config.get("enableRCON"):
|
||||
environment["ENABLE_RCON"] = "true"
|
||||
if config.get("rconPassword"):
|
||||
environment["RCON_PASSWORD"] = config["rconPassword"]
|
||||
|
||||
# Port bindings (host_port:container_port)
|
||||
port = config.get("port", "25565")
|
||||
port_bindings = {f"{25565}/tcp": int(port)}
|
||||
if config.get("enableRCON"):
|
||||
rcon_port = config.get("rconPort", "25575")
|
||||
port_bindings[f"{25575}/tcp"] = int(rcon_port)
|
||||
|
||||
# Create or get volume
|
||||
volume_name = f"{name}_data"
|
||||
try:
|
||||
client.volumes.get(volume_name)
|
||||
except:
|
||||
client.volumes.create(name=volume_name, labels={LABEL_MANAGED: LABEL_VALUE})
|
||||
|
||||
# Create container with proper volume mount
|
||||
restart_policy = config.get("restartPolicy", "unless-stopped")
|
||||
|
||||
container = client.containers.create(
|
||||
image="itzg/minecraft-server",
|
||||
name=name,
|
||||
environment=environment,
|
||||
ports=port_bindings,
|
||||
volumes=[f"{volume_name}:/data"],
|
||||
labels={LABEL_MANAGED: LABEL_VALUE},
|
||||
restart_policy={"Name": restart_policy} if restart_policy != "no" else None,
|
||||
detach=True
|
||||
)
|
||||
|
||||
return container
|
||||
|
||||
def start_container(client, container_id):
|
||||
"""Start a container"""
|
||||
container = client.containers.get(container_id)
|
||||
container.start()
|
||||
return container
|
||||
|
||||
def stop_container(client, container_id):
|
||||
"""Stop a container"""
|
||||
container = client.containers.get(container_id)
|
||||
container.stop()
|
||||
return container
|
||||
|
||||
def remove_container(client, container_id):
|
||||
"""Remove a container"""
|
||||
container = client.containers.get(container_id)
|
||||
container.remove(force=True)
|
||||
return container
|
||||
|
||||
195
backend/main.py
Normal file
195
backend/main.py
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
from fastapi import FastAPI, HTTPException, Depends
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from sqlalchemy.orm import Session
|
||||
from pydantic import BaseModel
|
||||
from typing import List, Optional
|
||||
import json
|
||||
|
||||
from backend.database import get_db, Container, Base, engine
|
||||
from backend.docker_manager import (
|
||||
get_docker_client, list_containers, create_container,
|
||||
start_container, stop_container, remove_container
|
||||
)
|
||||
|
||||
# Create tables
|
||||
Base.metadata.create_all(bind=engine)
|
||||
|
||||
app = FastAPI(title="Stronghold API")
|
||||
|
||||
# CORS middleware
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["*"],
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
|
||||
# Mount static files (frontend will be served by nginx in production)
|
||||
# app.mount("/", StaticFiles(directory="../frontend", html=True), name="static")
|
||||
|
||||
# Pydantic models
|
||||
class ContainerConfig(BaseModel):
|
||||
serverName: str
|
||||
serverType: str
|
||||
version: Optional[str] = "LATEST"
|
||||
memory: Optional[str] = "2G"
|
||||
port: Optional[str] = "25565"
|
||||
difficulty: Optional[str] = None
|
||||
gamemode: Optional[str] = None
|
||||
levelType: Optional[str] = None
|
||||
motd: Optional[str] = None
|
||||
maxPlayers: Optional[int] = 20
|
||||
viewDistance: Optional[int] = 10
|
||||
acceptEULA: bool = True
|
||||
enableRCON: bool = False
|
||||
rconPort: Optional[str] = "25575"
|
||||
rconPassword: Optional[str] = None
|
||||
pvpEnabled: bool = True
|
||||
allowFlight: bool = False
|
||||
restartPolicy: str = "unless-stopped"
|
||||
|
||||
class ContainerResponse(BaseModel):
|
||||
id: int
|
||||
container_id: str
|
||||
name: str
|
||||
image: str
|
||||
status: str
|
||||
created_at: str
|
||||
|
||||
# API Routes
|
||||
@app.get("/api/containers")
|
||||
def get_containers(db: Session = Depends(get_db)):
|
||||
"""List all Stronghold-managed containers"""
|
||||
try:
|
||||
client = get_docker_client()
|
||||
docker_containers = list_containers(client)
|
||||
|
||||
# Get containers from database
|
||||
db_containers = db.query(Container).all()
|
||||
|
||||
# Merge data
|
||||
result = []
|
||||
for db_container in db_containers:
|
||||
# Find matching docker container
|
||||
docker_container = next(
|
||||
(dc for dc in docker_containers if dc.id == db_container.container_id),
|
||||
None
|
||||
)
|
||||
|
||||
status = docker_container.status if docker_container else "unknown"
|
||||
|
||||
result.append({
|
||||
"id": db_container.id,
|
||||
"container_id": db_container.container_id,
|
||||
"name": db_container.name,
|
||||
"image": db_container.image,
|
||||
"status": status,
|
||||
"created_at": db_container.created_at.isoformat() if db_container.created_at else None
|
||||
})
|
||||
|
||||
return result
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@app.post("/api/containers")
|
||||
def create_container_endpoint(config: ContainerConfig, db: Session = Depends(get_db)):
|
||||
"""Create a new Minecraft server container"""
|
||||
try:
|
||||
client = get_docker_client()
|
||||
|
||||
# Check if name already exists
|
||||
existing = db.query(Container).filter(Container.name == config.serverName).first()
|
||||
if existing:
|
||||
raise HTTPException(status_code=400, detail="Container name already exists")
|
||||
|
||||
# Create container
|
||||
docker_container = create_container(client, config.serverName, config.dict())
|
||||
|
||||
# Save to database
|
||||
db_container = Container(
|
||||
container_id=docker_container.id,
|
||||
name=config.serverName,
|
||||
image="itzg/minecraft-server",
|
||||
status="created",
|
||||
config_json=json.dumps(config.dict())
|
||||
)
|
||||
db.add(db_container)
|
||||
db.commit()
|
||||
db.refresh(db_container)
|
||||
|
||||
# Start container
|
||||
docker_container.start()
|
||||
|
||||
# Update status
|
||||
db_container.status = "running"
|
||||
db.commit()
|
||||
|
||||
return {
|
||||
"id": db_container.id,
|
||||
"container_id": docker_container.id,
|
||||
"name": config.serverName,
|
||||
"status": "running"
|
||||
}
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@app.post("/api/containers/{container_id}/start")
|
||||
def start_container_endpoint(container_id: str, db: Session = Depends(get_db)):
|
||||
"""Start a container"""
|
||||
try:
|
||||
client = get_docker_client()
|
||||
container = start_container(client, container_id)
|
||||
|
||||
# Update database
|
||||
db_container = db.query(Container).filter(Container.container_id == container_id).first()
|
||||
if db_container:
|
||||
db_container.status = "running"
|
||||
db.commit()
|
||||
|
||||
return {"status": "started", "container_id": container_id}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@app.post("/api/containers/{container_id}/stop")
|
||||
def stop_container_endpoint(container_id: str, db: Session = Depends(get_db)):
|
||||
"""Stop a container"""
|
||||
try:
|
||||
client = get_docker_client()
|
||||
container = stop_container(client, container_id)
|
||||
|
||||
# Update database
|
||||
db_container = db.query(Container).filter(Container.container_id == container_id).first()
|
||||
if db_container:
|
||||
db_container.status = "stopped"
|
||||
db.commit()
|
||||
|
||||
return {"status": "stopped", "container_id": container_id}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@app.delete("/api/containers/{container_id}")
|
||||
def delete_container_endpoint(container_id: str, db: Session = Depends(get_db)):
|
||||
"""Delete a container"""
|
||||
try:
|
||||
client = get_docker_client()
|
||||
remove_container(client, container_id)
|
||||
|
||||
# Remove from database
|
||||
db_container = db.query(Container).filter(Container.container_id == container_id).first()
|
||||
if db_container:
|
||||
db.delete(db_container)
|
||||
db.commit()
|
||||
|
||||
return {"status": "deleted", "container_id": container_id}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@app.get("/api/health")
|
||||
def health_check():
|
||||
"""Health check endpoint"""
|
||||
return {"status": "ok"}
|
||||
|
||||
5
backend/requirements.txt
Normal file
5
backend/requirements.txt
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
fastapi==0.104.1
|
||||
uvicorn[standard]==0.24.0
|
||||
docker==7.0.0
|
||||
sqlalchemy==2.0.23
|
||||
|
||||
38
design.md
Normal file
38
design.md
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
# Design
|
||||
|
||||
Take a lot of inspiration from crafty.
|
||||
Make creating a modded server as simple as it is using ATLauncher
|
||||
|
||||
# Philosophy
|
||||
KISS = Keep It Simple Stupid
|
||||
dont make things over complicated
|
||||
|
||||
Keep code clean, readable, and concise.
|
||||
|
||||
Modular
|
||||
|
||||
# Plans
|
||||
This web ui app should be ran in a docker container.
|
||||
User authentication, permissions
|
||||
simple status page for players to see if the server is up
|
||||
|
||||
# References
|
||||
[itzg docker-minecraft-server](https://github.com/itzg/docker-minecraft-server)
|
||||
[itzg docs](https://docker-minecraft-server.readthedocs.io/en/latest/) these docs exist in the main itzg github repo
|
||||
[itzg minecraft proxy](https://github.com/itzg/docker-mc-proxy) used to setup proxy servers like velocity and bungee cord
|
||||
[itzeg mc-router](https://github.com/itzg/mc-router) used to direct client to the right minecraft proxy or server based on requested server address
|
||||
[crafty](https://craftycontrol.com)
|
||||
[docker-rcon-web-admin](https://github.com/itzg/docker-rcon-web-admin)
|
||||
[setupmc.com](https://setupmc.com/java-server/) Not open source but it's a web ui to generate yml files for docker using the itzg container image
|
||||
|
||||
|
||||
# Maybe useful references
|
||||
These are the github repos to other minecraft project that may be useful
|
||||
|
||||
[pterodactyl](https://github.com/pterodactyl/panel)
|
||||
[fork](https://github.com/ForkGG/Fork) This is a Windows based server manager that may have useful ideas.
|
||||
[MCSManager](https://github.com/MCSManager/MCSManager)
|
||||
|
||||
Minecraft launchers for clients. they have tools to download packs and server packs
|
||||
[ATLauncher](https://github.com/ATLauncher/ATLauncher)
|
||||
[Prism Launcher](https://github.com/PrismLauncher/PrismLauncher)
|
||||
0
docker-compose
Normal file
0
docker-compose
Normal file
24
docker-compose.yml
Normal file
24
docker-compose.yml
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
version: '3.8'
|
||||
|
||||
services:
|
||||
stronghold:
|
||||
build: .
|
||||
ports:
|
||||
- "8080:80"
|
||||
volumes:
|
||||
# Socket access for Podman (rootless)
|
||||
# For Podman rootless, mount the socket to /var/run/docker.sock inside container
|
||||
# This way the Docker SDK can find it at the standard location
|
||||
- ${XDG_RUNTIME_DIR}/podman/podman.sock:/var/run/docker.sock:ro
|
||||
# Database persistence
|
||||
- ./data:/app/data
|
||||
# Hot reload frontend (optional, for development)
|
||||
- ./index.html:/usr/share/nginx/html/index.html:ro,z
|
||||
- ./manage.html:/usr/share/nginx/html/manage.html:ro,z
|
||||
environment:
|
||||
# Set working directory for database
|
||||
- PWD=/app/data
|
||||
# Pass XDG_RUNTIME_DIR for Podman rootless
|
||||
- XDG_RUNTIME_DIR=${XDG_RUNTIME_DIR:-/run/user/1000}
|
||||
working_dir: /app/data
|
||||
restart: unless-stopped
|
||||
852
index.html
Normal file
852
index.html
Normal file
|
|
@ -0,0 +1,852 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Stronghold - Minecraft Server Generator</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
||||
padding: 40px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #333;
|
||||
margin-bottom: 10px;
|
||||
font-size: 2.5em;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
color: #666;
|
||||
margin-bottom: 30px;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
.tabs {
|
||||
display: flex;
|
||||
border-bottom: 2px solid #e0e0e0;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.tab {
|
||||
padding: 12px 24px;
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: 1em;
|
||||
font-weight: 500;
|
||||
color: #666;
|
||||
border-bottom: 3px solid transparent;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.tab:hover {
|
||||
color: #667eea;
|
||||
}
|
||||
|
||||
.tab.active {
|
||||
color: #667eea;
|
||||
border-bottom-color: #667eea;
|
||||
}
|
||||
|
||||
.tab-content {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tab-content.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.form-section {
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
font-size: 0.95em;
|
||||
}
|
||||
|
||||
input, select, textarea {
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
border: 2px solid #e0e0e0;
|
||||
border-radius: 6px;
|
||||
font-size: 1em;
|
||||
transition: border-color 0.3s;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
input:focus, select:focus, textarea:focus {
|
||||
outline: none;
|
||||
border-color: #667eea;
|
||||
}
|
||||
|
||||
textarea {
|
||||
resize: vertical;
|
||||
min-height: 80px;
|
||||
}
|
||||
|
||||
.form-row {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.form-row-3 {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
input[type="checkbox"] {
|
||||
width: auto;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.checkbox-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.generate-btn {
|
||||
width: 100%;
|
||||
padding: 15px;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
font-size: 1.1em;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.generate-btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 10px 20px rgba(102, 126, 234, 0.4);
|
||||
}
|
||||
|
||||
.generate-btn:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.preview {
|
||||
margin-top: 30px;
|
||||
padding: 20px;
|
||||
background: #f8f9fa;
|
||||
border-radius: 6px;
|
||||
border: 2px solid #e0e0e0;
|
||||
}
|
||||
|
||||
.preview h3 {
|
||||
margin-bottom: 15px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
pre {
|
||||
background: #2d2d2d;
|
||||
color: #f8f8f2;
|
||||
padding: 15px;
|
||||
border-radius: 6px;
|
||||
overflow-x: auto;
|
||||
font-family: 'Courier New', monospace;
|
||||
font-size: 0.85em;
|
||||
line-height: 1.5;
|
||||
max-height: 500px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.download-btn {
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
background: #28a745;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
font-size: 1em;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
margin-top: 15px;
|
||||
transition: background 0.3s;
|
||||
}
|
||||
|
||||
.download-btn:hover {
|
||||
background: #218838;
|
||||
}
|
||||
|
||||
.download-btn:disabled {
|
||||
background: #ccc;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.info-text {
|
||||
font-size: 0.85em;
|
||||
color: #666;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 1.2em;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-bottom: 15px;
|
||||
margin-top: 20px;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 2px solid #e0e0e0;
|
||||
}
|
||||
|
||||
.modpack-type-section {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.modpack-input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.modpack-input.active {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>🛡️ Stronghold</h1>
|
||||
<p class="subtitle">Minecraft Server Docker Compose Generator</p>
|
||||
|
||||
<div class="tabs">
|
||||
<button class="tab active" data-tab="basic">Basic Configuration</button>
|
||||
<button class="tab" data-tab="modpack">Modpack</button>
|
||||
<button class="tab" data-tab="advanced">Advanced</button>
|
||||
</div>
|
||||
|
||||
<form id="serverForm">
|
||||
<!-- Basic Configuration Tab -->
|
||||
<div class="tab-content active" id="basic-tab">
|
||||
<div class="form-section">
|
||||
<label for="serverName">Server Name</label>
|
||||
<input type="text" id="serverName" placeholder="my-minecraft-server" value="minecraft">
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="form-section">
|
||||
<label for="serverType">Server Type</label>
|
||||
<select id="serverType">
|
||||
<option value="VANILLA">Vanilla</option>
|
||||
<option value="PAPER" selected>Paper (Recommended)</option>
|
||||
<option value="FORGE">Forge (Modded)</option>
|
||||
<option value="FABRIC">Fabric (Modded)</option>
|
||||
<option value="SPIGOT">Spigot</option>
|
||||
<option value="BUKKIT">Bukkit</option>
|
||||
<option value="MAGMA">Magma (Mods + Plugins)</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-section">
|
||||
<label for="version">Minecraft Version</label>
|
||||
<input type="text" id="version" placeholder="LATEST or 1.20.1" value="LATEST">
|
||||
<span class="info-text">Use LATEST for newest version, or specify version like 1.20.1</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="form-section">
|
||||
<label for="memory">Memory Allocation</label>
|
||||
<select id="memory">
|
||||
<option value="1G">1GB (Small)</option>
|
||||
<option value="2G" selected>2GB (Recommended for most)</option>
|
||||
<option value="4G">4GB (Medium)</option>
|
||||
<option value="8G">8GB (Large/Modded)</option>
|
||||
<option value="16G">16GB (Very Large)</option>
|
||||
<option value="custom">Custom</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-section" id="customMemorySection" style="display: none;">
|
||||
<label for="customMemory">Custom Memory</label>
|
||||
<input type="text" id="customMemory" placeholder="32G">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="form-section">
|
||||
<label for="port">Server Port</label>
|
||||
<input type="number" id="port" value="25565" min="1024" max="65535">
|
||||
<span class="info-text">Default Minecraft port is 25565</span>
|
||||
</div>
|
||||
|
||||
<div class="form-section">
|
||||
<label for="difficulty">Difficulty</label>
|
||||
<select id="difficulty">
|
||||
<option value="">Default</option>
|
||||
<option value="peaceful">Peaceful</option>
|
||||
<option value="easy" selected>Easy</option>
|
||||
<option value="normal">Normal</option>
|
||||
<option value="hard">Hard</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="form-section">
|
||||
<label for="gamemode">Default Game Mode</label>
|
||||
<select id="gamemode">
|
||||
<option value="">Default</option>
|
||||
<option value="survival" selected>Survival</option>
|
||||
<option value="creative">Creative</option>
|
||||
<option value="adventure">Adventure</option>
|
||||
<option value="spectator">Spectator</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-section">
|
||||
<label for="levelType">World Type</label>
|
||||
<select id="levelType">
|
||||
<option value="">Default</option>
|
||||
<option value="DEFAULT">Default</option>
|
||||
<option value="FLAT">Flat</option>
|
||||
<option value="LARGEBIOMES">Large Biomes</option>
|
||||
<option value="AMPLIFIED">Amplified</option>
|
||||
<option value="CUSTOMIZED">Customized</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-section">
|
||||
<label for="motd">Server MOTD (Message of the Day)</label>
|
||||
<input type="text" id="motd" placeholder="A Minecraft Server" maxlength="59">
|
||||
<span class="info-text">Message shown in server list (max 59 characters)</span>
|
||||
</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="form-section">
|
||||
<label for="maxPlayers">Max Players</label>
|
||||
<input type="number" id="maxPlayers" value="20" min="1" max="999">
|
||||
</div>
|
||||
|
||||
<div class="form-section">
|
||||
<label for="viewDistance">View Distance (chunks)</label>
|
||||
<input type="number" id="viewDistance" value="10" min="3" max="32">
|
||||
<span class="info-text">Higher = better visibility but more CPU usage</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-section">
|
||||
<label class="checkbox-label">
|
||||
<input type="checkbox" id="acceptEULA" checked>
|
||||
Accept Minecraft EULA
|
||||
</label>
|
||||
<span class="info-text">Required to run a Minecraft server</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modpack Tab -->
|
||||
<div class="tab-content" id="modpack-tab">
|
||||
<div class="section-title">Modpack Installation</div>
|
||||
|
||||
<div class="form-section">
|
||||
<label for="modpackType">Modpack Source</label>
|
||||
<select id="modpackType">
|
||||
<option value="none">No Modpack (Vanilla/Plugins only)</option>
|
||||
<option value="curseforge">CurseForge Modpack</option>
|
||||
<option value="modrinth">Modrinth Modpack</option>
|
||||
<option value="url">Download from URL</option>
|
||||
<option value="local">Local File Path</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="modpack-input" id="curseforge-input">
|
||||
<div class="form-section">
|
||||
<label for="curseforgeFile">CurseForge Server Pack Path</label>
|
||||
<input type="text" id="curseforgeFile" placeholder="/modpacks/modpack-server.zip">
|
||||
<span class="info-text">Path to CurseForge server pack zip file inside container</span>
|
||||
</div>
|
||||
<div class="form-section">
|
||||
<label for="useCurseforgeType">Use CurseForge TYPE</label>
|
||||
<label class="checkbox-label">
|
||||
<input type="checkbox" id="useCurseforgeType" checked>
|
||||
Automatically set TYPE to CURSEFORGE
|
||||
</label>
|
||||
<span class="info-text">Uncheck if you want to manually set server type</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modpack-input" id="modrinth-input">
|
||||
<div class="form-section">
|
||||
<label for="modrinthProject">Modrinth Project ID or Slug</label>
|
||||
<input type="text" id="modrinthProject" placeholder="allthemods">
|
||||
<span class="info-text">Modrinth project identifier</span>
|
||||
</div>
|
||||
<div class="form-section">
|
||||
<label for="modrinthVersion">Version ID (optional)</label>
|
||||
<input type="text" id="modrinthVersion" placeholder="Leave empty for latest">
|
||||
<span class="info-text">Specific version ID, or leave empty for latest</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modpack-input" id="url-input">
|
||||
<div class="form-section">
|
||||
<label for="modpackUrl">Modpack URL</label>
|
||||
<input type="url" id="modpackUrl" placeholder="https://example.com/modpack.zip">
|
||||
<span class="info-text">Direct download URL for modpack zip file</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modpack-input" id="local-input">
|
||||
<div class="form-section">
|
||||
<label for="modpackPath">Local Modpack Path</label>
|
||||
<input type="text" id="modpackPath" placeholder="/modpacks/my-modpack.zip">
|
||||
<span class="info-text">Path to modpack file inside container (use volume mount)</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-section">
|
||||
<label class="checkbox-label">
|
||||
<input type="checkbox" id="removeOldMods">
|
||||
Remove Old Mods/Plugins Before Installing
|
||||
</label>
|
||||
<span class="info-text">Deletes existing mods/plugins before installing modpack</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Advanced Tab -->
|
||||
<div class="tab-content" id="advanced-tab">
|
||||
<div class="section-title">RCON Configuration</div>
|
||||
|
||||
<div class="form-section">
|
||||
<label class="checkbox-label">
|
||||
<input type="checkbox" id="enableRCON">
|
||||
Enable RCON (Remote Console)
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div id="rconConfig" style="display: none;">
|
||||
<div class="form-row">
|
||||
<div class="form-section">
|
||||
<label for="rconPort">RCON Port</label>
|
||||
<input type="number" id="rconPort" value="25575" min="1024" max="65535">
|
||||
</div>
|
||||
<div class="form-section">
|
||||
<label for="rconPassword">RCON Password</label>
|
||||
<input type="password" id="rconPassword" placeholder="changeit">
|
||||
<span class="info-text">Choose a strong password</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section-title">Server Properties</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="form-section">
|
||||
<label class="checkbox-label">
|
||||
<input type="checkbox" id="pvpEnabled" checked>
|
||||
Enable PVP
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-section">
|
||||
<label class="checkbox-label">
|
||||
<input type="checkbox" id="allowFlight">
|
||||
Allow Flight
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-section">
|
||||
<label for="maxTickTime">Max Tick Time (ms)</label>
|
||||
<input type="number" id="maxTickTime" placeholder="-1 (no limit)" value="-1">
|
||||
<span class="info-text">Maximum time a single tick can take (-1 = no limit)</span>
|
||||
</div>
|
||||
|
||||
<div class="form-section">
|
||||
<label for="ops">Server Operators (comma-separated Minecraft usernames)</label>
|
||||
<input type="text" id="ops" placeholder="Player1,Player2">
|
||||
<span class="info-text">Players who will have operator permissions</span>
|
||||
</div>
|
||||
|
||||
<div class="section-title">Container Options</div>
|
||||
|
||||
<div class="form-row">
|
||||
<div class="form-section">
|
||||
<label for="restartPolicy">Restart Policy</label>
|
||||
<select id="restartPolicy">
|
||||
<option value="no">No</option>
|
||||
<option value="always">Always</option>
|
||||
<option value="on-failure">On Failure</option>
|
||||
<option value="unless-stopped" selected>Unless Stopped</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-section">
|
||||
<label for="timezone">Timezone</label>
|
||||
<input type="text" id="timezone" placeholder="America/New_York" value="UTC">
|
||||
<span class="info-text">Server timezone (e.g., America/New_York, Europe/London)</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-section">
|
||||
<label class="checkbox-label">
|
||||
<input type="checkbox" id="rollingLogs">
|
||||
Enable Rolling Logs
|
||||
</label>
|
||||
<span class="info-text">Automatically delete old log files</span>
|
||||
</div>
|
||||
|
||||
<div class="form-section">
|
||||
<label class="checkbox-label">
|
||||
<input type="checkbox" id="overrideServerProperties">
|
||||
Override Server Properties
|
||||
</label>
|
||||
<span class="info-text">Allow environment variables to override server.properties</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="generate-btn" id="submitBtn">Create Server</button>
|
||||
<button type="button" class="generate-btn" id="generateYamlBtn" style="margin-top: 10px; background: #6c757d;">Generate YAML Only</button>
|
||||
</form>
|
||||
|
||||
<div id="preview" class="preview" style="display: none;">
|
||||
<h3>Generated docker-compose.yml</h3>
|
||||
<pre id="yamlPreview"></pre>
|
||||
<button class="download-btn" id="downloadBtn">Download docker-compose.yml</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Tab switching
|
||||
document.querySelectorAll('.tab').forEach(tab => {
|
||||
tab.addEventListener('click', () => {
|
||||
const targetTab = tab.dataset.tab;
|
||||
|
||||
// Update tabs
|
||||
document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
|
||||
tab.classList.add('active');
|
||||
|
||||
// Update tab content
|
||||
document.querySelectorAll('.tab-content').forEach(content => {
|
||||
content.classList.remove('active');
|
||||
});
|
||||
document.getElementById(`${targetTab}-tab`).classList.add('active');
|
||||
});
|
||||
});
|
||||
|
||||
// Modpack type switching
|
||||
const modpackType = document.getElementById('modpackType');
|
||||
modpackType.addEventListener('change', () => {
|
||||
document.querySelectorAll('.modpack-input').forEach(input => {
|
||||
input.classList.remove('active');
|
||||
});
|
||||
if (modpackType.value !== 'none') {
|
||||
const activeInput = document.getElementById(`${modpackType.value}-input`);
|
||||
if (activeInput) {
|
||||
activeInput.classList.add('active');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// RCON config toggle
|
||||
document.getElementById('enableRCON').addEventListener('change', (e) => {
|
||||
document.getElementById('rconConfig').style.display = e.target.checked ? 'block' : 'none';
|
||||
});
|
||||
|
||||
// Custom memory toggle
|
||||
const memorySelect = document.getElementById('memory');
|
||||
const customMemorySection = document.getElementById('customMemorySection');
|
||||
memorySelect.addEventListener('change', () => {
|
||||
customMemorySection.style.display = memorySelect.value === 'custom' ? 'block' : 'none';
|
||||
});
|
||||
|
||||
// Form submission
|
||||
const form = document.getElementById('serverForm');
|
||||
const preview = document.getElementById('preview');
|
||||
const yamlPreview = document.getElementById('yamlPreview');
|
||||
const downloadBtn = document.getElementById('downloadBtn');
|
||||
|
||||
const API_BASE = window.location.origin;
|
||||
|
||||
// Generate YAML only (existing functionality)
|
||||
document.getElementById('generateYamlBtn').addEventListener('click', () => {
|
||||
const config = gatherFormData();
|
||||
const yaml = generateDockerCompose(config);
|
||||
|
||||
yamlPreview.textContent = yaml;
|
||||
preview.style.display = 'block';
|
||||
downloadBtn.disabled = false;
|
||||
|
||||
downloadBtn.onclick = () => {
|
||||
const blob = new Blob([yaml], { type: 'text/yaml' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = 'docker-compose.yml';
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
URL.revokeObjectURL(url);
|
||||
};
|
||||
});
|
||||
|
||||
// Create server (new functionality)
|
||||
form.addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
const submitBtn = document.getElementById('submitBtn');
|
||||
submitBtn.disabled = true;
|
||||
submitBtn.textContent = 'Creating Server...';
|
||||
|
||||
try {
|
||||
const config = gatherFormData();
|
||||
|
||||
// Submit to API
|
||||
const response = await fetch(`${API_BASE}/api/containers`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(config),
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (response.ok) {
|
||||
// Show success message and redirect
|
||||
preview.style.display = 'block';
|
||||
preview.innerHTML = `
|
||||
<h3 style="color: #28a745;">✓ Server Created Successfully!</h3>
|
||||
<p><strong>Name:</strong> ${result.name}</p>
|
||||
<p><strong>Status:</strong> ${result.status}</p>
|
||||
<br>
|
||||
<a href="manage.html" class="btn btn-primary" style="text-decoration: none; display: inline-block; padding: 10px 20px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border-radius: 6px;">Go to Manage Page</a>
|
||||
`;
|
||||
} else {
|
||||
throw new Error(result.detail || 'Failed to create server');
|
||||
}
|
||||
} catch (error) {
|
||||
preview.style.display = 'block';
|
||||
preview.innerHTML = `
|
||||
<h3 style="color: #dc3545;">Error Creating Server</h3>
|
||||
<p>${error.message}</p>
|
||||
`;
|
||||
} finally {
|
||||
submitBtn.disabled = false;
|
||||
submitBtn.textContent = 'Create Server';
|
||||
}
|
||||
});
|
||||
|
||||
function gatherFormData() {
|
||||
return {
|
||||
serverName: document.getElementById('serverName').value || 'minecraft',
|
||||
serverType: document.getElementById('serverType').value,
|
||||
version: document.getElementById('version').value || 'LATEST',
|
||||
memory: memorySelect.value === 'custom'
|
||||
? document.getElementById('customMemory').value || '2G'
|
||||
: memorySelect.value,
|
||||
port: document.getElementById('port').value || '25565',
|
||||
difficulty: document.getElementById('difficulty').value,
|
||||
gamemode: document.getElementById('gamemode').value,
|
||||
levelType: document.getElementById('levelType').value,
|
||||
motd: document.getElementById('motd').value,
|
||||
maxPlayers: document.getElementById('maxPlayers').value,
|
||||
viewDistance: document.getElementById('viewDistance').value,
|
||||
acceptEULA: document.getElementById('acceptEULA').checked,
|
||||
|
||||
// Modpack
|
||||
modpackType: document.getElementById('modpackType').value,
|
||||
curseforgeFile: document.getElementById('curseforgeFile').value,
|
||||
useCurseforgeType: document.getElementById('useCurseforgeType').checked,
|
||||
modrinthProject: document.getElementById('modrinthProject').value,
|
||||
modrinthVersion: document.getElementById('modrinthVersion').value,
|
||||
modpackUrl: document.getElementById('modpackUrl').value,
|
||||
modpackPath: document.getElementById('modpackPath').value,
|
||||
removeOldMods: document.getElementById('removeOldMods').checked,
|
||||
|
||||
// RCON
|
||||
enableRCON: document.getElementById('enableRCON').checked,
|
||||
rconPort: document.getElementById('rconPort').value,
|
||||
rconPassword: document.getElementById('rconPassword').value,
|
||||
|
||||
// Advanced
|
||||
pvpEnabled: document.getElementById('pvpEnabled').checked,
|
||||
allowFlight: document.getElementById('allowFlight').checked,
|
||||
maxTickTime: document.getElementById('maxTickTime').value,
|
||||
ops: document.getElementById('ops').value,
|
||||
restartPolicy: document.getElementById('restartPolicy').value,
|
||||
timezone: document.getElementById('timezone').value,
|
||||
rollingLogs: document.getElementById('rollingLogs').checked,
|
||||
overrideServerProperties: document.getElementById('overrideServerProperties').checked
|
||||
};
|
||||
}
|
||||
|
||||
function generateDockerCompose(config) {
|
||||
let yaml = `services:
|
||||
${config.serverName}:
|
||||
image: itzg/minecraft-server
|
||||
container_name: ${config.serverName}
|
||||
ports:
|
||||
- "${config.port}:25565"`;
|
||||
|
||||
// RCON port if enabled
|
||||
if (config.enableRCON) {
|
||||
yaml += `\n - "${config.rconPort}:25575"`;
|
||||
}
|
||||
|
||||
yaml += `\n volumes:
|
||||
- ${config.serverName}_data:/data`;
|
||||
|
||||
// Modpack volume mount if using local file
|
||||
if (config.modpackType === 'curseforge' && config.curseforgeFile) {
|
||||
yaml += `\n - ./modpacks:/modpacks:ro`;
|
||||
} else if (config.modpackType === 'local' && config.modpackPath) {
|
||||
const modpackDir = config.modpackPath.substring(0, config.modpackPath.lastIndexOf('/'));
|
||||
if (modpackDir) {
|
||||
yaml += `\n - ./modpacks:${modpackDir}:ro`;
|
||||
}
|
||||
}
|
||||
|
||||
yaml += `\n environment:`;
|
||||
|
||||
// EULA
|
||||
if (config.acceptEULA) {
|
||||
yaml += `\n EULA: "TRUE"`;
|
||||
}
|
||||
|
||||
// Server Type
|
||||
let serverType = config.serverType;
|
||||
if (config.modpackType === 'curseforge' && config.useCurseforgeType) {
|
||||
serverType = 'CURSEFORGE';
|
||||
} else if (config.modpackType === 'modrinth') {
|
||||
serverType = config.serverType; // Keep original or could be auto-detected
|
||||
}
|
||||
yaml += `\n TYPE: ${serverType}`;
|
||||
|
||||
// Version
|
||||
if (config.version && config.version !== 'LATEST') {
|
||||
yaml += `\n VERSION: ${config.version}`;
|
||||
}
|
||||
|
||||
// Memory
|
||||
if (config.memory) {
|
||||
yaml += `\n MEMORY: ${config.memory}`;
|
||||
}
|
||||
|
||||
// Modpack configuration
|
||||
if (config.modpackType === 'curseforge' && config.curseforgeFile) {
|
||||
yaml += `\n CF_SERVER_MOD: ${config.curseforgeFile}`;
|
||||
} else if (config.modpackType === 'modrinth' && config.modrinthProject) {
|
||||
yaml += `\n MODPACK: modrinth:${config.modrinthProject}`;
|
||||
if (config.modrinthVersion) {
|
||||
yaml += `:${config.modrinthVersion}`;
|
||||
}
|
||||
} else if (config.modpackType === 'url' && config.modpackUrl) {
|
||||
yaml += `\n MODPACK: ${config.modpackUrl}`;
|
||||
} else if (config.modpackType === 'local' && config.modpackPath) {
|
||||
yaml += `\n MODPACK: ${config.modpackPath}`;
|
||||
}
|
||||
|
||||
if (config.removeOldMods) {
|
||||
yaml += `\n REMOVE_OLD_MODS: "TRUE"`;
|
||||
}
|
||||
|
||||
// RCON
|
||||
if (config.enableRCON) {
|
||||
yaml += `\n ENABLE_RCON: "true"`;
|
||||
if (config.rconPassword) {
|
||||
yaml += `\n RCON_PASSWORD: ${config.rconPassword}`;
|
||||
}
|
||||
}
|
||||
|
||||
// Difficulty
|
||||
if (config.difficulty) {
|
||||
yaml += `\n DIFFICULTY: ${config.difficulty}`;
|
||||
}
|
||||
|
||||
// Game Mode
|
||||
if (config.gamemode) {
|
||||
yaml += `\n MODE: ${config.gamemode}`;
|
||||
}
|
||||
|
||||
// Level Type
|
||||
if (config.levelType) {
|
||||
yaml += `\n LEVEL_TYPE: ${config.levelType}`;
|
||||
}
|
||||
|
||||
// MOTD
|
||||
if (config.motd) {
|
||||
yaml += `\n MOTD: "${config.motd}"`;
|
||||
}
|
||||
|
||||
// Max Players
|
||||
if (config.maxPlayers) {
|
||||
yaml += `\n MAX_PLAYERS: ${config.maxPlayers}`;
|
||||
}
|
||||
|
||||
// View Distance
|
||||
if (config.viewDistance) {
|
||||
yaml += `\n VIEW_DISTANCE: ${config.viewDistance}`;
|
||||
}
|
||||
|
||||
// PVP
|
||||
if (!config.pvpEnabled) {
|
||||
yaml += `\n PVP: "false"`;
|
||||
}
|
||||
|
||||
// Allow Flight
|
||||
if (config.allowFlight) {
|
||||
yaml += `\n ALLOW_FLIGHT: "true"`;
|
||||
}
|
||||
|
||||
// Max Tick Time
|
||||
if (config.maxTickTime && config.maxTickTime !== '-1') {
|
||||
yaml += `\n MAX_TICK_TIME: ${config.maxTickTime}`;
|
||||
}
|
||||
|
||||
// Ops
|
||||
if (config.ops) {
|
||||
yaml += `\n OPS: "${config.ops}"`;
|
||||
}
|
||||
|
||||
// Timezone
|
||||
if (config.timezone && config.timezone !== 'UTC') {
|
||||
yaml += `\n TZ: ${config.timezone}`;
|
||||
}
|
||||
|
||||
// Rolling Logs
|
||||
if (config.rollingLogs) {
|
||||
yaml += `\n ENABLE_ROLLING_LOGS: "true"`;
|
||||
}
|
||||
|
||||
// Override Server Properties
|
||||
if (config.overrideServerProperties) {
|
||||
yaml += `\n OVERRIDE_SERVER_PROPERTIES: "true"`;
|
||||
}
|
||||
|
||||
// Restart Policy
|
||||
yaml += `\n restart: ${config.restartPolicy}`;
|
||||
|
||||
yaml += `\n\nvolumes:
|
||||
${config.serverName}_data:`;
|
||||
|
||||
return yaml;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
292
manage.html
Normal file
292
manage.html
Normal file
|
|
@ -0,0 +1,292 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Manage Servers - Stronghold</title>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
min-height: 100vh;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
||||
padding: 40px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #333;
|
||||
margin-bottom: 10px;
|
||||
font-size: 2.5em;
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 10px 20px;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
font-size: 1em;
|
||||
font-weight: 500;
|
||||
transition: all 0.3s;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
|
||||
}
|
||||
|
||||
.btn-success {
|
||||
background: #28a745;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-danger {
|
||||
background: #dc3545;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-warning {
|
||||
background: #ffc107;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.btn-sm {
|
||||
padding: 6px 12px;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.servers-grid {
|
||||
display: grid;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.server-card {
|
||||
border: 2px solid #e0e0e0;
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.server-info h3 {
|
||||
color: #333;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.server-info p {
|
||||
color: #666;
|
||||
margin: 4px 0;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.status {
|
||||
display: inline-block;
|
||||
padding: 4px 12px;
|
||||
border-radius: 12px;
|
||||
font-size: 0.85em;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.status-running {
|
||||
background: #d4edda;
|
||||
color: #155724;
|
||||
}
|
||||
|
||||
.status-stopped {
|
||||
background: #f8d7da;
|
||||
color: #721c24;
|
||||
}
|
||||
|
||||
.status-unknown {
|
||||
background: #e2e3e5;
|
||||
color: #383d41;
|
||||
}
|
||||
|
||||
.server-actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.loading {
|
||||
text-align: center;
|
||||
padding: 40px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
text-align: center;
|
||||
padding: 60px 20px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.empty-state h3 {
|
||||
margin-bottom: 10px;
|
||||
color: #333;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<div>
|
||||
<h1>🛡️ Stronghold</h1>
|
||||
<p style="color: #666;">Manage Your Minecraft Servers</p>
|
||||
</div>
|
||||
<a href="index.html" class="btn btn-primary">Create New Server</a>
|
||||
</div>
|
||||
|
||||
<div id="serversContainer">
|
||||
<div class="loading">Loading servers...</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const API_BASE = window.location.origin;
|
||||
|
||||
async function loadServers() {
|
||||
try {
|
||||
const response = await fetch(`${API_BASE}/api/containers`);
|
||||
const servers = await response.json();
|
||||
|
||||
const container = document.getElementById('serversContainer');
|
||||
|
||||
if (servers.length === 0) {
|
||||
container.innerHTML = `
|
||||
<div class="empty-state">
|
||||
<h3>No servers found</h3>
|
||||
<p>Create your first Minecraft server to get started!</p>
|
||||
<br>
|
||||
<a href="index.html" class="btn btn-primary">Create Server</a>
|
||||
</div>
|
||||
`;
|
||||
return;
|
||||
}
|
||||
|
||||
container.innerHTML = '<div class="servers-grid"></div>';
|
||||
const grid = container.querySelector('.servers-grid');
|
||||
|
||||
servers.forEach(server => {
|
||||
const card = document.createElement('div');
|
||||
card.className = 'server-card';
|
||||
|
||||
const statusClass = server.status === 'running' ? 'status-running' :
|
||||
server.status === 'stopped' ? 'status-stopped' : 'status-unknown';
|
||||
|
||||
card.innerHTML = `
|
||||
<div class="server-info">
|
||||
<h3>${server.name}</h3>
|
||||
<p><strong>Image:</strong> ${server.image}</p>
|
||||
<p><strong>Status:</strong> <span class="status ${statusClass}">${server.status}</span></p>
|
||||
<p><strong>Created:</strong> ${new Date(server.created_at).toLocaleString()}</p>
|
||||
</div>
|
||||
<div class="server-actions">
|
||||
${server.status === 'running'
|
||||
? `<button class="btn btn-warning btn-sm" onclick="stopServer('${server.container_id}', '${server.name}')">Stop</button>`
|
||||
: `<button class="btn btn-success btn-sm" onclick="startServer('${server.container_id}', '${server.name}')">Start</button>`
|
||||
}
|
||||
<button class="btn btn-danger btn-sm" onclick="deleteServer('${server.container_id}', '${server.name}')">Delete</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
grid.appendChild(card);
|
||||
});
|
||||
} catch (error) {
|
||||
document.getElementById('serversContainer').innerHTML =
|
||||
`<div class="empty-state"><h3>Error loading servers</h3><p>${error.message}</p></div>`;
|
||||
}
|
||||
}
|
||||
|
||||
async function startServer(containerId, name) {
|
||||
if (!confirm(`Start server "${name}"?`)) return;
|
||||
|
||||
try {
|
||||
const response = await fetch(`${API_BASE}/api/containers/${containerId}/start`, {
|
||||
method: 'POST'
|
||||
});
|
||||
const result = await response.json();
|
||||
if (response.ok) {
|
||||
alert('Server started successfully!');
|
||||
loadServers();
|
||||
} else {
|
||||
alert('Error: ' + (result.detail || 'Unknown error'));
|
||||
}
|
||||
} catch (error) {
|
||||
alert('Error: ' + error.message);
|
||||
}
|
||||
}
|
||||
|
||||
async function stopServer(containerId, name) {
|
||||
if (!confirm(`Stop server "${name}"?`)) return;
|
||||
|
||||
try {
|
||||
const response = await fetch(`${API_BASE}/api/containers/${containerId}/stop`, {
|
||||
method: 'POST'
|
||||
});
|
||||
const result = await response.json();
|
||||
if (response.ok) {
|
||||
alert('Server stopped successfully!');
|
||||
loadServers();
|
||||
} else {
|
||||
alert('Error: ' + (result.detail || 'Unknown error'));
|
||||
}
|
||||
} catch (error) {
|
||||
alert('Error: ' + error.message);
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteServer(containerId, name) {
|
||||
if (!confirm(`Delete server "${name}"? This will remove the container and cannot be undone.`)) return;
|
||||
|
||||
try {
|
||||
const response = await fetch(`${API_BASE}/api/containers/${containerId}`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
const result = await response.json();
|
||||
if (response.ok) {
|
||||
alert('Server deleted successfully!');
|
||||
loadServers();
|
||||
} else {
|
||||
alert('Error: ' + (result.detail || 'Unknown error'));
|
||||
}
|
||||
} catch (error) {
|
||||
alert('Error: ' + error.message);
|
||||
}
|
||||
}
|
||||
|
||||
// Load servers on page load
|
||||
loadServers();
|
||||
|
||||
// Refresh every 5 seconds
|
||||
setInterval(loadServers, 5000);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
103
references/SUMMARY.md
Normal file
103
references/SUMMARY.md
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
# Reference Projects Summary
|
||||
|
||||
This directory contains detailed analysis of reference projects for the Stronghold Minecraft server management tool.
|
||||
|
||||
## Files
|
||||
|
||||
1. **itzg-projects.md** - Core Docker projects by itzg that Stronghold will integrate with:
|
||||
- docker-minecraft-server
|
||||
- docker-mc-proxy
|
||||
- mc-router
|
||||
- docker-rcon-web-admin
|
||||
|
||||
2. **server-managers.md** - Existing web-based server management tools:
|
||||
- Crafty (CraftyControl)
|
||||
- Pterodactyl Panel
|
||||
- Fork (ForkGG)
|
||||
- MCSManager
|
||||
- setupmc.com
|
||||
|
||||
3. **launchers.md** - Client-side launchers with excellent modpack workflows:
|
||||
- ATLauncher
|
||||
- Prism Launcher
|
||||
|
||||
4. **examples/** - Docker Compose example files from itzg repository:
|
||||
- docker-compose-big.yml (Large Biomes world type)
|
||||
- docker-compose-curseforge-atm7.yaml (All The Mods 7 modpack)
|
||||
- docker-compose-curseforge.yml (Basic CurseForge example)
|
||||
- docker-compose-magma.yml (Hybrid mods + plugins)
|
||||
- docker-compose-rconcmd.yml (Advanced RCON commands)
|
||||
- EXAMPLES-ANALYSIS.md (Detailed analysis of each example)
|
||||
|
||||
## Key Insights
|
||||
|
||||
### Architecture Recommendations
|
||||
- **Keep it simple** (KISS): Docker API directly, no agents/daemons needed initially
|
||||
- **Start without database**: Use file-based configuration, add database later if needed
|
||||
- **Node.js stack**: Could work well (like MCSManager but simpler)
|
||||
- **Single-host focus**: Start with single Docker host, expand later
|
||||
|
||||
### Feature Priorities
|
||||
1. **Server CRUD**: Create, read, update, delete servers
|
||||
2. **Configuration UI**: User-friendly interface for itzg container environment variables
|
||||
3. **Console Access**: RCON integration for server management
|
||||
4. **File Browser**: Access server files (worlds, configs, mods)
|
||||
5. **Modpack Support**: ATLauncher-like experience for server creation
|
||||
|
||||
### Technical Stack Suggestions
|
||||
- **Backend**: Node.js/Express or Python/FastAPI
|
||||
- **Frontend**: React, Vue, or SvelteKit
|
||||
- **Docker**: Direct Docker API integration
|
||||
- **Storage**: File-based configs initially, optional database later
|
||||
- **APIs**: Modrinth, CurseForge for modpack integration
|
||||
|
||||
### UI/UX Principles
|
||||
- Take inspiration from Crafty and Fork for clean, intuitive interfaces
|
||||
- Follow ATLauncher's model for modpack installation simplicity
|
||||
- Use setupmc.com as reference for configuration UI patterns
|
||||
- Prioritize common workflows over advanced features
|
||||
|
||||
### Implementation Phases
|
||||
|
||||
**MVP (Phase 1)**
|
||||
- Basic Docker integration
|
||||
- Simple server creation/management
|
||||
- Basic web UI
|
||||
- Console access
|
||||
|
||||
**V1.0 (Phase 2)**
|
||||
- Full configuration UI
|
||||
- File browser
|
||||
- Modpack installation (basic)
|
||||
- Proxy server support
|
||||
|
||||
**V1.5+ (Phase 3)**
|
||||
- Modpack browser
|
||||
- Advanced features
|
||||
- Templates/presets
|
||||
- Backup system
|
||||
- mc-router integration
|
||||
|
||||
## Notes on Reference Projects
|
||||
|
||||
### Most Relevant
|
||||
1. **itzg/docker-minecraft-server**: Core technology Stronghold will use
|
||||
2. **itzg examples**: Real-world docker-compose configurations showing patterns and edge cases
|
||||
3. **setupmc.com**: Shows how to simplify Docker config generation
|
||||
4. **ATLauncher**: Target UX for modpack installation
|
||||
5. **Crafty**: Good UI/UX patterns to follow
|
||||
|
||||
### Study but Don't Copy
|
||||
1. **Pterodactyl**: Too complex, but has good separation of concerns
|
||||
2. **MCSManager**: Good architecture ideas, but agent model overkill for Docker
|
||||
3. **Fork**: Great UX, but Windows-focused
|
||||
|
||||
## Questions to Resolve
|
||||
|
||||
Based on these references, Stronghold needs to decide:
|
||||
1. **Tech Stack**: Node.js vs Python vs Go?
|
||||
2. **Database**: Start with files or include database from start?
|
||||
3. **Multi-user**: Single-user MVP or multi-user from start?
|
||||
4. **Deployment**: Single container, docker-compose, or microservices?
|
||||
5. **Modpack APIs**: Which to support first (Modrinth, CurseForge, both)?
|
||||
|
||||
207
references/examples/ANALYSIS.md
Normal file
207
references/examples/ANALYSIS.md
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
# Docker Compose Examples Analysis
|
||||
|
||||
This document analyzes various docker-compose.yml examples to identify patterns, edge cases, and implementation requirements for Stronghold.
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Basic Server Setup
|
||||
|
||||
**Pattern Elements**:
|
||||
- Image: `itzg/minecraft-server`
|
||||
- Required: `EULA=TRUE`
|
||||
- Port mapping: `25565:25565`
|
||||
- Volume: Persistent data storage
|
||||
- Environment variables for configuration
|
||||
|
||||
### Modded Server Setup
|
||||
|
||||
**Pattern Elements**:
|
||||
- `TYPE`: FORGE, FABRIC, or other mod loader
|
||||
- `MODPACK` or `MODS`: Modpack/mod installation
|
||||
- Additional memory allocation
|
||||
- Mod volume mounts (`/mods`)
|
||||
- Config volume mounts (`/config`)
|
||||
|
||||
### Plugin Server Setup
|
||||
|
||||
**Pattern Elements**:
|
||||
- `TYPE`: PAPER, SPIGOT, BUKKIT
|
||||
- Plugin volume mounts (`/plugins`)
|
||||
- `PLUGINS` environment variable or volume
|
||||
|
||||
### Proxy Server Setup
|
||||
|
||||
**Pattern Elements**:
|
||||
- Image: `itzg/mc-proxy`
|
||||
- `PROXY_TYPE`: BUNGEE, VELOCITY, WATERFALL
|
||||
- Backend server configuration
|
||||
- Network linking
|
||||
|
||||
## Edge Cases to Handle
|
||||
|
||||
### 1. Multiple Mod Sources
|
||||
```yaml
|
||||
environment:
|
||||
COPY_MODS_SRC: /mods-common,/mods-local
|
||||
volumes:
|
||||
- ../shared-mods:/mods-common:ro
|
||||
- ./local-mods:/mods-local:ro
|
||||
```
|
||||
**Stronghold needs**: UI to manage multiple mod source directories
|
||||
|
||||
### 2. Generic Pack with Custom Configuration
|
||||
```yaml
|
||||
environment:
|
||||
GENERIC_PACK: https://example.com/server-pack.zip
|
||||
GENERIC_PACKS_DISABLE_MODS: "conflicting-mod.jar"
|
||||
APPLY_EXTRA_FILES: "config/server.properties<https://example.com/custom.properties"
|
||||
```
|
||||
**Stronghold needs**: Support for generic packs and file patching
|
||||
|
||||
### 3. Environment Variable Substitution in Configs
|
||||
```yaml
|
||||
environment:
|
||||
REPLACE_ENV_SUFFIXES: "yml,yaml,properties,json"
|
||||
REPLACE_ENV_VARIABLES_EXCLUDES: "secrets.yml"
|
||||
volumes:
|
||||
- ./config:/config
|
||||
```
|
||||
**Stronghold needs**: UI for managing env var substitution rules
|
||||
|
||||
### 4. Auto-removal of Mods/Plugins
|
||||
```yaml
|
||||
environment:
|
||||
REMOVE_OLD_MODS: "TRUE"
|
||||
REMOVE_OLD_MODS_INCLUDE: "*.jar"
|
||||
REMOVE_OLD_MODS_EXCLUDE: "core-mod.jar"
|
||||
REMOVE_OLD_MODS_DEPTH: 1
|
||||
```
|
||||
**Stronghold needs**: Options for mod/plugin cleanup behavior
|
||||
|
||||
### 5. Multiple Generic Packs with Prefix/Suffix
|
||||
```yaml
|
||||
environment:
|
||||
GENERIC_PACKS: configs-v9.0.1,mods-v4.3.6
|
||||
GENERIC_PACKS_PREFIX: "https://cdn.example.org/"
|
||||
GENERIC_PACKS_SUFFIX: ".zip"
|
||||
```
|
||||
**Stronghold needs**: Support for batch generic pack installation
|
||||
|
||||
### 6. Mod/Plugin URL Lists via File
|
||||
```yaml
|
||||
environment:
|
||||
MODS_FILE: /extras/mods.txt
|
||||
volumes:
|
||||
- ./mods-list.txt:/extras/mods.txt:ro
|
||||
```
|
||||
**Stronghold needs**: File-based mod/plugin list management
|
||||
|
||||
### 7. Custom Copy Destinations
|
||||
```yaml
|
||||
environment:
|
||||
COPY_PLUGINS_SRC: /plugins-custom
|
||||
COPY_PLUGINS_DEST: /data/plugins
|
||||
COPY_MODS_SRC: /mods-custom
|
||||
COPY_MODS_DEST: /data/mods
|
||||
COPY_CONFIG_SRC: /config-custom
|
||||
COPY_CONFIG_DEST: /data/config
|
||||
```
|
||||
**Stronghold needs**: Advanced volume mount configuration options
|
||||
|
||||
### 8. Multi-Server Network with Proxy
|
||||
**Complex Setup**:
|
||||
- Multiple backend servers
|
||||
- Proxy server
|
||||
- Internal Docker network
|
||||
- Port mapping coordination
|
||||
- Service dependencies
|
||||
|
||||
**Stronghold needs**: Multi-container orchestration UI
|
||||
|
||||
### 9. Modpack Updates with Checksum Control
|
||||
```yaml
|
||||
environment:
|
||||
MODPACK: modrinth:abc123
|
||||
SKIP_GENERIC_PACK_CHECKSUM: "false"
|
||||
SKIP_GENERIC_PACK_UPDATE_CHECK: "false"
|
||||
FORCE_GENERIC_PACK_UPDATE: "true"
|
||||
```
|
||||
**Stronghold needs**: Modpack update management UI
|
||||
|
||||
### 10. Hybrid Server (Mods + Plugins)
|
||||
```yaml
|
||||
environment:
|
||||
TYPE: MAGMA # or other hybrid type
|
||||
USES_PLUGINS: "true"
|
||||
volumes:
|
||||
- ./mods:/mods
|
||||
- ./plugins:/plugins
|
||||
```
|
||||
**Stronghold needs**: Detection and configuration of hybrid server types
|
||||
|
||||
## Configuration Complexity Levels
|
||||
|
||||
### Level 1: Simple
|
||||
- Basic vanilla server
|
||||
- Minimal configuration
|
||||
- Default settings
|
||||
|
||||
**Stronghold UI**: Simple wizard, minimal options
|
||||
|
||||
### Level 2: Standard
|
||||
- Common server types (Paper, Forge, Fabric)
|
||||
- Standard modpack installation
|
||||
- Basic resource allocation
|
||||
|
||||
**Stronghold UI**: Guided setup with sensible defaults
|
||||
|
||||
### Level 3: Advanced
|
||||
- Custom configurations
|
||||
- Multiple mod sources
|
||||
- Environment variable substitution
|
||||
- Custom volumes
|
||||
|
||||
**Stronghold UI**: Advanced options panel, expert mode
|
||||
|
||||
### Level 4: Expert
|
||||
- Edge cases
|
||||
- Manual docker-compose editing
|
||||
- Complex network setups
|
||||
- Custom scripts
|
||||
|
||||
**Stronghold UI**: YAML editor with validation, export/import
|
||||
|
||||
## Stronghold Implementation Priorities
|
||||
|
||||
### Phase 1 (MVP)
|
||||
- Level 1 configurations (simple servers)
|
||||
- Basic modpack installation (MODPACK env var)
|
||||
- Standard volume mounts
|
||||
|
||||
### Phase 2 (V1.0)
|
||||
- Level 2 configurations
|
||||
- Individual mod/plugin management
|
||||
- Multiple mod sources
|
||||
- Basic generic pack support
|
||||
|
||||
### Phase 3 (V1.5+)
|
||||
- Level 3 configurations
|
||||
- Advanced volume mount options
|
||||
- Environment variable substitution UI
|
||||
- Multi-server orchestration
|
||||
|
||||
### Phase 4 (Future)
|
||||
- Level 4 expert mode
|
||||
- YAML editor/validator
|
||||
- Import existing docker-compose files
|
||||
- Template marketplace
|
||||
|
||||
## Key Takeaways
|
||||
|
||||
1. **Most users need Level 1-2**: Focus UI on these first
|
||||
2. **Edge cases are powerful**: Support them but don't make them required
|
||||
3. **Flexibility is key**: Allow export to docker-compose.yml for advanced users
|
||||
4. **Validate configurations**: Check for conflicts and errors before applying
|
||||
5. **Presets help**: Provide templates for common scenarios
|
||||
6. **Documentation**: Link to itzg docs for advanced features
|
||||
|
||||
370
references/examples/EXAMPLES-ANALYSIS.md
Normal file
370
references/examples/EXAMPLES-ANALYSIS.md
Normal file
|
|
@ -0,0 +1,370 @@
|
|||
# Detailed Example Analysis
|
||||
|
||||
This document provides detailed analysis of each example docker-compose file from the itzg repository.
|
||||
|
||||
## 1. docker-compose-big.yml - Large Biomes World Type
|
||||
|
||||
**Source**: [itzg/docker-minecraft-server/examples/docker-compose-big.yml](https://github.com/itzg/docker-minecraft-server/blob/master/examples/docker-compose-big.yml)
|
||||
|
||||
### Purpose
|
||||
Demonstrates configuration for a vanilla Minecraft server with:
|
||||
- Large Biomes world generation
|
||||
- High memory allocation (32G)
|
||||
- RCON web admin integration
|
||||
- Performance tuning settings
|
||||
|
||||
### Key Features
|
||||
|
||||
#### World Configuration
|
||||
- `LEVEL_TYPE: LARGEBIOMES` - Generates worlds with larger biome sizes
|
||||
|
||||
#### Performance Settings
|
||||
- `MAX_MEMORY: 32G` - Very high memory allocation (for large servers)
|
||||
- `MAX_BUILD_HEIGHT: 256` - Standard build height
|
||||
- `VIEW_DISTANCE: 15` - Moderate view distance
|
||||
- `MAX_PLAYERS: 100` - High player capacity
|
||||
- `CONSOLE: "false"` - Disables console (likely uses RCON instead)
|
||||
|
||||
#### Multi-Service Setup
|
||||
- **minecraft**: Main server container
|
||||
- **rcon**: Separate RCON web admin service (itzg/rcon)
|
||||
- Exposes ports 4326 and 4327 for web admin access
|
||||
- Uses separate volume for RCON database
|
||||
|
||||
### Stronghold Implementation Notes
|
||||
|
||||
1. **World Type Selection**: UI needs dropdown/selector for world types:
|
||||
- DEFAULT
|
||||
- FLAT
|
||||
- LARGEBIOMES
|
||||
- AMPLIFIED
|
||||
- And modded world types (e.g., "biomesoplenty")
|
||||
|
||||
2. **Memory Presets**: Provide memory presets:
|
||||
- Small (1-2G): Single player / small groups
|
||||
- Medium (4-8G): Small servers
|
||||
- Large (16G+): Large servers
|
||||
- Custom: User-specified
|
||||
|
||||
3. **RCON Integration**: Show option to include RCON web admin:
|
||||
- Separate service
|
||||
- Automatic port configuration
|
||||
- Link to web admin interface
|
||||
|
||||
4. **Performance Tuning**: Advanced options panel:
|
||||
- View distance
|
||||
- Max players
|
||||
- Build height
|
||||
- Console enable/disable
|
||||
|
||||
---
|
||||
|
||||
## 2. docker-compose-curseforge-atm7.yaml - All The Mods 7
|
||||
|
||||
**Source**: [itzg/docker-minecraft-server/examples/docker-compose-curseforge-atm7.yaml](https://github.com/itzg/docker-minecraft-server/blob/master/examples/docker-compose-curseforge-atm7.yaml)
|
||||
|
||||
### Purpose
|
||||
Complete example for installing "All The Mods 7" modpack from CurseForge. This is a **comprehensive, well-documented example** that serves as an excellent template.
|
||||
|
||||
### Key Features
|
||||
|
||||
#### CurseForge Modpack Installation
|
||||
- `TYPE: CURSEFORGE` - CurseForge modpack type
|
||||
- `CF_SERVER_MOD: /modpacks/ATM7-0.4.32-server.zip` - Path to modpack server files
|
||||
- Modpack zip file mounted from local `./modpacks` directory
|
||||
|
||||
#### Extensive Configuration
|
||||
- **Memory**: `8G` - Appropriate for large modpacks
|
||||
- **Timezone**: `America/New_York` - Server timezone configuration
|
||||
- **Logging**: `ENABLE_ROLLING_LOGS: "true"` - Automatic log rotation
|
||||
- **Game Options**: Extensive server properties override
|
||||
|
||||
#### Server Properties Override
|
||||
- `OVERRIDE_SERVER_PROPERTIES: "true"` - Allows environment variable overrides
|
||||
- Custom difficulty, view distance, max players
|
||||
- PVP settings
|
||||
- Level type (biomesoplenty for ATM7)
|
||||
- MOTD customization
|
||||
- Flight allowed
|
||||
- Max tick time set to -1 (no timeout)
|
||||
|
||||
### Edge Cases Demonstrated
|
||||
|
||||
1. **EULA in Modpack**: Important note that EULA file in modpack.zip will overwrite EULA flag
|
||||
2. **Local Modpack Files**: Shows mounting local modpacks directory
|
||||
3. **Custom Container Name**: `container_name: mc_atm7`
|
||||
4. **Restart Policy**: `unless-stopped` for persistence
|
||||
|
||||
### Stronghold Implementation Notes
|
||||
|
||||
1. **Modpack Installation Wizard**:
|
||||
- Step 1: Select modpack source (CurseForge, Modrinth, local file, URL)
|
||||
- Step 2: If local file, prompt for file path or upload
|
||||
- Step 3: Auto-detect recommended memory based on modpack size/complexity
|
||||
- Step 4: Configuration presets (can customize later)
|
||||
|
||||
2. **Configuration UI Sections**:
|
||||
- **Basic**: EULA, memory, restart policy
|
||||
- **Modpack**: Type, source, file path
|
||||
- **Performance**: View distance, max players, tick time
|
||||
- **Gameplay**: Difficulty, PVP, flight, MOTD
|
||||
- **Advanced**: Override flags, timezone, logging
|
||||
|
||||
3. **Modpack Detection**:
|
||||
- Parse modpack manifest to suggest:
|
||||
- Server type (FORGE/FABRIC)
|
||||
- Recommended memory
|
||||
- Minecraft version
|
||||
- Required mods/dependencies
|
||||
|
||||
4. **File Management**:
|
||||
- UI for managing modpack files
|
||||
- Upload/download modpack files
|
||||
- Version selection
|
||||
- Update notifications
|
||||
|
||||
5. **Template Generation**:
|
||||
- Use this as a template for modpack installations
|
||||
- Generate similar structure with user's selections
|
||||
|
||||
---
|
||||
|
||||
## 3. docker-compose-curseforge.yml - Basic CurseForge Example
|
||||
|
||||
**Source**: [itzg/docker-minecraft-server/examples/docker-compose-curseforge.yml](https://github.com/itzg/docker-minecraft-server/blob/master/examples/docker-compose-curseforge.yml)
|
||||
|
||||
### Purpose
|
||||
Minimal example showing CurseForge modpack installation. Demonstrates simplicity for basic use cases.
|
||||
|
||||
### Key Features
|
||||
|
||||
#### Minimal Configuration
|
||||
- Only essential variables
|
||||
- `TYPE: CURSEFORGE`
|
||||
- `CF_SERVER_MOD` pointing to modpack zip
|
||||
- Uses environment variable substitution: `${IMAGE_TAG:-java8}`
|
||||
|
||||
#### Multiple Modpack Examples (Commented)
|
||||
Shows flexibility with commented examples:
|
||||
- Different modpack names
|
||||
- URL-based modpack (direct download)
|
||||
- Environment variable substitution for modpack selection
|
||||
|
||||
### Edge Cases Demonstrated
|
||||
|
||||
1. **Java Version Selection**: Uses `${IMAGE_TAG:-java8}` to select Java version
|
||||
2. **URL Modpacks**: Shows that modpack can be a URL (direct download)
|
||||
3. **Environment Variable Modpack Selection**: `${MODPACK:-default.zip}`
|
||||
4. **Read-only Modpack Mount**: `./modpacks:/modpacks:ro`
|
||||
|
||||
### Stronghold Implementation Notes
|
||||
|
||||
1. **Simple Modpack Installation**:
|
||||
- Minimal UI for quick setup
|
||||
- Three input methods:
|
||||
- Local file (browse/upload)
|
||||
- URL (direct download)
|
||||
- Modpack ID (if we integrate with CurseForge API)
|
||||
|
||||
2. **Java Version Selection**:
|
||||
- Dropdown for Java version
|
||||
- Auto-detect based on Minecraft version
|
||||
- Allow manual override
|
||||
|
||||
3. **Quick Setup Mode**:
|
||||
- Use this as "Simple" mode template
|
||||
- Advanced options hidden by default
|
||||
- "Show Advanced" toggle for power users
|
||||
|
||||
4. **Presets/Saved Configurations**:
|
||||
- Save common modpack configurations
|
||||
- Quick-switch between different modpacks
|
||||
- Template library
|
||||
|
||||
---
|
||||
|
||||
## 4. docker-compose-magma.yml - Hybrid Mods + Plugins
|
||||
|
||||
**Source**: [itzg/docker-minecraft-server/examples/docker-compose-magma.yml](https://github.com/itzg/docker-minecraft-server/blob/master/examples/docker-compose-magma.yml)
|
||||
|
||||
### Purpose
|
||||
Demonstrates Magma server type - a hybrid that supports both Forge mods AND Bukkit/Spigot plugins simultaneously.
|
||||
|
||||
### Key Features
|
||||
|
||||
#### Hybrid Server Type
|
||||
- `TYPE: MAGMA` - Enables both mods and plugins
|
||||
- `VERSION: 1.16.5` - Specific Minecraft version
|
||||
- `image: itzg/minecraft-server:java8` - Java 8 required for this version
|
||||
|
||||
#### Interactive Container
|
||||
- `tty: true` - Allocates a pseudo-TTY
|
||||
- `stdin_open: true` - Keeps STDIN open
|
||||
- Allows interactive console access
|
||||
|
||||
### Edge Cases Demonstrated
|
||||
|
||||
1. **Hybrid Server Type**: Unique server type requiring special handling
|
||||
2. **Version-Specific Java**: Older versions require Java 8
|
||||
3. **Interactive Mode**: Console access configuration
|
||||
|
||||
### Stronghold Implementation Notes
|
||||
|
||||
1. **Server Type Detection**:
|
||||
- When user selects Magma (or other hybrid types):
|
||||
- Show both "Mods" and "Plugins" tabs/sections
|
||||
- Support both `/mods` and `/plugins` volume mounts
|
||||
- Set `USES_PLUGINS=true` if needed
|
||||
|
||||
2. **Java Version Compatibility**:
|
||||
- Map Minecraft versions to required Java versions
|
||||
- Warn user if incompatible Java version selected
|
||||
- Auto-select appropriate Java version
|
||||
|
||||
3. **Version-Specific Handling**:
|
||||
- Some server types only work with specific Minecraft versions
|
||||
- Validate compatibility
|
||||
- Show warnings/errors
|
||||
|
||||
4. **Interactive Console**:
|
||||
- Option to enable interactive console
|
||||
- Useful for debugging
|
||||
- May not be needed for most users
|
||||
|
||||
5. **Hybrid Server UI**:
|
||||
- Special UI mode for hybrid servers
|
||||
- Clear separation of mods vs plugins
|
||||
- Different management for each type
|
||||
|
||||
---
|
||||
|
||||
## 5. docker-compose-rconcmd.yml - Advanced RCON Commands
|
||||
|
||||
**Source**: [itzg/docker-minecraft-server/examples/docker-compose-rconcmd.yml](https://github.com/itzg/docker-minecraft-server/blob/master/examples/docker-compose-rconcmd.yml)
|
||||
|
||||
### Purpose
|
||||
Demonstrates advanced RCON usage with:
|
||||
- Automated command execution at different lifecycle events
|
||||
- CurseForge API integration for mod installation
|
||||
- YAML heredoc syntax for multi-line commands
|
||||
|
||||
### Key Features
|
||||
|
||||
#### RCON Lifecycle Commands
|
||||
- `RCON_CMDS_STARTUP` - Commands executed when server starts
|
||||
- `RCON_CMDS_ON_CONNECT` - Commands executed when any player connects
|
||||
- `RCON_CMDS_FIRST_CONNECT` - Commands executed on first player connection
|
||||
- `RCON_CMDS_LAST_DISCONNECT` - Commands executed when last player disconnects
|
||||
|
||||
#### CurseForge API Integration
|
||||
- `CURSEFORGE_FILES` - List of CurseForge mod names to auto-install
|
||||
- `CF_API_KEY` - CurseForge API key from environment variable
|
||||
- Requires API key from https://console.curseforge.com/
|
||||
|
||||
#### Advanced YAML Syntax
|
||||
- Uses `|-` heredoc to remove leading/trailing newlines
|
||||
- Multi-line command lists
|
||||
- Proper formatting for readability
|
||||
|
||||
### Example Use Case
|
||||
The example shows:
|
||||
- Setting game rules on startup
|
||||
- Creating teams for players
|
||||
- Using Chunky (world pregeneration) mod
|
||||
- Giving items to new players
|
||||
- Managing entities when players disconnect
|
||||
|
||||
### Edge Cases Demonstrated
|
||||
|
||||
1. **Environment Variable Security**: API keys from `.env` file (not in compose file)
|
||||
2. **YAML Heredoc Syntax**: Proper multi-line string handling
|
||||
3. **CurseForge API Key**: Requires external API key management
|
||||
4. **Lifecycle Hooks**: Automated server management via RCON
|
||||
|
||||
### Stronghold Implementation Notes
|
||||
|
||||
1. **RCON Command Management UI**:
|
||||
- Tabs/sections for each lifecycle event
|
||||
- Multi-line text editor for commands
|
||||
- Command validation
|
||||
- Preview of commands that will run
|
||||
- Test/simulate commands
|
||||
|
||||
2. **CurseForge API Integration**:
|
||||
- UI for managing API key (stored securely)
|
||||
- Search/browse CurseForge mods by name
|
||||
- Auto-install mods via API
|
||||
- Dependency resolution
|
||||
|
||||
3. **Lifecycle Events**:
|
||||
- **Startup**: Server initialization commands
|
||||
- **On Connect**: Welcome messages, permissions, etc.
|
||||
- **First Connect**: One-time setup (world generation, etc.)
|
||||
- **Last Disconnect**: Cleanup, save, shutdown tasks
|
||||
|
||||
4. **Command Editor**:
|
||||
- Syntax highlighting (Minecraft commands)
|
||||
- Auto-completion
|
||||
- Validation
|
||||
- Help/cheat sheet
|
||||
|
||||
5. **Security**:
|
||||
- Secure storage of API keys
|
||||
- Environment variable management
|
||||
- Never expose secrets in generated files
|
||||
|
||||
6. **Advanced Features**:
|
||||
- Schedule commands (cron-like)
|
||||
- Conditional commands
|
||||
- Command templates
|
||||
- Import/export command sets
|
||||
|
||||
---
|
||||
|
||||
## Common Patterns Across Examples
|
||||
|
||||
### 1. Volume Management
|
||||
- All use named volumes or bind mounts for `/data`
|
||||
- Some use read-only mounts for modpacks
|
||||
- Consistent pattern: `volume_name:/data`
|
||||
|
||||
### 2. Environment Variables
|
||||
- `EULA: "TRUE"` - Always required
|
||||
- `TYPE` - Server type
|
||||
- `MEMORY` - Memory allocation
|
||||
- Port mapping: `25565:25565`
|
||||
|
||||
### 3. Restart Policies
|
||||
- `always` - Production servers
|
||||
- `unless-stopped` - Common for game servers
|
||||
- `on-failure` - Development/testing
|
||||
|
||||
### 4. Image Tags
|
||||
- Default: `itzg/minecraft-server`
|
||||
- Java version: `:java8`, `:java17`, etc.
|
||||
- Architecture: `:arm64`, `:amd64`, etc.
|
||||
- Environment variable substitution common
|
||||
|
||||
## Implementation Priorities for Stronghold
|
||||
|
||||
### Phase 1 (MVP)
|
||||
- Basic server creation (like curseforge.yml)
|
||||
- Simple modpack installation
|
||||
- Essential environment variables
|
||||
|
||||
### Phase 2 (V1.0)
|
||||
- Advanced modpack configuration (like atm7.yaml)
|
||||
- World type selection (like big.yml)
|
||||
- RCON basic integration
|
||||
|
||||
### Phase 3 (V1.5)
|
||||
- Hybrid server support (like magma.yml)
|
||||
- RCON lifecycle commands (like rconcmd.yml)
|
||||
- CurseForge API integration
|
||||
|
||||
### Phase 4 (Future)
|
||||
- Multi-service orchestration
|
||||
- Advanced RCON features
|
||||
- Template library
|
||||
- Import/export configurations
|
||||
|
||||
48
references/examples/README.md
Normal file
48
references/examples/README.md
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
# Docker Compose Examples Reference
|
||||
|
||||
This directory contains example Docker Compose configurations for various Minecraft server setups using itzg containers.
|
||||
|
||||
## Purpose
|
||||
|
||||
These examples serve as:
|
||||
- **Reference implementations** for common server configurations
|
||||
- **Edge case demonstrations** for complex scenarios
|
||||
- **Learning materials** for understanding itzg container capabilities
|
||||
- **Templates** for Stronghold to generate similar configurations
|
||||
|
||||
## Categories
|
||||
|
||||
### Basic Examples
|
||||
- Simple vanilla server
|
||||
- Basic modded server (Forge/Fabric)
|
||||
- Basic plugin server (Paper/Spigot)
|
||||
|
||||
### Advanced Examples
|
||||
- Multi-server setups
|
||||
- Proxy server configurations
|
||||
- Modpack installations
|
||||
- Custom configurations
|
||||
|
||||
### Edge Cases
|
||||
- Complex volume mounts
|
||||
- Multiple mod sources
|
||||
- Environment variable substitution
|
||||
- Generic pack installations
|
||||
- Custom network configurations
|
||||
|
||||
## Source
|
||||
|
||||
Examples are typically sourced from:
|
||||
- [itzg/docker-minecraft-server GitHub examples](https://github.com/itzg/docker-minecraft-server)
|
||||
- Community contributions
|
||||
- Documentation examples
|
||||
- Real-world use cases
|
||||
|
||||
## Usage in Stronghold
|
||||
|
||||
Stronghold should:
|
||||
1. Analyze these examples to understand configuration patterns
|
||||
2. Generate similar configurations dynamically based on user input
|
||||
3. Provide presets/templates based on common patterns
|
||||
4. Handle edge cases gracefully in the UI
|
||||
|
||||
28
references/examples/docker-compose-big.yml
Normal file
28
references/examples/docker-compose-big.yml
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
services:
|
||||
minecraft:
|
||||
ports:
|
||||
- "25565:25565"
|
||||
volumes:
|
||||
- "mcbig:/data"
|
||||
environment:
|
||||
EULA: "TRUE"
|
||||
MAX_MEMORY: 32G
|
||||
MAX_BUILD_HEIGHT: 256
|
||||
VIEW_DISTANCE: 15
|
||||
LEVEL_TYPE: LARGEBIOMES
|
||||
MAX_PLAYERS: 100
|
||||
CONSOLE: "false"
|
||||
image: itzg/minecraft-server
|
||||
restart: always
|
||||
rcon:
|
||||
image: itzg/rcon
|
||||
ports:
|
||||
- "4326:4326"
|
||||
- "4327:4327"
|
||||
volumes:
|
||||
- "rcon:/opt/rcon-web-admin/db"
|
||||
|
||||
volumes:
|
||||
mcbig:
|
||||
rcon:
|
||||
|
||||
149
references/examples/docker-compose-curseforge-atm7.yaml
Normal file
149
references/examples/docker-compose-curseforge-atm7.yaml
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
####################################################################
|
||||
# CURSEFORGE #
|
||||
# #
|
||||
# Date: 20221005 #
|
||||
# #
|
||||
# Mod: All The Mods 7 0.4.32 #
|
||||
# #
|
||||
# Notes: Verify that there is no EULA file in the modpack.zip #
|
||||
# if you do not delete it the EULA flag below will be #
|
||||
# overwritten when the modpack is copied. #
|
||||
# #
|
||||
####################################################################
|
||||
services:
|
||||
|
||||
####################################################################
|
||||
# Service Name #
|
||||
# #
|
||||
# Define Service Name here. If using RCON this name will be #
|
||||
# referenced again as RWA_RCON_HOST below. #
|
||||
# #
|
||||
# Example: 'name:' or 'mc_atm6:' #
|
||||
####################################################################
|
||||
mc_atm7:
|
||||
|
||||
####################################################################
|
||||
# Image & Container Name #
|
||||
# #
|
||||
# Specify Image Name and Java Version. The 'image' will always be #
|
||||
# 'itzg/minecraft-server' however the tag added to the end is #
|
||||
# where you can specify the java version or container architecture.#
|
||||
# See readme.md for a full list. #
|
||||
# #
|
||||
# 'container_name:' This can be anything you like. This is the name#
|
||||
# that will show when you run 'docker ps' commands. #
|
||||
####################################################################
|
||||
image: itzg/minecraft-server
|
||||
container_name: mc_atm7
|
||||
|
||||
####################################################################
|
||||
# Server Ports #
|
||||
# #
|
||||
# Specify external port. #
|
||||
####################################################################
|
||||
ports:
|
||||
- 25565:25565
|
||||
|
||||
####################################################################
|
||||
# Automatic Server Restart #
|
||||
# #
|
||||
# Define a restart policy here. #
|
||||
# - 'no' = Do not restart. #
|
||||
# - 'on-failure' = Restart if container exits because an error. #
|
||||
# - 'always' = Regardless of stop reason. #
|
||||
# - 'unless-stopped' = Similar to always except if stopped. #
|
||||
####################################################################
|
||||
restart: unless-stopped
|
||||
|
||||
####################################################################
|
||||
# Volume and Folder Access #
|
||||
# #
|
||||
# This section defines what folders and volumes you want to give #
|
||||
# this container access to. It is recommended to leaves these set #
|
||||
# to the default values unless you know what you are doing. #
|
||||
# #
|
||||
# Place your mod zip file in a folder called 'modpacks' in the #
|
||||
# same directory you place this docker-compose file. #
|
||||
# #
|
||||
# Specify the data volume name or directory here as well. #
|
||||
# In this example the volume name is 'data'. When docker creates #
|
||||
# the volume it will add what ever name you give it here to the #
|
||||
# end of the container name specified above. In this example it #
|
||||
# would be named 'mc_atm6_data'. If you change this be sure to #
|
||||
# update the volume name at the bottom of this config. #
|
||||
####################################################################
|
||||
volumes:
|
||||
- ./modpacks:/modpacks:ro
|
||||
- data:/data
|
||||
|
||||
####################################################################
|
||||
# EULA #
|
||||
# #
|
||||
# Accept EULA by setting to "true" #
|
||||
####################################################################
|
||||
environment:
|
||||
EULA: "true"
|
||||
|
||||
####################################################################
|
||||
# CURSEFORGE INSTALL #
|
||||
# #
|
||||
# Sets install type to FORGE and specifys the zip folder name #
|
||||
# and location of your mod pack. #
|
||||
# #
|
||||
# TYPE: Defines the install type as CURSEFORGE #
|
||||
# #
|
||||
# CF_SERVER_MOD: Define where the modpack.zip is located. #
|
||||
# #
|
||||
# Place your mod zip file in a folder called 'modpacks' in the #
|
||||
# same directory you place this docker-compose file. #
|
||||
####################################################################
|
||||
TYPE: CURSEFORGE
|
||||
CF_SERVER_MOD: /modpacks/ATM7-0.4.32-server.zip
|
||||
|
||||
####################################################################
|
||||
# Server Memory #
|
||||
# #
|
||||
# Set Maximum amount of memory allowed for your server. #
|
||||
####################################################################
|
||||
MEMORY: "8G"
|
||||
|
||||
####################################################################
|
||||
# Logging Options #
|
||||
# #
|
||||
# Set to "true" to delete old logs #
|
||||
################################################################ ####
|
||||
ENABLE_ROLLING_LOGS: "true"
|
||||
|
||||
####################################################################
|
||||
# Server Timezone #
|
||||
# #
|
||||
# Specify server Timezone #
|
||||
####################################################################
|
||||
TZ: "America/New_York"
|
||||
|
||||
####################################################################
|
||||
# Minecraft Game Options #
|
||||
# #
|
||||
# List any game options you want to define here. A full list can #
|
||||
# be found on the readme.md page on github. #
|
||||
####################################################################
|
||||
OVERRIDE_SERVER_PROPERTIES: "true"
|
||||
DIFFICULTY: "easy"
|
||||
MAX_TICK_TIME: "-1"
|
||||
ALLOW_FLIGHT: "true"
|
||||
OPS: ""
|
||||
VIEW_DISTANCE: 10
|
||||
MAX_PLAYERS: 10
|
||||
PVP: "false"
|
||||
LEVEL_TYPE: "biomesoplenty"
|
||||
MOTD: "Welcome Home"
|
||||
|
||||
####################################################################
|
||||
# Volumes #
|
||||
# #
|
||||
# Define data volume name here. You should leave this set to the #
|
||||
# default. #
|
||||
####################################################################
|
||||
volumes:
|
||||
data:
|
||||
|
||||
20
references/examples/docker-compose-curseforge.yml
Normal file
20
references/examples/docker-compose-curseforge.yml
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
services:
|
||||
mc:
|
||||
image: itzg/minecraft-server:${IMAGE_TAG:-java8}
|
||||
volumes:
|
||||
- ./modpacks:/modpacks:ro
|
||||
- data:/data
|
||||
environment:
|
||||
EULA: "true"
|
||||
TYPE: CURSEFORGE
|
||||
CF_SERVER_MOD: /modpacks/SIMPLE-SERVER-FILES-0.3.20.zip
|
||||
# CF_SERVER_MOD: /modpacks/createlive3serverfiles+1.4.2.zip
|
||||
# CF_SERVER_MOD: /modpacks/Valhelsia+3-3.5.1-SERVER.zip
|
||||
# CF_SERVER_MOD: https://media.forgecdn.net/files/3012/800/SkyFactory-4_Server_4.2.2.zip
|
||||
# CF_SERVER_MOD: /modpacks/${MODPACK:-SkyFactory_4_Server_4.1.0.zip}
|
||||
ports:
|
||||
- "25565:25565"
|
||||
|
||||
volumes:
|
||||
data: {}
|
||||
|
||||
16
references/examples/docker-compose-magma.yml
Normal file
16
references/examples/docker-compose-magma.yml
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
services:
|
||||
mc:
|
||||
image: itzg/minecraft-server:java8
|
||||
tty: true
|
||||
stdin_open: true
|
||||
ports:
|
||||
- "25565:25565"
|
||||
environment:
|
||||
EULA: "TRUE"
|
||||
TYPE: MAGMA
|
||||
VERSION: 1.16.5
|
||||
volumes:
|
||||
- data:/data
|
||||
volumes:
|
||||
data: {}
|
||||
|
||||
40
references/examples/docker-compose-rconcmd.yml
Normal file
40
references/examples/docker-compose-rconcmd.yml
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
services:
|
||||
minecraft:
|
||||
image: ${IMAGE_TO_TEST:-itzg/minecraft-server}
|
||||
ports:
|
||||
- "25565:25565"
|
||||
volumes:
|
||||
- "mc:/data"
|
||||
environment:
|
||||
EULA: "TRUE"
|
||||
TYPE: FABRIC
|
||||
MEMORY: "2G"
|
||||
CURSEFORGE_FILES: |
|
||||
fabric-api
|
||||
chunky-pregenerator
|
||||
# Allocate API key from https://console.curseforge.com/
|
||||
# and set in .env file making sure to double up dollar signs, such as
|
||||
# CF_API_KEY=$$2a$$10$$....
|
||||
# Refer to https://docker-minecraft-server.readthedocs.io/en/latest/types-and-platforms/mod-platforms/auto-curseforge/#api-key
|
||||
CF_API_KEY: ${CF_API_KEY}
|
||||
# YAML Heredoc, be sure to use '|-' this will remove the first newline and final new line.
|
||||
# This is versus '|' that will leaving with two empty strings at top and bottom.
|
||||
RCON_CMDS_STARTUP: |-
|
||||
/gamerule doFireTick false
|
||||
/team add New
|
||||
/team add Old
|
||||
/chunky radius 1000
|
||||
/chunky start
|
||||
RCON_CMDS_ON_CONNECT: |-
|
||||
/team join New @a[team=]
|
||||
/give @a[team=New] birch_boat
|
||||
/team join Old @a[team=New]
|
||||
RCON_CMDS_FIRST_CONNECT: |-
|
||||
/chunky pause
|
||||
RCON_CMDS_LAST_DISCONNECT: |-
|
||||
/kill @e[type=minecraft:boat]
|
||||
/chunky continue
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
mc: {}
|
||||
|
||||
283
references/itzg-projects.md
Normal file
283
references/itzg-projects.md
Normal file
|
|
@ -0,0 +1,283 @@
|
|||
# itzg Projects Reference
|
||||
|
||||
These are the core Docker projects by itzg that Stronghold will integrate with.
|
||||
|
||||
## itzg/docker-minecraft-server
|
||||
**GitHub**: https://github.com/itzg/docker-minecraft-server
|
||||
**Docs**: https://docker-minecraft-server.readthedocs.io/en/latest/
|
||||
|
||||
### Overview
|
||||
Docker image for running Minecraft Java Edition servers. Automatically downloads the specified version at startup.
|
||||
|
||||
### Key Features
|
||||
- **Automatic Version Management**: Downloads and sets up the specified Minecraft version at startup
|
||||
- **Server Type Support**: Supports multiple server types via `TYPE` environment variable:
|
||||
- VANILLA
|
||||
- PAPER (optimized, recommended)
|
||||
- FORGE (modded servers)
|
||||
- FABRIC (modded servers)
|
||||
- SPIGOT
|
||||
- BUKKIT
|
||||
- And more
|
||||
- **Configuration via Environment Variables**: Extensive configuration through environment variables for:
|
||||
- Server properties (gamemode, difficulty, seed, etc.)
|
||||
- Memory allocation (`MEMORY`)
|
||||
- Java version selection
|
||||
- Modpack installation
|
||||
- Plugin management
|
||||
- **Modpack Integration**:
|
||||
- Supports Modrinth and CurseForge modpack installation
|
||||
- Can download server packs automatically
|
||||
- Handles mod installation and updates
|
||||
- Feed the Beast (FTB) support
|
||||
- Packwiz modpack support
|
||||
- **Data Persistence**: Uses `/data` volume for:
|
||||
- World data
|
||||
- Server configurations
|
||||
- Mods and plugins
|
||||
- Logs
|
||||
- **Health Monitoring**: Built-in health checks
|
||||
- **RCON Support**: Built-in RCON support for remote console access
|
||||
- **Resource Management**: Memory and CPU allocation via Docker
|
||||
|
||||
### Important Environment Variables
|
||||
- `TYPE`: Server type (VANILLA, PAPER, FORGE, FABRIC, etc.)
|
||||
- `VERSION`: Minecraft version (LATEST, specific version, or SNAPSHOT)
|
||||
- `MEMORY`: JVM memory allocation
|
||||
- `EULA`: Must be set to `TRUE` to accept Minecraft EULA
|
||||
- `MOTD`: Server message of the day
|
||||
- `DIFFICULTY`: Game difficulty
|
||||
- `MODE`: Game mode (survival, creative, adventure, spectator)
|
||||
- `MODPACK`: Modpack URL or ID for automatic installation
|
||||
|
||||
### Mods and Plugins Management
|
||||
**Reference**: [itzg Mods and Plugins Documentation](https://docker-minecraft-server.readthedocs.io/en/latest/mods-and-plugins/)
|
||||
|
||||
#### Modpack Platforms Supported
|
||||
- **Modrinth**: Auto-download modpacks from Modrinth
|
||||
- **CurseForge**: Auto-download modpacks from CurseForge
|
||||
- **Feed the Beast (FTB)**: FTB modpack support
|
||||
- **Packwiz**: Packwiz format modpacks
|
||||
|
||||
#### Modpack Installation Methods
|
||||
|
||||
1. **MODPACK Environment Variable**:
|
||||
- Set `MODPACK` to a zip file URL or container path
|
||||
- Automatically downloads and installs modpack
|
||||
- Works with zip files containing jar files at top level
|
||||
|
||||
2. **GENERIC_PACK / GENERIC_PACKS**:
|
||||
- Install all server content (jars, mods, plugins, configs) from zip/tgz
|
||||
- Can apply CurseForge modpacks missing server start script
|
||||
- Supports multiple packs: `GENERIC_PACKS=pack1,pack2`
|
||||
- Prefix/suffix support: `GENERIC_PACKS_PREFIX` and `GENERIC_PACKS_SUFFIX`
|
||||
- Update checksum control: `SKIP_GENERIC_PACK_CHECKSUM`, `SKIP_GENERIC_PACK_UPDATE_CHECK`, `FORCE_GENERIC_PACK_UPDATE`
|
||||
- Can disable specific mods: `GENERIC_PACKS_DISABLE_MODS`
|
||||
|
||||
#### Individual Mod/Plugin Installation
|
||||
|
||||
1. **MODS / PLUGINS Environment Variables**:
|
||||
- Comma or newline delimited list of:
|
||||
- URLs of jar files
|
||||
- Container paths to jar files
|
||||
- Container paths to directories containing jars
|
||||
- Example:
|
||||
```yaml
|
||||
MODS: |
|
||||
https://example.com/mod1.jar
|
||||
/plugins/common/mod2.jar
|
||||
```
|
||||
- **Auto-removal**: Entries removed from list automatically remove files from server
|
||||
- Empty list removes all mods/plugins
|
||||
|
||||
2. **MODS_FILE / PLUGINS_FILE**:
|
||||
- Path or URL to text file listing mod/plugin URLs (one per line)
|
||||
- Blank lines and lines starting with `#` are ignored
|
||||
- Useful for managing large mod lists
|
||||
|
||||
#### Volume Mount Points for Mods/Plugins
|
||||
|
||||
1. **`/plugins` Volume**:
|
||||
- Syncs into `/data/plugins` for plugin-based server types
|
||||
- Customizable: `COPY_PLUGINS_SRC`, `COPY_PLUGINS_DEST`
|
||||
- Set `USES_PLUGINS=true` for hybrid mod-based loaders using plugins
|
||||
|
||||
2. **`/mods` Volume**:
|
||||
- Syncs into `/data/mods` for mod-based server types
|
||||
- Customizable: `COPY_MODS_SRC`, `COPY_MODS_DEST`
|
||||
|
||||
3. **`/config` Volume**:
|
||||
- Syncs into `/data/config` by default
|
||||
- Customizable: `COPY_CONFIG_SRC`, `COPY_CONFIG_DEST`
|
||||
- Environment variable processing on config files
|
||||
- `SYNC_SKIP_NEWER_IN_DESTINATION=false` to force overwrite
|
||||
|
||||
4. **Multiple Source Directories**:
|
||||
- `COPY_PLUGINS_SRC`, `COPY_MODS_SRC`, `COPY_CONFIG_SRC` can be comma/newline delimited lists
|
||||
- Allows combining shared and project-specific mods/plugins
|
||||
|
||||
#### Environment Variable Processing
|
||||
- Config files matching suffixes in `REPLACE_ENV_SUFFIXES` (default: "yml,yaml,txt,cfg,conf,properties,hjson,json,tml,toml")
|
||||
- Exclusions: `REPLACE_ENV_VARIABLES_EXCLUDES`, `REPLACE_ENV_VARIABLES_EXCLUDE_PATHS`
|
||||
- Disable with: `REPLACE_ENV_DURING_SYNC=false`
|
||||
|
||||
#### Removing Old Mods/Plugins
|
||||
|
||||
- **REMOVE_OLD_MODS=TRUE**: Delete old mods/plugins before installing new ones
|
||||
- Fine-tuning options:
|
||||
- `REMOVE_OLD_MODS_INCLUDE`: Comma-separated glob patterns to include
|
||||
- `REMOVE_OLD_MODS_EXCLUDE`: Comma-separated glob patterns to exclude
|
||||
- `REMOVE_OLD_MODS_DEPTH`: Maximum directory depth (default: 16)
|
||||
- Default: Only jar files are removed
|
||||
|
||||
#### Additional Configuration Files
|
||||
|
||||
- **APPLY_EXTRA_FILES**: Download/copy additional config files before server starts
|
||||
- Format: `destination<source_url` or `destination<source_path`
|
||||
- Multiple entries with comma/newline separation
|
||||
- Useful for baseline configs to be patched at runtime
|
||||
- Processed before patch processing
|
||||
|
||||
#### Mods vs Plugins
|
||||
|
||||
- **Mods**: Client-side modifications for Forge/Fabric servers
|
||||
- Modify rendering, add blocks, add behaviors
|
||||
- Usually need to be installed on both client and server
|
||||
- **Plugins**: Server-only modifications for Bukkit/Spigot/Paper
|
||||
- Add behaviors, commands, features
|
||||
- Only installed on server
|
||||
- **Hybrid**: Some types like Magma use both mods and plugins
|
||||
|
||||
### Usage Pattern
|
||||
Stronghold will need to:
|
||||
1. Generate docker-compose.yml files or use Docker API to create containers
|
||||
2. Set appropriate environment variables based on user configuration
|
||||
3. Mount volumes for persistent data storage
|
||||
4. Expose appropriate ports
|
||||
5. Handle container lifecycle (start, stop, restart, delete)
|
||||
|
||||
---
|
||||
|
||||
## itzg/docker-mc-proxy
|
||||
**GitHub**: https://github.com/itzg/docker-mc-proxy
|
||||
|
||||
### Overview
|
||||
Docker image for running Minecraft proxy servers (BungeeCord, Waterfall, Velocity). Enables managing multiple Minecraft servers under a single proxy network.
|
||||
|
||||
### Key Features
|
||||
- **Proxy Type Support**:
|
||||
- BungeeCord
|
||||
- Waterfall (BungeeCord fork)
|
||||
- Velocity
|
||||
- **Configuration Management**:
|
||||
- Configuration files via volume mounts
|
||||
- Environment variable substitution in config files
|
||||
- Automatic config synchronization
|
||||
- **Plugin Support**:
|
||||
- Plugins mounted via volumes
|
||||
- Supports proxy-specific plugins
|
||||
- **Port Configuration**:
|
||||
- Default proxy port (25577) can be mapped
|
||||
- Custom port configuration
|
||||
- **Health Checks**: Built-in health monitoring
|
||||
- **Java Version Support**: Multiple Java version tags available
|
||||
- **Multi-Architecture**: Supports multiple CPU architectures
|
||||
|
||||
### Usage Pattern
|
||||
Stronghold will need to:
|
||||
1. Create proxy containers with appropriate type
|
||||
2. Configure proxy config files (config.yml, servers.yml, etc.)
|
||||
3. Link backend servers to the proxy
|
||||
4. Manage plugin installation
|
||||
5. Handle port mapping and routing
|
||||
|
||||
---
|
||||
|
||||
## itzg/mc-router
|
||||
**GitHub**: https://github.com/itzg/mc-router
|
||||
|
||||
### Overview
|
||||
Lightweight TCP reverse proxy/multiplexer for Minecraft Java servers. Routes client connections to backend servers based on the requested server address (SRV records or subdomain).
|
||||
|
||||
### Key Features
|
||||
- **Dynamic Routing**: Routes based on server address requested by client
|
||||
- **Docker Auto-Discovery**: Automatically discovers running Minecraft containers
|
||||
- **Health Checks**: Monitors backend server health
|
||||
- **Load Balancing**: Can distribute connections across multiple servers
|
||||
- **REST API**: Provides REST API for managing routes
|
||||
- **High Availability**: Redirects to operational servers if one fails
|
||||
- **Configuration**:
|
||||
- Can be configured via environment variables
|
||||
- Supports static route configuration
|
||||
- Docker labels for dynamic discovery
|
||||
|
||||
### Usage Pattern
|
||||
Stronghold will need to:
|
||||
1. Deploy mc-router container alongside servers
|
||||
2. Configure routing rules (static or dynamic)
|
||||
3. Use Docker labels for auto-discovery
|
||||
4. Manage backend server registrations via REST API
|
||||
5. Monitor route health and availability
|
||||
|
||||
---
|
||||
|
||||
## itzg/docker-rcon-web-admin
|
||||
**GitHub**: https://github.com/itzg/docker-rcon-web-admin
|
||||
|
||||
### Overview
|
||||
Web-based admin interface for Minecraft servers via RCON (Remote Console).
|
||||
|
||||
### Key Features
|
||||
- **RCON Integration**: Connects to Minecraft servers via RCON protocol
|
||||
- **Web Interface**: Browser-based console access
|
||||
- **Command Execution**: Execute server commands remotely
|
||||
- **Log Viewing**: View server logs in real-time
|
||||
- **Docker Integration**: Runs as a side-car container
|
||||
|
||||
### Usage Pattern
|
||||
Stronghold may want to:
|
||||
1. Integrate RCON functionality directly rather than using separate container
|
||||
2. Use this as reference for RCON implementation
|
||||
3. Potentially use as a fallback/admin interface
|
||||
|
||||
---
|
||||
|
||||
## Key Takeaways for Stronghold
|
||||
|
||||
1. **Environment Variable Configuration**: All itzg containers use extensive environment variable configuration. Stronghold needs a robust system for:
|
||||
- UI to configure these variables
|
||||
- Validating configurations
|
||||
- Generating docker-compose.yml files or Docker API calls
|
||||
|
||||
2. **Volume Management**: Need to manage Docker volumes for:
|
||||
- Server data persistence
|
||||
- Configuration files
|
||||
- Mods/plugins
|
||||
- Backups
|
||||
|
||||
3. **Network Management**: Need to handle:
|
||||
- Port allocation and mapping
|
||||
- Internal Docker networking for proxy/server communication
|
||||
- External port exposure
|
||||
|
||||
4. **Lifecycle Management**: Complete container lifecycle:
|
||||
- Create (with proper configuration)
|
||||
- Start/Stop/Restart
|
||||
- Update/Upgrade
|
||||
- Delete (with data handling)
|
||||
|
||||
5. **Integration Points**:
|
||||
- Docker API for container management
|
||||
- RCON for server console access
|
||||
- Health checks for monitoring
|
||||
- REST APIs (mc-router) for advanced routing
|
||||
|
||||
6. **Mod/Plugin Management Complexity**: The itzg container provides extensive mod/plugin management options:
|
||||
- Multiple modpack platforms (Modrinth, CurseForge, FTB, Packwiz)
|
||||
- Multiple installation methods (MODPACK, GENERIC_PACK, MODS/PLUGINS vars, file lists)
|
||||
- Volume mounts for mods/plugins/configs
|
||||
- Auto-removal of mods/plugins
|
||||
- Environment variable substitution in configs
|
||||
- Stronghold UI should simplify these options while exposing flexibility when needed
|
||||
- Consider wizard-based flows for common scenarios (modpack installation) vs advanced configuration for power users
|
||||
|
||||
210
references/launchers.md
Normal file
210
references/launchers.md
Normal file
|
|
@ -0,0 +1,210 @@
|
|||
# Minecraft Launcher Reference
|
||||
|
||||
These are client-side Minecraft launchers that have excellent modpack installation workflows. Stronghold should aim to make server modpack installation as easy as these launchers make client installation.
|
||||
|
||||
## ATLauncher
|
||||
**GitHub**: https://github.com/ATLauncher/ATLauncher
|
||||
**Website**: https://atlauncher.com
|
||||
|
||||
### Overview
|
||||
Minecraft launcher focused on modpack installation and management. Known for making modpack installation simple and user-friendly.
|
||||
|
||||
### Key Features
|
||||
- **Modpack Browser**: Browse and search modpacks from various sources
|
||||
- **One-Click Installation**: Install modpacks with minimal configuration
|
||||
- **Instance Management**: Create multiple Minecraft instances with different modpacks
|
||||
- **Modpack Updates**: Easy updating of installed modpacks
|
||||
- **Server Pack Generation**: Can generate server packs from modpacks
|
||||
- **Integration with Modpack Platforms**:
|
||||
- CurseForge
|
||||
- Modrinth
|
||||
- FTB (Feed The Beast)
|
||||
- **Version Management**: Manage Minecraft and mod versions
|
||||
- **Mod Management**: View, enable, disable individual mods
|
||||
- **Configuration**: Edit modpack configurations easily
|
||||
|
||||
### User Experience Highlights
|
||||
- Simple, clean interface
|
||||
- Clear categorization of modpacks
|
||||
- Detailed modpack information before installation
|
||||
- Progress indicators during installation
|
||||
- Pre-configured settings that "just work"
|
||||
- Easy troubleshooting
|
||||
|
||||
### Lessons for Stronghold
|
||||
**This is a KEY reference** - the goal is to make modded server creation as simple as ATLauncher makes modpack installation.
|
||||
|
||||
Stronghold should:
|
||||
1. **Modpack Browser**: Provide UI to browse/search modpacks
|
||||
2. **One-Click Server Creation**: Create modded server from modpack in one click
|
||||
3. **Server Pack Handling**: Automatically detect and install server packs
|
||||
4. **Configuration Simplification**: Hide complexity, provide good defaults
|
||||
5. **Mod Management**: Allow viewing/managing mods in installed servers
|
||||
6. **Update Management**: Easy way to update modpacks
|
||||
|
||||
**Key Insight**: The magic of ATLauncher is that it handles all the complexity (downloading, dependency resolution, configuration, version matching) behind the scenes. Stronghold needs to do the same for servers.
|
||||
|
||||
---
|
||||
|
||||
## Prism Launcher
|
||||
**GitHub**: https://github.com/PrismLauncher/PrismLauncher
|
||||
**Website**: https://prismlauncher.org
|
||||
|
||||
### Overview
|
||||
Fork of MultiMC, focused on modpack management. Open source and community-driven.
|
||||
|
||||
### Key Features
|
||||
- **Multi-Platform**: Windows, macOS, Linux
|
||||
- **Modpack Support**:
|
||||
- Modrinth integration
|
||||
- CurseForge integration
|
||||
- FTB integration
|
||||
- Technic Platform support
|
||||
- **Instance Management**: Multiple instances with isolated configurations
|
||||
- **Mod Management**: Individual mod installation, removal, updates
|
||||
- **Version Control**: Git integration for instance management
|
||||
- **Metadata Management**: Rich metadata for modpacks and mods
|
||||
- **Customization**: Highly customizable interface and workflows
|
||||
|
||||
### Technology Stack
|
||||
- C++/Qt for desktop application
|
||||
- Various APIs for modpack platforms
|
||||
|
||||
### Lessons for Stronghold
|
||||
- **Modrinth/CurseForge APIs**: Need to integrate with these platforms
|
||||
- **Metadata Handling**: Rich metadata helps users make informed choices
|
||||
- **Version Management**: Proper version handling is critical
|
||||
- **Instance Isolation**: Each server should be isolated (Docker helps here)
|
||||
|
||||
### API Integration Notes
|
||||
Both ATLauncher and Prism Launcher integrate with:
|
||||
- **Modrinth API**: Modern modpack/mod platform
|
||||
- **CurseForge API**: Legacy but still popular platform
|
||||
- **FTB API**: Feed The Beast modpacks
|
||||
|
||||
Stronghold will need to:
|
||||
1. Integrate with these APIs for modpack discovery
|
||||
2. Handle server pack downloads from these platforms
|
||||
3. Parse modpack metadata (version, dependencies, server pack info)
|
||||
4. Manage modpack installation in Docker containers
|
||||
|
||||
---
|
||||
|
||||
## Key Takeaways for Stronghold
|
||||
|
||||
### The ATLauncher Experience, But for Servers
|
||||
|
||||
When a user wants to create a modded server, the flow should be:
|
||||
|
||||
1. **Browse Modpacks**: Search/browse available modpacks (like ATLauncher)
|
||||
2. **Select Modpack**: Click on a modpack to see details
|
||||
3. **Create Server**: One click to create server from modpack
|
||||
4. **Automatic Setup**: Stronghold handles:
|
||||
- Downloading server pack
|
||||
- Setting up Docker container with correct server type (FORGE/FABRIC)
|
||||
- Installing mods
|
||||
- Configuring environment variables
|
||||
- Setting up volumes
|
||||
- Starting server
|
||||
5. **Ready to Play**: Server is ready, user can customize further if needed
|
||||
|
||||
### Technical Requirements
|
||||
|
||||
1. **Modpack Platform Integration**:
|
||||
- Modrinth API client
|
||||
- CurseForge API client
|
||||
- FTB API (if needed)
|
||||
|
||||
2. **Modpack Processing**:
|
||||
- Parse modpack manifest files
|
||||
- Download modpack files
|
||||
- Extract server packs
|
||||
- Handle mod dependencies
|
||||
- Version resolution
|
||||
|
||||
3. **Docker Integration**:
|
||||
- Detect server type (FORGE/FABRIC) from modpack
|
||||
- Set appropriate `TYPE` environment variable
|
||||
- Configure modpack installation
|
||||
- Set up proper Java versions
|
||||
- Allocate appropriate memory
|
||||
|
||||
4. **UI Components**:
|
||||
- Modpack browser/search
|
||||
- Modpack detail view
|
||||
- Installation progress
|
||||
- Mod management UI
|
||||
- Server configuration tied to modpack
|
||||
|
||||
### Simplification Goals
|
||||
|
||||
**From User Perspective:**
|
||||
- Before: User needs to know about modpack formats, server packs, FORGE vs FABRIC, Java versions, memory allocation, Docker, etc.
|
||||
- After: User finds modpack, clicks "Create Server", server is ready
|
||||
|
||||
**Implementation Complexity:**
|
||||
- Handle all the technical details internally
|
||||
- Provide smart defaults
|
||||
- Allow customization but don't require it
|
||||
- Good error messages if something goes wrong
|
||||
|
||||
### Implementation Phases
|
||||
|
||||
**Phase 1: Basic Modpack Support**
|
||||
- Manual modpack URL/ID input
|
||||
- Support for Modrinth server packs
|
||||
- Basic installation
|
||||
|
||||
**Phase 2: Modpack Browser**
|
||||
- Integrate Modrinth API
|
||||
- Browse/search modpacks
|
||||
- Server pack detection and installation
|
||||
|
||||
**Phase 3: Enhanced Features**
|
||||
- CurseForge integration
|
||||
- Modpack updates
|
||||
- Mod management UI
|
||||
- Advanced configuration options
|
||||
|
||||
---
|
||||
|
||||
## Related Tools
|
||||
|
||||
### Server Pack Generators
|
||||
Some modpacks come with server pack generators. Stronghold should:
|
||||
- Detect if server pack is available
|
||||
- Download server pack automatically
|
||||
- Use itzg container's built-in modpack support when possible
|
||||
- Handle cases where manual setup is needed
|
||||
|
||||
### itzg Container Modpack Support
|
||||
The itzg/docker-minecraft-server container has extensive built-in modpack support ([Documentation](https://docker-minecraft-server.readthedocs.io/en/latest/mods-and-plugins/)):
|
||||
|
||||
**Modpack Platforms**:
|
||||
- Modrinth (auto-download)
|
||||
- CurseForge (auto-download)
|
||||
- Feed the Beast (FTB)
|
||||
- Packwiz format
|
||||
|
||||
**Installation Methods**:
|
||||
- `MODPACK` environment variable: Simple zip file or modpack ID
|
||||
- `GENERIC_PACK` / `GENERIC_PACKS`: Install complete server content from archives
|
||||
- Individual mods via `MODS` / `PLUGINS` environment variables
|
||||
- File-based lists via `MODS_FILE` / `PLUGINS_FILE`
|
||||
|
||||
**Advanced Features**:
|
||||
- Volume mounts for mods/plugins/configs (`/mods`, `/plugins`, `/config`)
|
||||
- Auto-removal of mods/plugins
|
||||
- Environment variable substitution in configs
|
||||
- Multiple source directories
|
||||
- Disable specific mods
|
||||
|
||||
**Key Insight**: The container handles much of the complexity internally. Stronghold's role is to:
|
||||
1. Provide UI for modpack selection/browsing
|
||||
2. Detect modpack platform and server type automatically
|
||||
3. Generate appropriate environment variables
|
||||
4. Handle the container creation with proper configuration
|
||||
5. Manage modpack updates and mod additions/removals
|
||||
|
||||
Stronghold should leverage this built-in support heavily to simplify implementation - we don't need to reimplement modpack processing, just orchestrate it via the container's environment variables.
|
||||
|
||||
207
references/server-managers.md
Normal file
207
references/server-managers.md
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
# Server Management Web UIs Reference
|
||||
|
||||
These are existing web-based Minecraft server management tools that can provide inspiration for Stronghold's UI/UX and feature set.
|
||||
|
||||
## Crafty (CraftyControl)
|
||||
**Website**: https://craftycontrol.com
|
||||
|
||||
### Overview
|
||||
Web-based Minecraft server management tool. Stronghold takes inspiration from Crafty's approach to server management.
|
||||
|
||||
### Notable Features (based on common patterns)
|
||||
- Web-based interface for managing servers
|
||||
- Docker-based server hosting
|
||||
- Server creation and configuration UI
|
||||
- Console access
|
||||
- File browser/editor
|
||||
- Backup management
|
||||
- Plugin/mod management
|
||||
- User management (multi-user support)
|
||||
- Server templates/presets
|
||||
|
||||
### Design Philosophy
|
||||
- User-friendly interface
|
||||
- Simplified server management
|
||||
- Docker containerization
|
||||
- Self-hosted solution
|
||||
|
||||
### Lessons for Stronghold
|
||||
- Keep the UI clean and intuitive (KISS principle)
|
||||
- Make common tasks easy to accomplish
|
||||
- Provide good defaults with customization options
|
||||
- Focus on Docker-based deployment
|
||||
|
||||
---
|
||||
|
||||
## Pterodactyl Panel
|
||||
**GitHub**: https://github.com/pterodactyl/panel
|
||||
|
||||
### Overview
|
||||
Open-source game server management panel. Supports multiple game types including Minecraft. Uses a client-server architecture with Wings (daemon) and Panel (web UI).
|
||||
|
||||
### Architecture
|
||||
- **Panel**: Web UI (Laravel/PHP)
|
||||
- **Wings**: Daemon running on game servers (Go)
|
||||
- **API**: RESTful API between Panel and Wings
|
||||
- **Database**: MySQL/PostgreSQL
|
||||
|
||||
### Key Features
|
||||
- Multi-server management
|
||||
- User management and permissions
|
||||
- Resource allocation (CPU, memory, disk)
|
||||
- File manager with code editor
|
||||
- Console access
|
||||
- Backup system
|
||||
- Server templates
|
||||
- Plugin/mod installation
|
||||
- Resource monitoring
|
||||
- SFTP access
|
||||
- Multi-node support (Wings daemons on multiple hosts)
|
||||
|
||||
### Technology Stack
|
||||
- Backend: Laravel (PHP)
|
||||
- Daemon: Go
|
||||
- Frontend: React/Vue components
|
||||
- Database: MySQL/PostgreSQL
|
||||
|
||||
### Lessons for Stronghold
|
||||
- **Pros**:
|
||||
- Comprehensive feature set
|
||||
- Multi-user with permissions
|
||||
- Good separation of concerns (Panel/Daemon)
|
||||
- Resource management
|
||||
- **Cons/Considerations**:
|
||||
- Complex architecture (may violate KISS)
|
||||
- Requires database
|
||||
- More overhead than needed for single-host Docker setup
|
||||
- Can be over-engineered for simple use cases
|
||||
|
||||
**Takeaway**: Consider simplified version - Pterodactyl is powerful but complex. Stronghold can be simpler since it's focused on Docker containers rather than multi-node deployments.
|
||||
|
||||
---
|
||||
|
||||
## Fork (ForkGG)
|
||||
**GitHub**: https://github.com/ForkGG/Fork
|
||||
|
||||
### Overview
|
||||
Windows-based Minecraft server manager (not web-based). Built with .NET.
|
||||
|
||||
### Key Features
|
||||
- Simple, intuitive UI
|
||||
- Server creation wizard
|
||||
- Console management
|
||||
- File browser
|
||||
- Plugin/mod installation
|
||||
- Server templates
|
||||
- Backup management
|
||||
- Resource monitoring
|
||||
|
||||
### Design Philosophy
|
||||
- Windows-focused
|
||||
- User-friendly
|
||||
- Simplified workflows
|
||||
|
||||
### Lessons for Stronghold
|
||||
- Good UX patterns for server management
|
||||
- Simple workflows for common tasks
|
||||
- Focus on ease of use
|
||||
- Wizard-based server creation (good for beginners)
|
||||
|
||||
**Note**: Being Windows-focused limits direct applicability, but UX patterns are valuable.
|
||||
|
||||
---
|
||||
|
||||
## MCSManager
|
||||
**GitHub**: https://github.com/MCSManager/MCSManager
|
||||
|
||||
### Overview
|
||||
Open-source Minecraft server management panel. Built with Node.js.
|
||||
|
||||
### Architecture
|
||||
- **Web UI**: React-based frontend
|
||||
- **Backend**: Node.js/Express API
|
||||
- **Agent**: Daemon running on servers (also Node.js)
|
||||
- **Database**: MongoDB (or can use file-based)
|
||||
|
||||
### Key Features
|
||||
- Web-based interface
|
||||
- Multi-server management
|
||||
- Console access
|
||||
- File manager
|
||||
- Task scheduling
|
||||
- Backup system
|
||||
- User management
|
||||
- Server templates
|
||||
- Remote server management (via agents)
|
||||
- REST API
|
||||
|
||||
### Technology Stack
|
||||
- Backend: Node.js/Express
|
||||
- Frontend: React
|
||||
- Database: MongoDB (optional, can use files)
|
||||
- Agents: Node.js daemons
|
||||
|
||||
### Lessons for Stronghold
|
||||
- **Pros**:
|
||||
- Node.js stack (good for web-based tools)
|
||||
- Can work without database (file-based)
|
||||
- REST API architecture
|
||||
- Good separation (UI/API/Agent)
|
||||
- **Considerations**:
|
||||
- Agent-based architecture (may not be needed for Docker-only)
|
||||
- Can be complex
|
||||
- MongoDB dependency (unless using file mode)
|
||||
|
||||
**Takeaway**: Node.js stack could work well for Stronghold. The agent model might be overkill if we're just managing Docker containers directly.
|
||||
|
||||
---
|
||||
|
||||
## setupmc.com
|
||||
**Website**: https://setupmc.com/java-server/
|
||||
|
||||
### Overview
|
||||
Web UI for generating docker-compose.yml files for itzg docker-minecraft-server. Not open source but provides a good example of a configuration generator.
|
||||
|
||||
### Key Features
|
||||
- Interactive web form for server configuration
|
||||
- Generates docker-compose.yml files
|
||||
- Handles various server types
|
||||
- Configuration presets
|
||||
- Downloadable configuration files
|
||||
|
||||
### Lessons for Stronghold
|
||||
- **Inspiration**: This is essentially a subset of what Stronghold should do
|
||||
- Shows how to make Docker configuration user-friendly
|
||||
- Good example of configuration UI patterns
|
||||
- Proves the value of simplifying Docker setup
|
||||
|
||||
**Takeaway**: Stronghold should go beyond just generating configs - should also manage the actual containers, but this is a good reference for the configuration UI.
|
||||
|
||||
---
|
||||
|
||||
## Comparison Summary
|
||||
|
||||
| Feature | Crafty | Pterodactyl | Fork | MCSManager | setupmc.com |
|
||||
|---------|--------|-------------|------|------------|-------------|
|
||||
| Web UI | ✅ | ✅ | ❌ | ✅ | ✅ |
|
||||
| Docker-based | ✅ | ❌ (Wings) | ❌ | ❌ (Agents) | ✅ |
|
||||
| Multi-user | ✅ | ✅ | ❌ | ✅ | ❌ |
|
||||
| Complexity | Medium | High | Low | Medium | Low |
|
||||
| Database | Yes | Yes | No | Optional | No |
|
||||
| Architecture | Simple | Panel/Daemon | Desktop | UI/API/Agent | Static site |
|
||||
|
||||
### Recommendations for Stronghold
|
||||
|
||||
1. **KISS Principle**: Keep architecture simple - Docker API directly, no agents/daemons needed
|
||||
2. **Database**: Start without database (file-based config), add later if needed
|
||||
3. **Stack**: Node.js/Express + React could be good (like MCSManager but simpler)
|
||||
4. **Features**: Focus on essential features first:
|
||||
- Server CRUD operations
|
||||
- Configuration UI
|
||||
- Console access
|
||||
- File browser
|
||||
- Basic backups
|
||||
5. **Multi-user**: Can add later, not essential for MVP
|
||||
6. **UI Patterns**: Study Crafty and Fork for UX inspiration
|
||||
7. **Configuration**: Use setupmc.com as reference for config UI patterns
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue