Update launcher submodule to commit e1371e2
MrixsCraft
Private Minecraft server project with a web-based launcher. Consists of two independent Go repositories unified via git submodules:
server/— backend (Go + net/http + PostgreSQL)launcher/— desktop launcher (Go + Fyne GUI)
Domain: minecraft.mrixs.me · CDN: cdn.mrixs.me
Architecture
┌─────────────┐ HTTP/API ┌──────────────┐
│ Launcher │ ◄──────────────► │ Server │
│ (Go+Fyne) │ Yggdrasil+REST │ (Go+pgx) │
└─────────────┘ └──────┬──────┘
│
┌──────┴──────┐
│ PostgreSQL │
│ 16 │
└─────────────┘
cdn.mrixs.me minecraft.mrixs.me
┌──────────┐ ┌────────────────┐
│ Caddy │ │ Caddy │
│ file srv │ │ reverse proxy │
│ (CAS) │ │ + HTTPS │
└──────────┘ └────────────────┘
Infrastructure (Docker Compose): Caddy · Go backend · PostgreSQL 16 · Watchtower (auto-update)
Directory Structure
MC-server/
├── .gitmodules # Submodules: launcher, server
├── docs/
│ ├── state.md # Project status and detailed architecture
│ ├── launcher/Specification.md # Launcher specification (RU)
│ └── server/Specification.md # Server specification (RU)
├── launcher/ # Git submodule — MrixsCraft-launcher
│ ├── cmd/launcher/main.go
│ └── internal/
│ ├── auth/ # Yggdrasil client
│ ├── config/ # Launcher settings & system paths
│ ├── fetcher/ # HTTP downloader with SHA-1 verification
│ ├── java/ # JRE detection/download
│ ├── launch/ # Manifest parsing, game launch, classpath assembly
│ ├── selfupdate/# Binary auto-updater (SHA-256)
│ └── ui/ # Fyne GUI (screens, components, theme)
└── server/ # Git submodule — MrixsCraft-server
├── cmd/
│ ├── server/main.go # HTTP routes, middleware, graceful shutdown
│ └── ci-release/main.go # CI release uploader
├── Dockerfile # Multi-stage (~20 MB)
├── docker-compose.yml # Caddy + backend + postgres + watchtower
├── Caddyfile # Reverse proxy, CDN, HTTPS
├── .gitea/workflows/ci.yml # CI: lint → test → build → docker push
├── migrations/
│ ├── 001_init.sql # Full schema: 6 tables + indexes
│ └── 002_migration_history.sql # Migration tracking
└── internal/
├── admin/ # Modpack CRUD, file upload, manifests
├── api/ # Public API: auth, skins, capes, launcher
├── auth/ # Yggdrasil: authenticate/refresh/validate
├── cas/ # Content-Addressable Storage (SHA-1)
├── config/ # ENV configuration
├── database/ # PostgreSQL (pgx/pgxpool), data models
├── middleware/ # CORS, Logging, Recovery, RateLimiter
├── session/ # Background expired-session cleanup
└── templates/ # Go html/template (dark theme)
Tech Stack
| Component | Technology |
|---|---|
| Language | Go 1.25 (server) · Go 1.22 (launcher) |
| HTTP | net/http (stdlib) |
| Database | PostgreSQL 16 + pgx/v5 |
| Hashing | SHA-1 (CAS) · SHA-256 (launcher releases) · bcrypt (passwords) |
| GUI | Fyne v2.4.5 |
| Auth | Custom Yggdrasil server + authlib-injector |
| Proxy | Caddy 2 (auto-HTTPS) |
| Containers | Docker + Docker Compose |
| Registry | Gitea Container Registry |
| CI/CD | Gitea Actions |
| Auto-update | Watchtower |
Getting Started
Prerequisites
- Go 1.25+ (server) / Go 1.22+ (launcher)
- Docker & Docker Compose (production)
- PostgreSQL 16 (if running without Docker)
Clone with Submodules
git clone --recurse-submodules gitea.mrixs.me:mrixs/mrixscraft.git MC-server
If already cloned without submodules:
git submodule update --init --recursive
Server
cd server/
# Configure
cp .env.example .env
# edit .env: DATABASE_URL, JWT_SECRET, etc.
# Run locally
go run ./cmd/server
# Or via Docker Compose
docker compose up -d
Required environment variables:
| Variable | Default | Required |
|---|---|---|
SERVER_PORT |
8080 |
No |
DATABASE_URL |
— | Yes |
CAS_DIR |
/var/www/cdn/files |
No |
JWT_SECRET |
— | Yes |
Launcher
cd launcher/
go build -o mrixscraft-launcher ./cmd/launcher
./mrixscraft-launcher
Or: go run ./cmd/launcher
Server API
Yggdrasil (Mojang-compatible)
| Method | Path | Description |
|---|---|---|
| POST | /authserver/authenticate |
Login with credentials |
| POST | /authserver/refresh |
Refresh token |
| POST | /authserver/validate |
Validate token (204) |
| POST | /authserver/invalidate |
Invalidate token |
| POST | /authserver/signout |
Sign out (delete all sessions) |
| GET | /sessionserver/session/minecraft/profile/{uuid} |
Player profile with textures |
Public API
| Method | Path | Description |
|---|---|---|
| POST | /api/web/register |
Player registration |
| POST | /api/web/login |
Website login |
| POST | /api/web/profile/skin |
Upload skin (PNG) |
| POST | /api/web/profile/cape |
Upload cape (PNG) |
| DELETE | /api/web/profile/skin |
Delete skin |
| GET | /api/web/profile/{uuid} |
Player profile |
Launcher API
| Method | Path | Description |
|---|---|---|
| GET | /api/launcher/latest |
Latest launcher version |
| GET | /api/servers.json |
Active modpack list |
| GET | /api/instances/{slug}/manifest.json |
Modpack manifest |
CAS (File Server)
| Method | Path | Description |
|---|---|---|
| GET | /files/{sha1} |
File by SHA-1 hash |
| GET | /files/launcher/{version}/{os}/{arch}/{filename} |
Launcher binary |
| GET | /skins/{hash} |
Skin/cape by hash |
Admin (Bearer token + role=admin)
| Method | Path | Description |
|---|---|---|
| GET | /api/admin/modpacks |
List modpacks |
| POST | /api/admin/modpacks |
Create modpack |
| PUT | /api/admin/modpacks/{id} |
Update modpack |
| DELETE | /api/admin/modpacks/{id} |
Deactivate modpack |
| POST | /api/admin/modpacks/{slug}/upload |
Upload files (≤500 MB) |
| POST | /api/admin/modpacks/{slug}/manifest |
Generate manifest.json |
| POST | /api/admin/launcher/release |
Upload launcher release (X-CI-Token) |
| GET | /admin |
Web admin interface (requires admin role) |
Content-Addressable Storage (CAS)
All files (mods, libraries, assets) are stored by their SHA-1 hash:
/var/www/cdn/files/ab/abcdef1234... (first 2 chars as subdirectory)
- Immutable — files are never overwritten
- Cache-Control:
public, max-age=31536000, immutable(1 year) - Deduplication — automatic (same hash = same file)
- Concurrent-safe — per-hash
sync.Mutexprevents race conditions - Verification — constant-time SHA-1 comparison
Database Schema
7 tables:
| Table | Purpose |
|---|---|
users |
Players (username, email, password_hash, uuid, role) |
player_textures |
Skins & capes (skin_hash, cape_hash → CAS) |
yggdrasil_sessions |
Auth sessions (access_token, client_token, expires_at) |
modpacks |
Modpacks/servers (slug, name, minecraft_version, java_version, server_ip) |
global_files |
CAS file registry (sha1 PK, size_bytes, file_name, mime_type) |
launcher_releases |
Launcher releases (version, os, arch, sha256, file_path) |
migration_history |
Applied migration tracking |
Migrations are applied manually: psql $DATABASE_URL -f migrations/001_init.sql
Launcher Client File Structure
| OS | Root Directory |
|---|---|
| Windows | %APPDATA%\MrixsCraft\ |
| macOS | ~/Library/Application Support/MrixsCraft/ |
| Linux | ~/.MrixsCraft/ |
MrixsCraft/
├── launcher.json # Settings (RAM, server URL, window)
├── session.json # Yggdrasil tokens
├── authlib-injector.jar # Auth interceptor
├── Java/{8,17,21}/ # Portable JREs
├── assets/ # Game assets
├── libraries/ # Shared libraries (LWJGL, etc.)
└── instances/{slug}/ # Isolated modpack clients
├── mods/
├── mods_backup/ # Unknown mods moved here (soft delete)
├── config/
└── resourcepacks/
Testing
# Server
cd server/
go test ./... -v -race -cover
# Launcher — no tests (GUI testing is impractical)
Server test coverage: cas, auth, api, session packages.
CI/CD
Gitea Actions pipeline (.gitea/workflows/ci.yml):
lint (go vet + gofmt) → test (race detector) → build → docker push (master only)
Images: gitea.mrixs.me/mrixs/mrixscraft-server:latest + :sha
Watchtower on VPS polls every 5 minutes and auto-deploys new images.
Known TODOs
Server
- Full-text file search in DB
- SIGHUP config reload (requires
config.Atomicrefactor)
Launcher
- PLAY button wired to
launch.Prepare+Game.Start(stub) - Server list hardcoded (not loaded from
/api/servers.json) - Java auto-download not implemented
- Skin avatar rendering (8×64 face crop)
- News/patchnotes on MainScreen
servers.datNBT manipulation
Infrastructure
- CI deploy step (SSH + docker compose up) — needs secrets
- Automatic Go migration runner (currently manual)
- Backup script not in cron
Commands Reference
# Server
cd server/
go build -o mrixscraft-server ./cmd/server
go test ./...
go run ./cmd/server
docker compose up -d
# Launcher
cd launcher/
go build -o mrixscraft-launcher ./cmd/launcher
go run ./cmd/launcher