try this shi
This commit is contained in:
34
.gitignore
vendored
Normal file
34
.gitignore
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
# Dependencies
|
||||
node_modules/
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
package-lock.json
|
||||
|
||||
# Environment variables
|
||||
.env
|
||||
.env.local
|
||||
.env.production
|
||||
|
||||
# Build outputs
|
||||
dist/
|
||||
build/
|
||||
*.log
|
||||
|
||||
# IDE
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Minecraft data
|
||||
data/
|
||||
|
||||
# Docker
|
||||
.dockerignore
|
||||
|
||||
101
QUICKSTART.md
Normal file
101
QUICKSTART.md
Normal file
@@ -0,0 +1,101 @@
|
||||
# ⚡ Quick Start Guide
|
||||
|
||||
Get your Minecraft Dashboard up and running in 3 simple steps!
|
||||
|
||||
## Prerequisites
|
||||
- Docker and Docker Compose installed
|
||||
- Minecraft server running on `mcnet` network
|
||||
|
||||
## 🚀 3-Step Setup
|
||||
|
||||
### 1️⃣ Start Your Minecraft Server
|
||||
|
||||
If not already running, start your Minecraft server with the provided configuration:
|
||||
|
||||
```bash
|
||||
docker-compose -f docker-compose.minecraft.yml up -d
|
||||
```
|
||||
|
||||
### 2️⃣ Launch the Dashboard
|
||||
|
||||
Simply run:
|
||||
|
||||
```bash
|
||||
./start-dashboard.sh
|
||||
```
|
||||
|
||||
This will:
|
||||
- Create the `mcnet` network (if it doesn't exist)
|
||||
- Build the frontend and backend containers
|
||||
- Start all dashboard services
|
||||
|
||||
### 3️⃣ Open the Dashboard
|
||||
|
||||
Navigate to in your browser:
|
||||
```
|
||||
http://localhost:8080
|
||||
```
|
||||
|
||||
## 🎮 Using the Dashboard
|
||||
|
||||
### Features:
|
||||
- **🟢 Server Status** - See if your server is online
|
||||
- **👥 Player Count** - Monitor active players
|
||||
- **▶️ Start Button** - Start the Minecraft server
|
||||
- **⏹️ Stop Button** - Gracefully stop the server
|
||||
- **🔄 Auto-Refresh** - Updates every 5 seconds
|
||||
|
||||
### Controls:
|
||||
- Click **START SERVER** to boot up your Minecraft server
|
||||
- Click **STOP SERVER** to safely shut it down (requires confirmation)
|
||||
- Click **🔄** to manually refresh the status
|
||||
|
||||
## 🛑 Stopping the Dashboard
|
||||
|
||||
When you're done:
|
||||
|
||||
```bash
|
||||
./stop-dashboard.sh
|
||||
```
|
||||
|
||||
Or manually:
|
||||
```bash
|
||||
docker-compose -f docker-compose.dashboard.yml down
|
||||
```
|
||||
|
||||
## 📝 Useful Commands
|
||||
|
||||
```bash
|
||||
# View logs
|
||||
docker-compose -f docker-compose.dashboard.yml logs -f
|
||||
|
||||
# Restart the dashboard
|
||||
docker-compose -f docker-compose.dashboard.yml restart
|
||||
|
||||
# Rebuild after making changes
|
||||
docker-compose -f docker-compose.dashboard.yml up -d --build
|
||||
```
|
||||
|
||||
## ❓ Common Issues
|
||||
|
||||
**Dashboard shows "Server Offline"**
|
||||
- Make sure Minecraft server is running: `docker ps | grep mc-java`
|
||||
- Verify RCON is enabled in your Minecraft configuration
|
||||
|
||||
**Start/Stop buttons don't work**
|
||||
- Check Docker socket access: `docker inspect mc-dashboard-backend | grep docker.sock`
|
||||
|
||||
**Can't access dashboard**
|
||||
- Verify port 8080 is not in use: `lsof -i :8080`
|
||||
- Check if frontend is running: `docker ps | grep mc-dashboard-frontend`
|
||||
|
||||
## 📖 Need More Help?
|
||||
|
||||
See the full documentation:
|
||||
- [README.md](README.md) - Complete documentation
|
||||
- [SETUP.md](SETUP.md) - Detailed setup guide
|
||||
|
||||
---
|
||||
|
||||
Enjoy your Minecraft Dashboard! 🎮⛏️
|
||||
|
||||
218
README.md
Normal file
218
README.md
Normal file
@@ -0,0 +1,218 @@
|
||||
# 🎮 Minecraft Server Dashboard
|
||||
|
||||
A beautiful, modern web dashboard to monitor and control your Minecraft server with real-time statistics and server management.
|
||||
|
||||

|
||||
|
||||
## ✨ Features
|
||||
|
||||
- 🎯 **Real-time Server Monitoring**
|
||||
- Player count and online players list
|
||||
- Server version and status
|
||||
- Latency monitoring
|
||||
- TPS (Ticks Per Second) tracking
|
||||
|
||||
- 🎮 **Server Control**
|
||||
- Start server with one click
|
||||
- Stop server gracefully (with confirmation)
|
||||
- Automatic status refresh every 5 seconds
|
||||
|
||||
- 🎨 **Beautiful UI**
|
||||
- Modern gradient design
|
||||
- Minecraft-themed color palette
|
||||
- Responsive layout for all devices
|
||||
- Smooth animations and transitions
|
||||
- Real-time status indicators
|
||||
|
||||
## 🏗️ Architecture
|
||||
|
||||
### Backend
|
||||
- **Node.js + Express** - RESTful API server
|
||||
- **RCON Integration** - Direct communication with Minecraft server
|
||||
- **Docker API** - Container management for start/stop functionality
|
||||
- **minecraft-server-util** - Server status queries
|
||||
|
||||
### Frontend
|
||||
- **React 18** - Modern UI framework
|
||||
- **Vite** - Lightning-fast build tool
|
||||
- **Tailwind CSS** - Utility-first styling
|
||||
- **Lucide React** - Beautiful icons
|
||||
- **Axios** - HTTP client
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
### Prerequisites
|
||||
- Docker and Docker Compose installed
|
||||
- Existing Minecraft server running on `mcnet` network
|
||||
|
||||
### Installation
|
||||
|
||||
1. **Clone or navigate to the project directory**
|
||||
```bash
|
||||
cd mc
|
||||
```
|
||||
|
||||
2. **Start your Minecraft server** (if not already running)
|
||||
```bash
|
||||
docker-compose -f docker-compose.minecraft.yml up -d
|
||||
```
|
||||
|
||||
3. **Build and start the dashboard**
|
||||
```bash
|
||||
docker-compose -f docker-compose.dashboard.yml up -d --build
|
||||
```
|
||||
|
||||
4. **Access the dashboard**
|
||||
- Open your browser to: `http://localhost:8080`
|
||||
|
||||
### Development Mode
|
||||
|
||||
For local development without Docker:
|
||||
|
||||
**Backend:**
|
||||
```bash
|
||||
cd backend
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
**Frontend:**
|
||||
```bash
|
||||
cd frontend
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
## 📁 Project Structure
|
||||
|
||||
```
|
||||
mc/
|
||||
├── backend/
|
||||
│ ├── src/
|
||||
│ │ └── index.js # Express API server
|
||||
│ ├── Dockerfile
|
||||
│ └── package.json
|
||||
├── frontend/
|
||||
│ ├── src/
|
||||
│ │ ├── App.jsx # Main React component
|
||||
│ │ ├── main.jsx
|
||||
│ │ ├── index.css
|
||||
│ │ └── App.css
|
||||
│ ├── public/
|
||||
│ ├── index.html
|
||||
│ ├── Dockerfile
|
||||
│ ├── nginx.conf
|
||||
│ ├── vite.config.js
|
||||
│ └── package.json
|
||||
├── docker-compose.dashboard.yml
|
||||
└── README.md
|
||||
```
|
||||
|
||||
## 🔧 Configuration
|
||||
|
||||
### Environment Variables
|
||||
|
||||
Create a `.env` file based on `.env.example`:
|
||||
|
||||
```env
|
||||
# Minecraft Server
|
||||
MINECRAFT_HOST=mc-java
|
||||
MINECRAFT_PORT=25565
|
||||
RCON_PORT=25575
|
||||
RCON_PASSWORD=bethureddy1
|
||||
CONTAINER_NAME=mc-java
|
||||
|
||||
# Dashboard
|
||||
DASHBOARD_PORT=8080
|
||||
```
|
||||
|
||||
### Network Configuration
|
||||
|
||||
The dashboard connects to your Minecraft server via the `mcnet` Docker network. Make sure your Minecraft server is on this network:
|
||||
|
||||
```yaml
|
||||
networks:
|
||||
mcnet:
|
||||
external: true
|
||||
```
|
||||
|
||||
## 📊 API Endpoints
|
||||
|
||||
### GET `/api/status`
|
||||
Returns Minecraft server status including:
|
||||
- Online status
|
||||
- Player count and list
|
||||
- Server version
|
||||
- Latency
|
||||
- TPS (if available)
|
||||
- MOTD
|
||||
|
||||
### GET `/api/container/status`
|
||||
Returns Docker container status:
|
||||
- Running state
|
||||
- Container health
|
||||
- Start time
|
||||
|
||||
### POST `/api/server/start`
|
||||
Starts the Minecraft server container
|
||||
|
||||
### POST `/api/server/stop`
|
||||
Gracefully stops the Minecraft server (saves world first)
|
||||
|
||||
## 🎨 UI Components
|
||||
|
||||
### Status Cards
|
||||
- **Players** - Current player count vs max players
|
||||
- **Version** - Minecraft server version
|
||||
- **Latency** - Server response time
|
||||
- **TPS** - Server performance metric
|
||||
|
||||
### Control Panel
|
||||
- **Start Button** - Starts the server (disabled when running)
|
||||
- **Stop Button** - Stops the server with confirmation (disabled when stopped)
|
||||
- **Refresh Button** - Manually refresh status
|
||||
|
||||
### Player List
|
||||
- Displays all currently online players
|
||||
- Beautiful avatar placeholders
|
||||
- Grid layout for easy viewing
|
||||
|
||||
## 🐛 Troubleshooting
|
||||
|
||||
### Dashboard can't connect to Minecraft server
|
||||
- Ensure Minecraft server is running: `docker ps | grep mc-java`
|
||||
- Verify both containers are on `mcnet` network
|
||||
- Check RCON is enabled in server configuration
|
||||
|
||||
### Start/Stop buttons not working
|
||||
- Ensure backend has access to Docker socket
|
||||
- Verify volume mount: `/var/run/docker.sock:/var/run/docker.sock`
|
||||
- Check container name matches: `CONTAINER_NAME=mc-java`
|
||||
|
||||
### RCON connection failed
|
||||
- Verify RCON password matches Minecraft server
|
||||
- Check RCON port (default: 25575)
|
||||
- Ensure RCON is enabled in server.properties
|
||||
|
||||
## 🔒 Security Notes
|
||||
|
||||
- The dashboard requires access to Docker socket for start/stop functionality
|
||||
- RCON password is configured via environment variables
|
||||
- Consider using Docker secrets for production deployments
|
||||
- Restrict dashboard access using firewall rules or reverse proxy authentication
|
||||
|
||||
## 📝 License
|
||||
|
||||
MIT
|
||||
|
||||
## 🤝 Contributing
|
||||
|
||||
Contributions are welcome! Feel free to submit issues and pull requests.
|
||||
|
||||
## 💖 Acknowledgments
|
||||
|
||||
- Built with React and Node.js
|
||||
- Minecraft server status via minecraft-server-util
|
||||
- RCON implementation using modern-rcon
|
||||
- Icons by Lucide React
|
||||
|
||||
241
SETUP.md
Normal file
241
SETUP.md
Normal file
@@ -0,0 +1,241 @@
|
||||
# 🚀 Setup Guide for Minecraft Dashboard
|
||||
|
||||
## Quick Setup (Recommended)
|
||||
|
||||
### Step 1: Ensure Minecraft Server is Running
|
||||
|
||||
First, make sure your Minecraft server is running. Save this as `docker-compose.minecraft.yml`:
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
minecraft:
|
||||
image: itzg/minecraft-server:latest
|
||||
container_name: mc-java
|
||||
environment:
|
||||
EULA: "TRUE"
|
||||
ENABLE_RCON: "true"
|
||||
RCON_PASSWORD: "bethureddy1"
|
||||
RCON_PORT: "25575"
|
||||
TZ: "America/Chicago"
|
||||
TYPE: "PAPER"
|
||||
VERSION: "1.21.10"
|
||||
MEMORY: "20G"
|
||||
volumes:
|
||||
- ./data:/data
|
||||
expose:
|
||||
- "25565"
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- mcnet
|
||||
|
||||
nginx-stream:
|
||||
image: nginx:1.27-alpine
|
||||
container_name: mc-proxy
|
||||
depends_on:
|
||||
- minecraft
|
||||
ports:
|
||||
- "25565:25565/tcp"
|
||||
volumes:
|
||||
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- mcnet
|
||||
|
||||
networks:
|
||||
mcnet:
|
||||
driver: bridge
|
||||
```
|
||||
|
||||
Start the Minecraft server:
|
||||
```bash
|
||||
docker-compose -f docker-compose.minecraft.yml up -d
|
||||
```
|
||||
|
||||
### Step 2: Start the Dashboard
|
||||
|
||||
Make the start script executable and run it:
|
||||
|
||||
```bash
|
||||
chmod +x start-dashboard.sh
|
||||
./start-dashboard.sh
|
||||
```
|
||||
|
||||
Or manually:
|
||||
```bash
|
||||
docker-compose -f docker-compose.dashboard.yml up -d --build
|
||||
```
|
||||
|
||||
### Step 3: Access the Dashboard
|
||||
|
||||
Open your browser and navigate to:
|
||||
```
|
||||
http://localhost:8080
|
||||
```
|
||||
|
||||
## 🎯 What You'll See
|
||||
|
||||
The dashboard displays:
|
||||
|
||||
1. **Server Status** - Real-time online/offline indicator
|
||||
2. **Control Buttons** - Start and Stop your server
|
||||
3. **Player Count** - Current players vs max capacity
|
||||
4. **Server Version** - Minecraft version running
|
||||
5. **Latency** - Server response time
|
||||
6. **TPS** - Server performance (if available)
|
||||
7. **Online Players List** - Names of all connected players
|
||||
8. **MOTD** - Server message of the day
|
||||
|
||||
## 🛠️ Troubleshooting
|
||||
|
||||
### Dashboard shows "Server Offline" but server is running
|
||||
|
||||
1. Check if both containers are on the same network:
|
||||
```bash
|
||||
docker network inspect mcnet
|
||||
```
|
||||
|
||||
2. Verify RCON is enabled on the Minecraft server:
|
||||
```bash
|
||||
docker exec mc-java cat /data/server.properties | grep rcon
|
||||
```
|
||||
|
||||
3. Check backend logs:
|
||||
```bash
|
||||
docker logs mc-dashboard-backend
|
||||
```
|
||||
|
||||
### Start/Stop buttons don't work
|
||||
|
||||
The backend needs access to the Docker socket. Verify the volume mount:
|
||||
```bash
|
||||
docker inspect mc-dashboard-backend | grep docker.sock
|
||||
```
|
||||
|
||||
Should show: `/var/run/docker.sock:/var/run/docker.sock`
|
||||
|
||||
### Dashboard won't load
|
||||
|
||||
1. Check if frontend is running:
|
||||
```bash
|
||||
docker ps | grep mc-dashboard-frontend
|
||||
```
|
||||
|
||||
2. Check frontend logs:
|
||||
```bash
|
||||
docker logs mc-dashboard-frontend
|
||||
```
|
||||
|
||||
3. Verify port 8080 is not in use:
|
||||
```bash
|
||||
lsof -i :8080
|
||||
```
|
||||
|
||||
## 🔄 Updates and Maintenance
|
||||
|
||||
### Rebuild the Dashboard
|
||||
```bash
|
||||
docker-compose -f docker-compose.dashboard.yml up -d --build
|
||||
```
|
||||
|
||||
### View Logs
|
||||
```bash
|
||||
# All services
|
||||
docker-compose -f docker-compose.dashboard.yml logs -f
|
||||
|
||||
# Backend only
|
||||
docker logs -f mc-dashboard-backend
|
||||
|
||||
# Frontend only
|
||||
docker logs -f mc-dashboard-frontend
|
||||
```
|
||||
|
||||
### Stop the Dashboard
|
||||
```bash
|
||||
./stop-dashboard.sh
|
||||
```
|
||||
|
||||
Or manually:
|
||||
```bash
|
||||
docker-compose -f docker-compose.dashboard.yml down
|
||||
```
|
||||
|
||||
## 🔐 Security Considerations
|
||||
|
||||
1. **Change RCON Password**: Update `RCON_PASSWORD` in both your Minecraft and dashboard configurations
|
||||
2. **Firewall**: Only expose port 8080 to trusted networks
|
||||
3. **Reverse Proxy**: Consider using nginx/traefik with authentication for production
|
||||
4. **Docker Socket**: The backend needs Docker socket access - only run in trusted environments
|
||||
|
||||
## 📊 Port Usage
|
||||
|
||||
- **8080** - Dashboard web interface
|
||||
- **3001** - Backend API (internal only)
|
||||
- **25565** - Minecraft server
|
||||
- **25575** - RCON (internal only)
|
||||
|
||||
## 🎨 Customization
|
||||
|
||||
### Change Dashboard Port
|
||||
|
||||
Edit `docker-compose.dashboard.yml`:
|
||||
```yaml
|
||||
mc-dashboard-frontend:
|
||||
ports:
|
||||
- "3000:80" # Change 8080 to your preferred port
|
||||
```
|
||||
|
||||
### Update Refresh Interval
|
||||
|
||||
Edit `frontend/src/App.jsx`, line with `setInterval`:
|
||||
```javascript
|
||||
const interval = setInterval(fetchStatus, 10000) // 10 seconds instead of 5
|
||||
```
|
||||
|
||||
## 🐳 Docker Commands Reference
|
||||
|
||||
```bash
|
||||
# Start everything
|
||||
docker-compose -f docker-compose.dashboard.yml up -d
|
||||
|
||||
# Stop everything
|
||||
docker-compose -f docker-compose.dashboard.yml down
|
||||
|
||||
# Rebuild and restart
|
||||
docker-compose -f docker-compose.dashboard.yml up -d --build
|
||||
|
||||
# View logs
|
||||
docker-compose -f docker-compose.dashboard.yml logs -f
|
||||
|
||||
# Restart a specific service
|
||||
docker-compose -f docker-compose.dashboard.yml restart mc-dashboard-backend
|
||||
|
||||
# Remove everything including volumes
|
||||
docker-compose -f docker-compose.dashboard.yml down -v
|
||||
```
|
||||
|
||||
## ✅ Verification Checklist
|
||||
|
||||
- [ ] Minecraft server is running
|
||||
- [ ] RCON is enabled on Minecraft server
|
||||
- [ ] Both services are on `mcnet` network
|
||||
- [ ] Backend has Docker socket access
|
||||
- [ ] Port 8080 is available
|
||||
- [ ] Dashboard shows "Server Online"
|
||||
- [ ] Start/Stop buttons work
|
||||
- [ ] Player count updates
|
||||
|
||||
## 🆘 Getting Help
|
||||
|
||||
If you encounter issues:
|
||||
|
||||
1. Check logs: `docker-compose -f docker-compose.dashboard.yml logs`
|
||||
2. Verify network: `docker network inspect mcnet`
|
||||
3. Test RCON: `docker exec mc-java rcon-cli -p bethureddy1 list`
|
||||
4. Restart everything: `./stop-dashboard.sh && ./start-dashboard.sh`
|
||||
|
||||
---
|
||||
|
||||
Happy Minecrafting! 🎮⛏️
|
||||
|
||||
14
backend/Dockerfile
Normal file
14
backend/Dockerfile
Normal file
@@ -0,0 +1,14 @@
|
||||
FROM node:20-alpine
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY package*.json ./
|
||||
|
||||
RUN npm install --production
|
||||
|
||||
COPY . .
|
||||
|
||||
EXPOSE 3001
|
||||
|
||||
CMD ["npm", "start"]
|
||||
|
||||
19
backend/package.json
Normal file
19
backend/package.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "mc-dashboard-backend",
|
||||
"version": "1.0.0",
|
||||
"description": "Minecraft Server Dashboard Backend",
|
||||
"main": "src/index.js",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"start": "node src/index.js",
|
||||
"dev": "node --watch src/index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"express": "^4.18.2",
|
||||
"cors": "^2.8.5",
|
||||
"minecraft-server-util": "^5.4.3",
|
||||
"modern-rcon": "^1.2.1",
|
||||
"dockerode": "^4.0.2"
|
||||
}
|
||||
}
|
||||
|
||||
169
backend/src/index.js
Normal file
169
backend/src/index.js
Normal file
@@ -0,0 +1,169 @@
|
||||
import express from 'express';
|
||||
import cors from 'cors';
|
||||
import { status } from 'minecraft-server-util';
|
||||
import Rcon from 'modern-rcon';
|
||||
import Docker from 'dockerode';
|
||||
|
||||
const app = express();
|
||||
const PORT = process.env.PORT || 3001;
|
||||
|
||||
app.use(cors());
|
||||
app.use(express.json());
|
||||
|
||||
const MINECRAFT_HOST = process.env.MINECRAFT_HOST || 'mc-java';
|
||||
const MINECRAFT_PORT = parseInt(process.env.MINECRAFT_PORT || '25565');
|
||||
const RCON_PORT = parseInt(process.env.RCON_PORT || '25575');
|
||||
const RCON_PASSWORD = process.env.RCON_PASSWORD || 'bethureddy1';
|
||||
const CONTAINER_NAME = process.env.CONTAINER_NAME || 'mc-java';
|
||||
|
||||
const docker = new Docker({ socketPath: '/var/run/docker.sock' });
|
||||
|
||||
// Get server status
|
||||
app.get('/api/status', async (req, res) => {
|
||||
try {
|
||||
const response = await status(MINECRAFT_HOST, MINECRAFT_PORT, {
|
||||
timeout: 5000,
|
||||
enableSRV: true
|
||||
});
|
||||
|
||||
let playerList = [];
|
||||
let tps = null;
|
||||
let usedMemory = null;
|
||||
let maxMemory = null;
|
||||
|
||||
// Try to get additional info via RCON if server is online
|
||||
try {
|
||||
const rcon = new Rcon(MINECRAFT_HOST, RCON_PORT, RCON_PASSWORD);
|
||||
await rcon.connect();
|
||||
|
||||
// Get player list
|
||||
const listResponse = await rcon.send('list');
|
||||
playerList = parsePlayerList(listResponse);
|
||||
|
||||
// Get TPS and memory info
|
||||
try {
|
||||
const tpsResponse = await rcon.send('spark tps');
|
||||
tps = parseTPS(tpsResponse);
|
||||
} catch (e) {
|
||||
// spark might not be installed
|
||||
}
|
||||
|
||||
await rcon.disconnect();
|
||||
} catch (rconError) {
|
||||
console.error('RCON error:', rconError.message);
|
||||
}
|
||||
|
||||
res.json({
|
||||
online: true,
|
||||
version: response.version.name,
|
||||
protocol: response.version.protocol,
|
||||
players: {
|
||||
online: response.players.online,
|
||||
max: response.players.max,
|
||||
list: playerList
|
||||
},
|
||||
motd: response.motd.clean,
|
||||
latency: response.roundTripLatency,
|
||||
tps: tps,
|
||||
memory: {
|
||||
used: usedMemory,
|
||||
max: maxMemory
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Status error:', error.message);
|
||||
res.json({
|
||||
online: false,
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Get container status
|
||||
app.get('/api/container/status', async (req, res) => {
|
||||
try {
|
||||
const container = docker.getContainer(CONTAINER_NAME);
|
||||
const info = await container.inspect();
|
||||
|
||||
res.json({
|
||||
running: info.State.Running,
|
||||
status: info.State.Status,
|
||||
startedAt: info.State.StartedAt,
|
||||
health: info.State.Health?.Status || 'unknown'
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Container status error:', error.message);
|
||||
res.status(500).json({ error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
// Start the Minecraft server
|
||||
app.post('/api/server/start', async (req, res) => {
|
||||
try {
|
||||
const container = docker.getContainer(CONTAINER_NAME);
|
||||
const info = await container.inspect();
|
||||
|
||||
if (info.State.Running) {
|
||||
return res.json({ success: false, message: 'Server is already running' });
|
||||
}
|
||||
|
||||
await container.start();
|
||||
res.json({ success: true, message: 'Server started successfully' });
|
||||
} catch (error) {
|
||||
console.error('Start error:', error.message);
|
||||
res.status(500).json({ success: false, error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
// Stop the Minecraft server
|
||||
app.post('/api/server/stop', async (req, res) => {
|
||||
try {
|
||||
const container = docker.getContainer(CONTAINER_NAME);
|
||||
const info = await container.inspect();
|
||||
|
||||
if (!info.State.Running) {
|
||||
return res.json({ success: false, message: 'Server is already stopped' });
|
||||
}
|
||||
|
||||
// Try graceful shutdown via RCON first
|
||||
try {
|
||||
const rcon = new Rcon(MINECRAFT_HOST, RCON_PORT, RCON_PASSWORD);
|
||||
await rcon.connect();
|
||||
await rcon.send('save-all');
|
||||
await rcon.send('stop');
|
||||
await rcon.disconnect();
|
||||
} catch (rconError) {
|
||||
console.error('RCON shutdown error, using docker stop:', rconError.message);
|
||||
await container.stop({ t: 30 }); // 30 second timeout
|
||||
}
|
||||
|
||||
res.json({ success: true, message: 'Server stopped successfully' });
|
||||
} catch (error) {
|
||||
console.error('Stop error:', error.message);
|
||||
res.status(500).json({ success: false, error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
// Helper function to parse player list from RCON
|
||||
function parsePlayerList(response) {
|
||||
const match = response.match(/There are \d+ of a max of \d+ players online: (.*)/);
|
||||
if (match && match[1]) {
|
||||
return match[1].split(', ').filter(name => name.length > 0);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
// Helper function to parse TPS (if spark is installed)
|
||||
function parseTPS(response) {
|
||||
const match = response.match(/TPS.*?(\d+\.?\d*)/);
|
||||
if (match) {
|
||||
return parseFloat(match[1]);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
app.listen(PORT, '0.0.0.0', () => {
|
||||
console.log(`🚀 Minecraft Dashboard Backend running on port ${PORT}`);
|
||||
console.log(`📡 Monitoring Minecraft server at ${MINECRAFT_HOST}:${MINECRAFT_PORT}`);
|
||||
});
|
||||
|
||||
34
docker-compose.dashboard.yml
Normal file
34
docker-compose.dashboard.yml
Normal file
@@ -0,0 +1,34 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
mc-dashboard-backend:
|
||||
build: ./backend
|
||||
container_name: mc-dashboard-backend
|
||||
environment:
|
||||
- MINECRAFT_HOST=mc-java
|
||||
- MINECRAFT_PORT=25565
|
||||
- RCON_PORT=25575
|
||||
- RCON_PASSWORD=bethureddy1
|
||||
- CONTAINER_NAME=mc-java
|
||||
- PORT=3001
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- mcnet
|
||||
|
||||
mc-dashboard-frontend:
|
||||
build: ./frontend
|
||||
container_name: mc-dashboard-frontend
|
||||
ports:
|
||||
- "8080:80"
|
||||
depends_on:
|
||||
- mc-dashboard-backend
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- mcnet
|
||||
|
||||
networks:
|
||||
mcnet:
|
||||
external: true
|
||||
|
||||
23
frontend/Dockerfile
Normal file
23
frontend/Dockerfile
Normal file
@@ -0,0 +1,23 @@
|
||||
FROM node:20-alpine as builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY package*.json ./
|
||||
|
||||
RUN npm install
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN npm run build
|
||||
|
||||
# Production stage
|
||||
FROM nginx:1.27-alpine
|
||||
|
||||
COPY --from=builder /app/dist /usr/share/nginx/html
|
||||
|
||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
|
||||
17
frontend/index.html
Normal file
17
frontend/index.html
Normal file
@@ -0,0 +1,17 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/minecraft-icon.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap" rel="stylesheet">
|
||||
<title>Minecraft Server Dashboard</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.jsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
25
frontend/nginx.conf
Normal file
25
frontend/nginx.conf
Normal file
@@ -0,0 +1,25 @@
|
||||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
location /api {
|
||||
proxy_pass http://mc-dashboard-backend:3001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $host;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
}
|
||||
|
||||
gzip on;
|
||||
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
|
||||
}
|
||||
|
||||
27
frontend/package.json
Normal file
27
frontend/package.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": "mc-dashboard-frontend",
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"axios": "^1.6.0",
|
||||
"lucide-react": "^0.294.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.2.43",
|
||||
"@types/react-dom": "^18.2.17",
|
||||
"@vitejs/plugin-react": "^4.2.1",
|
||||
"autoprefixer": "^10.4.16",
|
||||
"postcss": "^8.4.32",
|
||||
"tailwindcss": "^3.3.6",
|
||||
"vite": "^5.0.8"
|
||||
}
|
||||
}
|
||||
|
||||
7
frontend/postcss.config.js
Normal file
7
frontend/postcss.config.js
Normal file
@@ -0,0 +1,7 @@
|
||||
export default {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
||||
|
||||
9
frontend/public/minecraft-icon.svg
Normal file
9
frontend/public/minecraft-icon.svg
Normal file
@@ -0,0 +1,9 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
||||
<rect width="100" height="100" fill="#8B4513"/>
|
||||
<rect x="10" y="10" width="30" height="30" fill="#654321"/>
|
||||
<rect x="60" y="10" width="30" height="30" fill="#654321"/>
|
||||
<rect x="10" y="60" width="30" height="30" fill="#654321"/>
|
||||
<rect x="60" y="60" width="30" height="30" fill="#654321"/>
|
||||
<rect x="35" y="35" width="30" height="30" fill="#A0522D"/>
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 431 B |
2
frontend/src/App.css
Normal file
2
frontend/src/App.css
Normal file
@@ -0,0 +1,2 @@
|
||||
/* Additional custom styles if needed */
|
||||
|
||||
234
frontend/src/App.jsx
Normal file
234
frontend/src/App.jsx
Normal file
@@ -0,0 +1,234 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
import axios from 'axios'
|
||||
import {
|
||||
Play,
|
||||
Square,
|
||||
Users,
|
||||
Activity,
|
||||
Server,
|
||||
Clock,
|
||||
Zap,
|
||||
RefreshCw
|
||||
} from 'lucide-react'
|
||||
import './App.css'
|
||||
|
||||
const API_URL = import.meta.env.VITE_API_URL || '/api'
|
||||
|
||||
function App() {
|
||||
const [serverStatus, setServerStatus] = useState(null)
|
||||
const [containerStatus, setContainerStatus] = useState(null)
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [actionLoading, setActionLoading] = useState(false)
|
||||
const [lastUpdate, setLastUpdate] = useState(null)
|
||||
|
||||
const fetchStatus = async () => {
|
||||
try {
|
||||
const [serverRes, containerRes] = await Promise.all([
|
||||
axios.get(`${API_URL}/status`),
|
||||
axios.get(`${API_URL}/container/status`)
|
||||
])
|
||||
setServerStatus(serverRes.data)
|
||||
setContainerStatus(containerRes.data)
|
||||
setLastUpdate(new Date())
|
||||
setLoading(false)
|
||||
} catch (error) {
|
||||
console.error('Error fetching status:', error)
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
fetchStatus()
|
||||
const interval = setInterval(fetchStatus, 5000) // Update every 5 seconds
|
||||
return () => clearInterval(interval)
|
||||
}, [])
|
||||
|
||||
const handleStart = async () => {
|
||||
setActionLoading(true)
|
||||
try {
|
||||
await axios.post(`${API_URL}/server/start`)
|
||||
setTimeout(fetchStatus, 2000) // Wait 2s then refresh
|
||||
} catch (error) {
|
||||
console.error('Error starting server:', error)
|
||||
}
|
||||
setActionLoading(false)
|
||||
}
|
||||
|
||||
const handleStop = async () => {
|
||||
if (!window.confirm('Are you sure you want to stop the server?')) {
|
||||
return
|
||||
}
|
||||
setActionLoading(true)
|
||||
try {
|
||||
await axios.post(`${API_URL}/server/stop`)
|
||||
setTimeout(fetchStatus, 2000) // Wait 2s then refresh
|
||||
} catch (error) {
|
||||
console.error('Error stopping server:', error)
|
||||
}
|
||||
setActionLoading(false)
|
||||
}
|
||||
|
||||
const isServerOnline = serverStatus?.online && containerStatus?.running
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="min-h-screen flex items-center justify-center">
|
||||
<div className="text-white text-2xl flex items-center gap-3">
|
||||
<RefreshCw className="animate-spin" size={32} />
|
||||
Loading...
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="min-h-screen p-8">
|
||||
<div className="max-w-6xl mx-auto">
|
||||
{/* Header */}
|
||||
<div className="text-center mb-12">
|
||||
<h1 className="text-5xl font-bold text-white mb-4 drop-shadow-lg">
|
||||
⛏️ Minecraft Server Dashboard
|
||||
</h1>
|
||||
<p className="text-white/80 text-lg">
|
||||
Monitor and control your Minecraft server
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Status Overview Card */}
|
||||
<div className="bg-white/10 backdrop-blur-lg rounded-2xl p-8 mb-8 border-4 border-white/20">
|
||||
<div className="flex items-center justify-between mb-6">
|
||||
<div className="flex items-center gap-4">
|
||||
<div className={`w-4 h-4 rounded-full ${isServerOnline ? 'bg-green-400 pulse-glow' : 'bg-red-400'}`}></div>
|
||||
<h2 className="text-3xl font-bold text-white">
|
||||
{isServerOnline ? 'Server Online' : 'Server Offline'}
|
||||
</h2>
|
||||
</div>
|
||||
{lastUpdate && (
|
||||
<div className="text-white/60 text-sm flex items-center gap-2">
|
||||
<Clock size={16} />
|
||||
Updated {lastUpdate.toLocaleTimeString()}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Control Buttons */}
|
||||
<div className="flex gap-4 mb-8">
|
||||
<button
|
||||
onClick={handleStart}
|
||||
disabled={actionLoading || (containerStatus?.running && isServerOnline)}
|
||||
className="minecraft-button flex-1 bg-green-500 hover:bg-green-600 disabled:bg-gray-400 disabled:cursor-not-allowed text-white font-bold py-4 px-8 rounded-lg flex items-center justify-center gap-3 text-lg"
|
||||
>
|
||||
<Play size={24} />
|
||||
Start Server
|
||||
</button>
|
||||
<button
|
||||
onClick={handleStop}
|
||||
disabled={actionLoading || !containerStatus?.running}
|
||||
className="minecraft-button flex-1 bg-red-500 hover:bg-red-600 disabled:bg-gray-400 disabled:cursor-not-allowed text-white font-bold py-4 px-8 rounded-lg flex items-center justify-center gap-3 text-lg"
|
||||
>
|
||||
<Square size={24} />
|
||||
Stop Server
|
||||
</button>
|
||||
<button
|
||||
onClick={fetchStatus}
|
||||
disabled={actionLoading}
|
||||
className="minecraft-button bg-blue-500 hover:bg-blue-600 disabled:bg-gray-400 text-white font-bold py-4 px-8 rounded-lg flex items-center justify-center"
|
||||
>
|
||||
<RefreshCw size={24} className={actionLoading ? 'animate-spin' : ''} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Stats Grid */}
|
||||
{isServerOnline && (
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
|
||||
{/* Players Online */}
|
||||
<div className="bg-gradient-to-br from-blue-500 to-blue-600 rounded-xl p-6 text-white">
|
||||
<div className="flex items-center gap-3 mb-2">
|
||||
<Users size={24} />
|
||||
<h3 className="font-semibold text-lg">Players</h3>
|
||||
</div>
|
||||
<p className="text-4xl font-bold">
|
||||
{serverStatus.players.online} / {serverStatus.players.max}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Server Version */}
|
||||
<div className="bg-gradient-to-br from-purple-500 to-purple-600 rounded-xl p-6 text-white">
|
||||
<div className="flex items-center gap-3 mb-2">
|
||||
<Server size={24} />
|
||||
<h3 className="font-semibold text-lg">Version</h3>
|
||||
</div>
|
||||
<p className="text-2xl font-bold truncate">
|
||||
{serverStatus.version}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Latency */}
|
||||
<div className="bg-gradient-to-br from-green-500 to-green-600 rounded-xl p-6 text-white">
|
||||
<div className="flex items-center gap-3 mb-2">
|
||||
<Activity size={24} />
|
||||
<h3 className="font-semibold text-lg">Latency</h3>
|
||||
</div>
|
||||
<p className="text-4xl font-bold">
|
||||
{serverStatus.latency}ms
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* TPS */}
|
||||
<div className="bg-gradient-to-br from-yellow-500 to-yellow-600 rounded-xl p-6 text-white">
|
||||
<div className="flex items-center gap-3 mb-2">
|
||||
<Zap size={24} />
|
||||
<h3 className="font-semibold text-lg">TPS</h3>
|
||||
</div>
|
||||
<p className="text-4xl font-bold">
|
||||
{serverStatus.tps || '20.0'}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Player List */}
|
||||
{isServerOnline && serverStatus.players.online > 0 && (
|
||||
<div className="bg-white/10 backdrop-blur-lg rounded-2xl p-8 border-4 border-white/20">
|
||||
<h2 className="text-2xl font-bold text-white mb-4 flex items-center gap-3">
|
||||
<Users size={28} />
|
||||
Online Players
|
||||
</h2>
|
||||
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
|
||||
{serverStatus.players.list.map((player, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="bg-white/20 rounded-lg p-4 text-white font-semibold flex items-center gap-2"
|
||||
>
|
||||
<div className="w-8 h-8 bg-gradient-to-br from-green-400 to-blue-500 rounded-md flex items-center justify-center text-xs">
|
||||
{player[0].toUpperCase()}
|
||||
</div>
|
||||
{player}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* MOTD */}
|
||||
{isServerOnline && serverStatus.motd && (
|
||||
<div className="bg-white/10 backdrop-blur-lg rounded-2xl p-8 mt-8 border-4 border-white/20">
|
||||
<h2 className="text-2xl font-bold text-white mb-4">Message of the Day</h2>
|
||||
<p className="text-white/90 text-lg font-mono">
|
||||
{serverStatus.motd}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Footer */}
|
||||
<div className="text-center mt-12 text-white/60">
|
||||
<p>Made with ❤️ for Minecraft</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default App
|
||||
|
||||
56
frontend/src/index.css
Normal file
56
frontend/src/index.css
Normal file
@@ -0,0 +1,56 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
||||
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
||||
sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.pixel-border {
|
||||
box-shadow:
|
||||
0 -4px 0 0 rgba(0,0,0,0.3),
|
||||
0 4px 0 0 rgba(255,255,255,0.3),
|
||||
-4px 0 0 0 rgba(0,0,0,0.3),
|
||||
4px 0 0 0 rgba(255,255,255,0.3);
|
||||
}
|
||||
|
||||
.minecraft-button {
|
||||
position: relative;
|
||||
transition: all 0.1s;
|
||||
box-shadow:
|
||||
0 4px 0 0 rgba(0,0,0,0.3);
|
||||
}
|
||||
|
||||
.minecraft-button:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow:
|
||||
0 6px 0 0 rgba(0,0,0,0.3);
|
||||
}
|
||||
|
||||
.minecraft-button:active {
|
||||
transform: translateY(2px);
|
||||
box-shadow:
|
||||
0 2px 0 0 rgba(0,0,0,0.3);
|
||||
}
|
||||
|
||||
.pulse-glow {
|
||||
animation: pulse-glow 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse-glow {
|
||||
0%, 100% {
|
||||
box-shadow: 0 0 20px rgba(93, 205, 227, 0.5);
|
||||
}
|
||||
50% {
|
||||
box-shadow: 0 0 40px rgba(93, 205, 227, 0.8);
|
||||
}
|
||||
}
|
||||
|
||||
11
frontend/src/main.jsx
Normal file
11
frontend/src/main.jsx
Normal file
@@ -0,0 +1,11 @@
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom/client'
|
||||
import App from './App.jsx'
|
||||
import './index.css'
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root')).render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>,
|
||||
)
|
||||
|
||||
27
frontend/tailwind.config.js
Normal file
27
frontend/tailwind.config.js
Normal file
@@ -0,0 +1,27 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
export default {
|
||||
content: [
|
||||
"./index.html",
|
||||
"./src/**/*.{js,ts,jsx,tsx}",
|
||||
],
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
minecraft: {
|
||||
grass: '#7cbd56',
|
||||
dirt: '#8b5a2b',
|
||||
stone: '#7a7a7a',
|
||||
diamond: '#5dcde3',
|
||||
emerald: '#50c878',
|
||||
gold: '#fcba03',
|
||||
redstone: '#dc143c',
|
||||
}
|
||||
},
|
||||
fontFamily: {
|
||||
minecraft: ['"Press Start 2P"', 'cursive'],
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [],
|
||||
}
|
||||
|
||||
17
frontend/vite.config.js
Normal file
17
frontend/vite.config.js
Normal file
@@ -0,0 +1,17 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
server: {
|
||||
host: '0.0.0.0',
|
||||
port: 3000,
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: process.env.VITE_API_URL || 'http://localhost:3001',
|
||||
changeOrigin: true
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
15
package.json
Normal file
15
package.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "minecraft-dashboard",
|
||||
"version": "1.0.0",
|
||||
"description": "Beautiful Minecraft Server Dashboard",
|
||||
"scripts": {
|
||||
"start": "./start-dashboard.sh",
|
||||
"stop": "./stop-dashboard.sh",
|
||||
"logs": "docker-compose -f docker-compose.dashboard.yml logs -f",
|
||||
"rebuild": "docker-compose -f docker-compose.dashboard.yml up -d --build"
|
||||
},
|
||||
"keywords": ["minecraft", "dashboard", "docker", "react", "nodejs"],
|
||||
"author": "",
|
||||
"license": "MIT"
|
||||
}
|
||||
|
||||
9
public/minecraft-icon.svg
Normal file
9
public/minecraft-icon.svg
Normal file
@@ -0,0 +1,9 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
|
||||
<rect width="100" height="100" fill="#8B4513"/>
|
||||
<rect x="10" y="10" width="30" height="30" fill="#654321"/>
|
||||
<rect x="60" y="10" width="30" height="30" fill="#654321"/>
|
||||
<rect x="10" y="60" width="30" height="30" fill="#654321"/>
|
||||
<rect x="60" y="60" width="30" height="30" fill="#654321"/>
|
||||
<rect x="35" y="35" width="30" height="30" fill="#A0522D"/>
|
||||
</svg>
|
||||
|
||||
|
After Width: | Height: | Size: 431 B |
23
start-dashboard.sh
Executable file
23
start-dashboard.sh
Executable file
@@ -0,0 +1,23 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Colors for output
|
||||
GREEN='\033[0;32m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
echo -e "${BLUE}🎮 Starting Minecraft Dashboard...${NC}"
|
||||
|
||||
# Check if mcnet network exists
|
||||
if ! docker network ls | grep -q mcnet; then
|
||||
echo -e "${BLUE}Creating mcnet network...${NC}"
|
||||
docker network create mcnet
|
||||
fi
|
||||
|
||||
# Build and start the dashboard
|
||||
echo -e "${BLUE}Building and starting dashboard services...${NC}"
|
||||
docker-compose -f docker-compose.dashboard.yml up -d --build
|
||||
|
||||
echo -e "${GREEN}✅ Dashboard is starting!${NC}"
|
||||
echo -e "${GREEN}📊 Access the dashboard at: http://localhost:8080${NC}"
|
||||
echo -e "${BLUE}📝 View logs: docker-compose -f docker-compose.dashboard.yml logs -f${NC}"
|
||||
|
||||
13
stop-dashboard.sh
Executable file
13
stop-dashboard.sh
Executable file
@@ -0,0 +1,13 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
echo -e "${BLUE}🛑 Stopping Minecraft Dashboard...${NC}"
|
||||
|
||||
docker-compose -f docker-compose.dashboard.yml down
|
||||
|
||||
echo -e "${RED}✅ Dashboard stopped!${NC}"
|
||||
|
||||
Reference in New Issue
Block a user