A self-hosted platform for @mattlol85's ideas — running on bare metal, served to the internet.
Explore the docs »
Live Site
·
Report Bug
·
Request Feature
Table of Contents
Fitz-Net is a self-hosted, full-stack personal platform running on a home server — exposed to the internet via dynamic DNS. It's a place to build and ship real ideas, backed by real infrastructure: a Proxmox hypervisor, Docker containers, a Caddy reverse proxy, physical ESP32 hardware that talks to the backend over WebSockets, a self-hosted email server for fitznet.org, a Discord bot (Fitz-Bot) that manages a Minecraft server, and a full observability stack (Grafana, Loki, Prometheus, Promtail, cAdvisor).
Traffic arrives at fitznet.org, which is fronted by an external reverse proxy that forwards to fitznet.doomdns.org (dynamic DNS on the home router). From there it reaches a Proxmox server where the active Ubuntu VM runs Docker, hosting all services behind a Caddy reverse proxy. A second Ubuntu VM is kept idle as a spare/staging target.
graph TD
Internet(["🌐 Internet"])
FitznetOrg["fitznet.org\nReverse Proxy"]
DNS["fitznet.doomdns.org\nDynamic DNS"]
Router["🏠 Home Router\nPort Forwarding"]
subgraph Proxmox["Proxmox Server · 192.168.1.225"]
VM1["Ubuntu VM 1\n⏸ Idle"]
subgraph VM2["Ubuntu VM 2 · 192.168.1.59 — Docker"]
Caddy["Caddy\nReverse Proxy"]
subgraph Core["fitznet-core"]
Website["fitz-net-website\nReact SPA"]
API["fitz-net-api\nSpring Boot REST"]
Bell["GamerBell\nWebSocket + OTA"]
Mongo["MongoDB"]
end
subgraph Mail["mail/"]
MailServer["mailserver\nSMTP + IMAP"]
Roundcube["Roundcube\nWebmail"]
end
subgraph Obs["observability/"]
Grafana["Grafana\nlogs.fitznet.org"]
Prometheus["Prometheus\n:9090"]
Loki["Loki\n:3100"]
Promtail["Promtail"]
CAdvisor["cAdvisor\n:8081"]
NodeExp["node-exporter\n:9100"]
end
end
FitzBot["🤖 Fitz-Bot\nDiscord bot · Spring Boot"]
subgraph VM3["Ubuntu VM · Minecraft Server"]
MC["Minecraft Server\nRCON :25575 · whitelist"]
end
end
ESP32["📟 ESP32 Bell\nEsp32FitznetBell"]
Discord(["💬 Discord"])
Internet --> FitznetOrg --> DNS --> Router
Router -->|"80/443"| Caddy
Router -->|"25/587/993"| MailServer
Caddy --> Website
Caddy --> API
Caddy --> Bell
Caddy --> Roundcube
Caddy --> Grafana
API --> Mongo
MailServer --> Roundcube
ESP32 -->|"wss"| Bell
Discord <-->|"slash commands"| FitzBot
FitzBot -->|"RCON · whitelist add"| MC
Promtail -->|"logs"| Loki
CAdvisor -->|"metrics"| Prometheus
NodeExp -->|"metrics"| Prometheus
Loki --> Grafana
Prometheus --> Grafana
The services and how they interact at the application layer:
graph LR
Browser(["🖥 Browser"])
ESP32(["📟 ESP32 Device"])
subgraph Website["fitz-net-website · React 19 + Vite"]
React["App"]
AuthCtx["AuthContext\nJWT · localStorage"]
ApiSvc["api.js\nfetch wrapper"]
WSClient["STOMP WebSocket\nClient"]
end
subgraph API["fitz-net-api · Spring Boot 3.4"]
SecFilter["JWT Auth Filter"]
Controllers["Controllers"]
Services["Services"]
Repos["Repositories"]
MailSvc["EmailService\nSpring Mail"]
end
subgraph Bell["GamerBell · Spring Boot 3.4"]
WSHandler["ButtonWebSocket\nHandler"]
BellSvc["ButtonService\nSession Pool"]
FirmSvc["FirmwareService\nOTA Cache"]
end
Mongo[("MongoDB")]
GitHub(["GitHub Releases\nOTA Firmware"])
MailServer(["mail.fitznet.org\ndocker-mailserver"])
Browser --> React
React --> AuthCtx --> ApiSvc
ApiSvc -->|"REST / HTTPS"| SecFilter
SecFilter --> Controllers --> Services --> Repos --> Mongo
Services --> MailSvc -->|"SMTP"| MailServer
React --> WSClient
WSClient -->|"wss"| WSHandler
WSHandler --> BellSvc -->|"broadcast"| WSClient
ESP32 -->|"wss"| WSHandler
ESP32 -->|"GET /api/firmware/latest"| FirmSvc
FirmSvc -->|"fetch .bin"| GitHub
| Repo | Description |
|---|---|
| Fitz-Net | This repo — orchestration hub, architecture docs |
| fitz-net-api | Spring Boot 3.4 REST API — user management, auth, encryption, email |
| fitz-net-website | React 19 SPA — dashboard, live board, game stats, auth, password reset |
| GamerBell | Spring Boot WebSocket relay + OTA firmware server for ESP32 bells |
| Esp32FitznetBell | C++ / PlatformIO firmware for the physical ESP32 bell button |
| Fitz-Bot | Discord bot — voice-join milestones, media downloads (Radarr/Sonarr), Minecraft whitelist management |
| Fitz-Net-Agent-Sandbox | AI agent workspace + mail server Docker Compose config |
Repo: mattlol85/fitz-net-website
Live: https://fitznet.org
React 19 frontend served via Caddy. Features:
- Homepage with animated Fitz-Net branding
- Overwatch 2 tracker — competitive leaderboard, history charts, player avatars
- LiveBoard — real-time collaborative canvas via STOMP WebSocket
- GamerBell widget — live status of physical ESP32 button devices
- Status Dashboard — monitors all service health via Spring Actuator
- User auth (JWT), profile editing, forgot-password / reset-password flow
Stack: React 19 · Vite 6 · React Router 7 · Vanilla CSS Modules · Docker
Repo: mattlol85/fitz-net-api
Live: https://api.fitznet.org
Spring Boot 3.4 REST API and WebSocket backend. Features:
- User management (register, login, JWT auth, profile update)
- Overwatch 2 integration via OverFast API (player stats, ratings, history snapshots)
- LiveBoard STOMP WebSocket for shared canvas state
- AES encryption endpoints
- Password reset via email — generates secure tokens, sends reset links via
noreply@fitznet.org
Stack: Java 21 · Spring Boot 3.4 · MongoDB · Spring Security (JWT/BCrypt) · Spring Mail · Gradle · Docker
Key environment variables:
| Variable | Purpose |
|---|---|
JWT_SECRET |
HS256 signing key |
ADMIN_API_KEY |
Optional. Enables the X-Admin-Key header for managing user permissions (see below); unset disables it |
MONGO_HOST / MONGO_PORT |
MongoDB connection |
MONGO_USERNAME / MONGO_PASSWORD |
MongoDB app-user credentials |
MAIL_HOST |
SMTP host (mail.fitznet.org) |
MAIL_USERNAME |
SMTP user (noreply@fitznet.org) |
MAIL_PASSWORD |
SMTP password |
APP_BASE_URL |
Base URL for reset links (https://fitznet.org) |
Repo: mattlol85/GamerBell
Live: https://gamerbell.fitznet.org
Spring Boot WebSocket relay service bridging physical ESP32 button devices with the Fitz-Net web UI. Also handles over-the-air (OTA) firmware updates for ESP32s via the GitHub Releases API.
Stack: Java 21 · Spring Boot 3.4 · Spring WebSocket · Docker
Repo: mattlol85/Esp32FitznetBell
C++ / PlatformIO firmware for the physical ESP32 bell button. The device connects to GamerBell over a WebSocket to broadcast button press/release events and shows the currently active users on a local 0.96" OLED screen. WiFi credentials and the user's display name are configured at first boot through the FitzNetBell-Setup WiFiManager captive portal — nothing is hardcoded. New firmware is published as GitHub Releases and pushed to devices over the air via GamerBell's GET /api/firmware/latest.
Hardware: ESP32 DevKit · SSD1306 OLED (I2C — SDA GPIO 21, SCL GPIO 22) · push button on GPIO 13.
Stack: C++ · PlatformIO · Arduino framework · WebSockets · Adafruit SSD1306/GFX · ArduinoJson · WiFiManager · FastLED
Repo: mattlol85/Fitz-Bot
Discord bot for the Fitz-Net community. Built on JDA, it tracks voice-channel activity and posts milestone celebrations, exposes media-download commands backed by Radarr/Sonarr, and manages the Minecraft server that runs on a separate VM adjacent to the Docker host.
The /whitelist <username> command lets trusted members (gated by a configurable Discord role) add players to the Minecraft whitelist over RCON. Together with white-list=true + online-mode=true on the server, this keeps anonymous crawlers/bots out.
Slash commands:
| Command | Purpose |
|---|---|
/whitelist <username> |
Add a player to the Minecraft whitelist (role-gated) |
/setwhitelistrole <role> |
Choose which Discord role may use /whitelist (admin) |
/setbotchannel · /getbotchannel |
Configure where milestone messages post |
/joenet download · /joenet status |
Search/queue movies & TV (Radarr/Sonarr) |
Stack: Java 21 · Spring Boot 3.2 · JDA 5 · Gradle
Key environment variables:
| Variable | Purpose |
|---|---|
DISCORD_BOT_TOKEN |
Discord bot token |
MINECRAFT_RCON_HOST / MINECRAFT_RCON_PORT |
Minecraft server RCON endpoint |
MINECRAFT_RCON_PASSWORD |
RCON password (matches rcon.password in server.properties) |
JOENET_HOST · JOENET_RADARR_APIKEY · JOENET_SONARR_APIKEY |
Media download integration |
See docs/fitz-bot.md for the Minecraft topology and whitelist/RCON setup guide.
Config: Fitz-Net-Agent-Sandbox/mail/
Live: https://mail.fitznet.org (webmail) · mail.fitznet.org:993 (IMAP) · mail.fitznet.org:587 (SMTP)
Self-hosted email for fitznet.org running via Docker Compose alongside the other services.
| Container | Image | Role |
|---|---|---|
mailserver |
ghcr.io/docker-mailserver/docker-mailserver |
SMTP (Postfix) + IMAP (Dovecot) + rspamd spam filter + DKIM |
roundcube |
roundcube/roundcubemail |
Browser-based webmail, proxied through Caddy |
DNS records required:
| Type | Name | Value |
|---|---|---|
| A | mail |
<public IP> |
| MX | @ |
mail.fitznet.org (priority 10) |
| TXT | @ |
v=spf1 mx ~all |
| TXT | _dmarc |
v=DMARC1; p=quarantine; rua=mailto:admin@fitznet.org |
| TXT | dkim._domainkey |
(generated by docker-mailserver) |
DMARC: start at
p=noneonly long enough to confirm from theruaaggregate reports that all legitimate mail (including the Resend relay) passes SPF/DKIM alignment, then publishp=quarantineas above. Move top=rejectonce quarantine has been clean for a few weeks.
See docs/mail-server.md for the full step-by-step setup guide.
User permissions: users carry a set of permissions that the website uses to show/hide tabs and that the API enforces. Permissions are defined at runtime in MongoDB (permissions collection) — only ADMIN is built in and cannot be deleted. Create them first, then grant them. Manage them from the website /admin page (needs ADMIN) or the API, using either an admin user's JWT or the X-Admin-Key header:
curl -H "X-Admin-Key: $ADMIN_API_KEY" https://<api>/admin/permissions
curl -H "X-Admin-Key: $ADMIN_API_KEY" -H 'Content-Type: application/json' -X POST \
-d '{"name":"RADARR","description":"Radarr tab"}' https://<api>/admin/permissions
curl -H "X-Admin-Key: $ADMIN_API_KEY" -X DELETE https://<api>/admin/permissions/RADARR # also revokes from all users
curl -H "X-Admin-Key: $ADMIN_API_KEY" https://<api>/admin/users
curl -H "X-Admin-Key: $ADMIN_API_KEY" -X POST https://<api>/admin/users/<user>/permissions/RADARR
curl -H "X-Admin-Key: $ADMIN_API_KEY" -X DELETE https://<api>/admin/users/<user>/permissions/RADARR
curl -H "X-Admin-Key: $ADMIN_API_KEY" -H 'Content-Type: application/json' -X PUT \
-d '{"permissions":["RADARR","SONARR"]}' https://<api>/admin/users/<user>/permissionsThere is no seeded admin; grant ADMIN to the first user with the API key.
Each component lives in its own repository. Clone the ones you need:
git clone https://github.com/mattlol85/fitz-net-api.git
git clone https://github.com/mattlol85/fitz-net-website.git
git clone https://github.com/mattlol85/GamerBell.git
git clone https://github.com/mattlol85/Esp32FitznetBell.gitfitz-net-api — requires Java 21 and MongoDB:
cd fitz-net-api
./gradlew bootRunfitz-net-website — requires Node.js:
cd fitz-net-website
npm install
npm run devGamerBell — requires Java 21:
cd GamerBell
./gradlew bootRun --args='--spring.profiles.active=dev'Esp32FitznetBell — requires PlatformIO and an ESP32 board:
cd Esp32FitznetBell
pio run # Compile firmware
pio run --target upload # Flash to a connected ESP32 over USB
pio device monitor # Serial logs (115200 baud)
# First boot: connect to the "FitzNetBell-Setup" WiFi AP to set WiFi + display nameMail stack — run on the Proxmox Docker host:
cd Fitz-Net-Agent-Sandbox/mail
docker compose up -d
# First time: create mailboxes and generate DKIM
docker exec -ti mailserver setup email add matt@fitznet.org
docker exec -ti mailserver setup email add noreply@fitznet.org
docker exec -ti mailserver setup config dkimObservability stack — run on the Docker host:
cd observability
cp .env.example .env # then set GRAFANA_ADMIN_PASSWORD to a strong value
docker compose up -d
# Grafana UI available at https://logs.fitznet.org (login: admin / $GRAFANA_ADMIN_PASSWORD)
# GRAFANA_ADMIN_PASSWORD only applies on first start; on an existing install rotate it with:
# docker exec -it grafana grafana cli admin reset-admin-password '<new password>'See each repo's .github/agents.md for full conventions, build commands, and architecture details.
See docs/mail-server.md for the complete mail server setup guide.
- React frontend + Spring Boot API
- JWT authentication and user management
- Overwatch 2 stats tracker and leaderboard
- LiveBoard — real-time collaborative canvas
- ESP32 physical bell button with WebSocket integration (GamerBell + Esp32FitznetBell)
- OTA firmware updates for ESP32 devices via GitHub Releases
- Self-hosted on Proxmox + Docker behind Caddy reverse proxy
- Observability stack — Grafana, Loki, Prometheus, Promtail, cAdvisor, node-exporter
- Self-hosted email at fitznet.org (docker-mailserver + Roundcube)
- Password reset via email
- Raspberry Pi remote client with hardware buttons
- 3D print enclosure and upload files to GitHub
- Complete a 1.0 release
See the open issues for a full list of proposed features and known issues.
- Fork the relevant repo
- Create a feature branch:
git checkout -b feature/your-feature - Commit using conventional commits:
feat(scope): what you added fix(scope): what you fixed chore(scope): maintenance change - Push and open a Pull Request against
main
This hub ships custom Claude Code agents and skills for the cross-repo orchestration work this repo exists to do. They live in .claude/.
Agents (.claude/agents/):
| Agent | What it does |
|---|---|
repo-sweeper |
Read-only sweep of all six sibling repos — pulls each, lists open issues, returns a ranked table clustered by repo/theme/effort |
pr-triage |
Scores every open PR across the six repos for merge confidence (diff size, CI, contract surfaces touched) and lists what is safe to auto-merge + tag |
cross-repo-feature |
Implements a multi-repo feature per the numbered workflow in .github/agents.md — matching branches, API contract first, backend before frontend, linked PRs |
release-conductor |
The merge → tag → deploy → handoff tail: verifies CI, merges, cuts semver tags, triggers Deploy to Proxmox, writes a prod handoff |
java-spring-agent |
Java 21 / Spring Boot specialist for fitz-net-api, GamerBell, Fitz-Bot |
react-frontend-agent |
React 19 / Vite specialist for fitz-net-website |
esp32-cpp-agent |
C++ / PlatformIO specialist for Esp32FitznetBell |
Skills (.claude/skills/):
| Skill | What it does |
|---|---|
sync-siblings |
Runs the mandatory six-repo git pull and prints a per-repo branch/ahead-behind/dirty summary |
prod-handoff |
Template + checklist for the docs/*-handoff.md runbooks that live on the prod Proxmox VM |
deploy-to-proxmox |
Documents the web-triggered deploy workflow, its tag/latest input, and post-deploy /actuator/health checks |
local-fitznet |
Spin up / tear down the full local stack via docker-compose.yml, with the URLs to check |
arch-visualize |
How the website's 3D architecture graph is built and updated — data model, node/link conventions, live preview |
vulnScan |
Language-agnostic CVE scan (Gradle, npm, PlatformIO): upgrades vulnerable packages, verifies build + tests, leaves changes uncommitted. --report-only to just scan |
Distributed under the MIT License. See LICENSE for more information.
Matt - @mattylol85 - mattlol85@gmail.com
Project Link: https://github.com/mattlol85/Fitz-Net
