WHAT WAS DONE: Created comprehensive implementation plan for dynamic Servers page using Cloudflare Workers + Pterodactyl Client API. Includes complete Gemini AI consultation archive with architectural recommendations. NEW DOCUMENTATION: 1. docs/planning/dynamic-servers-page-implementation.md (737 lines) - Executive summary and architecture overview - 12-day implementation timeline (April 3-15, 2026) - Phase-by-phase task breakdown - Security considerations and RV travel requirements - Caching strategy and performance metrics - Success criteria and monitoring setup 2. docs/planning/gemini-servers-consultation/ - 01-initial-consultation.md (original prompt to Gemini) - 02-followup-questions.md (7 technical clarification questions) - 03-gemini-initial-response.md (Cloudflare Workers architecture) - 04-gemini-followup-response.md (implementation Q&A) KEY ARCHITECTURAL DECISIONS: - ✅ Cloudflare Workers (serverless, zero maintenance, RV-ready) - ✅ Pterodactyl Client API (not Application API!) - ✅ Service Account pattern (read-only permissions) - ✅ Edge caching (60 seconds, protects Pterodactyl from traffic spikes) - ✅ Pipe-delimited naming: 'Modpack Name | vX.Y.Z' IMPLEMENTATION PHASES: Phase 1 (Apr 3-4): Pterodactyl Service Account setup Phase 2 (Apr 4-6): Local Worker development with Wrangler Phase 3 (Apr 7-9): Deploy Worker to production Phase 4 (Apr 9-11): Frontend integration + testing Phase 5 (Apr 11-12): Uptime Kuma monitoring setup Phase 6 (Apr 14): DNS cutover to firefrostgaming.com EASY WINS TO ADD: - Copy Server IP button (clipboard.writeText) - Auto-refresh every 60 seconds (setInterval) - Pulse animation for online status (CSS provided) SKIP (TOO COMPLEX): - Historical uptime tracking (requires database) - Live console output (security risk + WebSocket complexity) GEMINI VALIDATION: 'Your timeline is highly realistic. Get that Service Account created today, mock up the .dev.vars this weekend, and you'll be coasting into April 15.' Butter No Nutters (CEO) has granted royal approval on architecture. 😺👑 This is the final blocker before soft launch. Once implemented, Servers page will auto-update when infrastructure changes - zero manual edits required. Fire + Frost + Foundation = Where Love Builds Legacy 💙 Signed-off-by: Claude (Chronicler #56) <claude@firefrostgaming.com>
18 KiB
Dynamic Servers Page Implementation Plan
Created: April 3, 2026
Status: Ready for Implementation
Target Launch: April 15, 2026 (12 days)
Architecture: Cloudflare Workers + Pterodactyl Client API
Executive Summary
The Problem: The Servers page is currently static HTML. Every time we add/remove/modify a Minecraft server, we must manually edit website code and redeploy. This is unsustainable for a hosting company.
The Solution: Cloudflare Workers acting as a serverless proxy between the website and Pterodactyl Panel. The Worker fetches live server status from Pterodactyl's Client API, caches at the edge for 60 seconds, and serves JSON to the frontend. Zero manual updates required.
Why This Architecture:
- ✅ Serverless: No VPS to maintain (critical for RV travel!)
- ✅ Secure: API keys hidden in Worker environment variables
- ✅ Fast: Edge caching protects Pterodactyl from traffic spikes
- ✅ Free: Cloudflare Workers free tier covers our needs
- ✅ RV-Ready: Fully decoupled, graceful degradation if panel goes down
Architecture Overview
User Browser
↓
firefrostgaming.com/servers (11ty static page)
↓ (JavaScript fetch)
Cloudflare Worker (https://servers-api.YOUR-WORKER.workers.dev)
↓ (Server-side API call, API key hidden)
Pterodactyl Client API (/api/client/servers)
↓ (Returns server list + live status)
Worker (caches for 60 seconds at edge)
↓
JSON response → Browser renders
Key Insight from Gemini: If 1,000 users hit the site simultaneously, the FIRST user triggers the Worker → Pterodactyl API call (400ms). The remaining 999 users get cached data from Cloudflare's edge in ~10ms. Pterodactyl only gets hit once per minute regardless of traffic!
Critical Pterodactyl API Distinction
Two APIs, Two Purposes
Application API (Admin) - ptla_ prefix:
- Used for administrative tasks
- Lists ALL servers regardless of owner
- Cannot provide real-time player counts or live stats
- Good for: Trinity Panel monitoring, server creation/deletion
Client API (User-Facing) - ptlc_ prefix:
- Used for end-user access
- Only shows servers the user has access to
- Provides
/resourcesendpoint with live stats - Good for: Website status display, player counts
We need the Client API for the website!
Implementation Plan (12 Days)
Phase 1: Pterodactyl Setup (April 3-4)
Task 1.1: Check Existing API Key Type
# Look at Trinity Panel API key
# If it starts with ptla_ = Application API (wrong for this!)
# If it starts with ptlc_ = Client API (perfect!)
Task 1.2: Create Service Account
- Log into Pterodactyl Admin panel (https://panel.firefrostgaming.com)
- Go to Users → Create new user:
- Username:
website-api - Email:
website-api@firefrostgaming.com - Password: (generate secure password)
- Username:
- For EACH Minecraft server we want public:
- Go to Servers in Admin panel
- Click the server
- Go to Subusers tab
- Add
website-api@firefrostgaming.com - Grant ONLY these permissions:
- ✅ View Server
- ✅ View Server Statistics
- ❌ Everything else (no control permissions!)
- Log out of Admin account
- Log in as
website-api@firefrostgaming.com - Go to Account Settings → API Credentials
- Create new Client API key
- SAVE THIS KEY! It starts with
ptlc_
Task 1.3: Standardize Server Descriptions Update ALL Minecraft server descriptions in Pterodactyl to follow this format:
All The Mods 10 | v1.0.9
Stoneblock 3 | v1.2.4
Project Architect 2 | v2.0.1
Society | v1.1.0
Mythcraft | v2.3.1
All The Mons | v1.0.5
Format: Modpack Name | v[Version]
Why pipe-delimited:
- Clean, readable in Pterodactyl UI
- Easy JavaScript parsing:
const [name, version] = desc.split(' | '); - No special characters that break JSON
Phase 2: Local Development (April 4-6)
Task 2.1: Install Wrangler CLI
npm install -g wrangler
Task 2.2: Create Worker Project
mkdir cloudflare-workers
cd cloudflare-workers
mkdir servers-api
cd servers-api
wrangler init
Task 2.3: Create .dev.vars (Local Secrets)
Create file: .dev.vars in worker directory:
PANEL_URL="https://panel.firefrostgaming.com"
CLIENT_API_KEY="ptlc_YOUR_ACTUAL_KEY_HERE"
IMPORTANT: Add .dev.vars to .gitignore - NEVER commit secrets!
Task 2.4: Write Worker Code
See cloudflare-worker-code.js in this directory for complete code.
Key features:
- Fetches from Pterodactyl Client API
/api/clientendpoint - Gets live server list
- For each server, fetches
/resourcesendpoint for status - Returns JSON with server name, status, players, description
- Handles CORS for firefrostgaming.com
- Edge caching: 60 seconds
- Graceful error handling if panel is down
Task 2.5: Test Locally
wrangler dev
# Worker runs at http://localhost:8787
# Open browser, test endpoint
# Verify JSON structure matches expectations
Test cases:
- ✅ All servers listed
- ✅ Online/Offline status correct
- ✅ Player counts (if available)
- ✅ Modpack names parsed correctly
- ✅ CORS headers present
- ✅ Error handling works (simulate panel down)
Phase 3: Deploy to Production (April 7-9)
Task 3.1: Deploy Worker
wrangler deploy
Output will be: https://servers-api.YOUR-WORKER.workers.dev
Task 3.2: Configure Production Secrets
wrangler secret put PANEL_URL
# Enter: https://panel.firefrostgaming.com
wrangler secret put CLIENT_API_KEY
# Paste the ptlc_ key
Task 3.3: Test Production Worker
curl https://servers-api.YOUR-WORKER.workers.dev
# Should return JSON with all servers
Task 3.4: Update Cloudflare Worker Settings
- Go to Cloudflare Dashboard → Workers
- Click
servers-api - Settings → Triggers → Add custom domain (optional):
api.firefrostgaming.com - Verify CORS settings
Phase 4: Frontend Integration (April 9-11)
Task 4.1: Update servers.njk
See servers-page-frontend.html in this directory for complete code.
Key features:
- Static HTML container
- JavaScript fetches from Worker on page load
- Renders server cards dynamically
- "Pulse" animation for online status (Frost cyan)
- Offline status in Fire orange
- Player count display (if available)
- Error handling with friendly message
- Auto-refresh every 60 seconds
Task 4.2: Add Easy Wins
- Copy IP Button:
<button onclick="navigator.clipboard.writeText('atm10.firefrostgaming.com')">
Copy Server IP
</button>
- Auto-Refresh:
setInterval(() => {
fetch(WORKER_URL).then(/* update UI */);
}, 60000); // Every 60 seconds
Task 4.3: Test on Preview
- Commit changes to git
- Push to Gitea (auto-deploys to GitHub → Cloudflare Pages)
- Wait 60-90 seconds
- Test
https://firefrost-website.pages.dev/servers - Verify on multiple devices:
- Desktop (Firefox, Chrome)
- Mobile (Michael's phone, Meg's phone)
- Tablet
Test checklist:
- ✅ All servers display
- ✅ Status indicators correct (green pulse = online, red = offline)
- ✅ Player counts showing (if Pterodactyl provides them)
- ✅ Copy IP buttons work
- ✅ Auto-refresh updates without page reload
- ✅ Mobile responsive (no horizontal scroll!)
- ✅ Error message displays if Worker fails
- ✅ Loading state shows during fetch
Phase 5: Monitoring Setup (April 11-12)
Task 5.1: Uptime Kuma Monitoring
- Log into Uptime Kuma (Command Center)
- Add new monitor:
- Name: "Servers API Worker"
- Type: HTTP(s)
- URL:
https://servers-api.YOUR-WORKER.workers.dev - Interval: 120 seconds (2 minutes)
- Retries: 3
- Set up Discord notification:
- Webhook URL: (Trinity Discord channel)
- Alert on: Down, Error, Recovery
Task 5.2: Worker Error Webhook (Optional) Add Discord webhook to Worker error handler:
catch (error) {
// Alert Discord that Worker failed
fetch('https://discord.com/api/webhooks/YOUR_WEBHOOK', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
content: '🚨 Servers API Worker failed to reach Pterodactyl Panel!'
})
});
// Return graceful error to users
return new Response(JSON.stringify({
error: "Servers temporarily unreachable",
servers: []
}), { status: 500 });
}
Task 5.3: Cloudflare Analytics
- Go to Cloudflare Dashboard → Workers → servers-api
- View Analytics tab
- Monitor:
- Request count
- Error rate
- CPU time usage
- P95 response time
Target metrics:
- Error rate: <1%
- Response time: <500ms
- CPU time: <5ms (network time doesn't count)
Phase 6: DNS Cutover (April 14)
CRITICAL: Do NOT attempt DNS cutover until Servers page tested thoroughly on preview!
Pre-Flight Checklist:
- ✅ Cloudflare Worker deployed and tested
- ✅ servers.njk updated and tested on preview
- ✅ All 7 pages working on firefrost-website.pages.dev
- ✅ Mobile responsive verified
- ✅ Uptime Kuma monitoring active
- ✅ Discord alerts tested
- ✅ Michael + Meg + Holly have reviewed site
- ✅ Paymenter subscription links verified
- ✅ /discord redirect working
DNS Cutover Steps:
- Log into Cloudflare Dashboard
- Go to Workers & Pages → firefrost-website
- Settings → Domains → Add custom domain
- Enter:
firefrostgaming.com - Cloudflare provisions SSL certificate (1-5 minutes)
- Wait for edge network propagation (5-15 minutes)
- Test: Visit
https://firefrostgaming.com - Verify all pages load correctly
- Check Servers page specifically
Expected "routing weirdness" (Gemini's warning):
- First 5-15 minutes: Some users may see old Ghost site, some see new 11ty site
- After 15 minutes: All users see new site
- This is normal edge network propagation
Rollback Plan (if needed):
- Remove custom domain from Cloudflare Pages
- Old Ghost site becomes active again
- Debug issue
- Try cutover again when ready
Player Count Nuance (Important!)
From Gemini:
The Client API does return a
playersinteger underattributes.resources.players. However, Pterodactyl's Wings daemon gets this number by passively querying the Minecraft server. For heavily modded servers (like ATM10), the server query port sometimes hangs or reports 0 even when players are online.
Strategy:
- MVP (Launch): Show player counts IF Pterodactyl provides them
- Monitor: Watch for false zeros (server shows "0 players" but you know people are online)
- If unreliable: Remove player count display post-launch
- DO NOT: Try to build custom RCON/Query proxy 12 days before launch
Keep it simple: Online/Offline status is the MVP. Player counts are a nice-to-have.
Server Naming Convention (Enforced Standard)
Format: Modpack Name | v[Version]
Examples:
All The Mods 10 | v1.0.9
Stoneblock 3 | v1.2.4
Project Architect 2 | v2.0.1
Society | v1.1.0
Mythcraft | v2.3.1
All The Mons | v1.0.5
JavaScript parsing:
const description = "All The Mods 10 | v1.0.9";
const [modpackName, version] = description.split(' | ');
// modpackName = "All The Mods 10"
// version = "v1.0.9"
Where to store: Pterodactyl Server Description field (visible in Client API)
Maintenance: When adding new servers, Michael MUST follow this format for automatic website updates!
Caching Strategy
Cache-Control Header:
'Cache-Control': 'public, s-maxage=60, max-age=60'
What this means:
public: Anyone can cache thiss-maxage=60: Cloudflare Edge caches for 60 secondsmax-age=60: User's browser caches for 60 seconds
Traffic pattern example:
Time 00:00 - User A visits → Worker executes → Pterodactyl queried → Result cached
Time 00:15 - User B visits → Cloudflare Edge returns cached data (no Worker execution!)
Time 00:30 - User C visits → Cloudflare Edge returns cached data (no Worker execution!)
Time 00:45 - User D visits → Cloudflare Edge returns cached data (no Worker execution!)
Time 01:01 - User E visits → Cache expired → Worker executes → Pterodactyl queried → New cache
Result: Pterodactyl only gets hit ONCE per minute, regardless of website traffic!
Why 60 seconds is acceptable: Minecraft server status doesn't change rapidly. If a server goes down, users will see the old "Online" status for up to 60 seconds max. This is totally fine for this use case.
Future Enhancements (Post-Launch)
✅ Easy Wins (Add These!)
- Copy IP Button - One line of JavaScript
- Auto-Refresh -
setIntervalevery 60 seconds - Status Pulse Animation - CSS keyframe already provided
⚠️ Possible But Complex
- Modpack logos - Would need image hosting, careful sizing
- Server tags - Requires Pterodactyl custom fields
- "Last seen online" - Requires tracking state changes
❌ Architectural Nightmares (Skip!)
- Historical uptime tracking - Needs database (kills static site)
- Live console output - Security risk + WebSocket complexity
- Custom RCON integration - Over-engineering for MVP
Philosophy: Ship the MVP. Add features iteratively after launch based on actual user feedback.
Security Considerations
API Key Protection
- ✅ Client API key stored in Cloudflare Worker environment variables
- ✅ Never exposed to browser
- ✅
.dev.varsfile in.gitignore - ✅ Service Account has minimal permissions (read-only)
CORS Configuration
- ✅ Only allows
https://firefrostgaming.comorigin - ✅ Rejects requests from other domains
- ✅ Handles OPTIONS preflight requests
Rate Limiting
- ✅ Edge caching prevents API abuse
- ✅ Pterodactyl only hit once per minute max
- ✅ No user can DOS the panel through the website
Error Disclosure
- ✅ Generic error messages to users ("Servers temporarily unreachable")
- ❌ Never expose API endpoints or keys in error messages
- ✅ Detailed errors logged to Cloudflare Analytics only
RV Travel Considerations
Why this architecture works for remote operation:
- Zero VPS dependencies: Worker is serverless, no SSH needed
- Automatic recovery: If panel goes down temporarily, Worker error handling keeps site usable
- Push notifications: Discord webhooks alert Michael/Meg immediately
- Edge monitoring: Uptime Kuma on Command Center watches Worker health
- Simple troubleshooting: Only 3 moving parts (Worker, Pterodactyl, Frontend)
Troubleshooting from the road:
- Panel down? Uptime Kuma + Discord alert
- Worker failing? Cloudflare Dashboard shows errors
- Website broken? Cloudflare Pages deployment logs
- All accessible via phone/tablet over cellular!
Timeline & Milestones
April 3 (Today):
- ✅ Check existing API key type
- ✅ Create Service Account in Pterodactyl
- ✅ Standardize server descriptions
April 4-6 (Weekend):
- ✅ Install Wrangler CLI
- ✅ Build Worker locally
- ✅ Test with real Pterodactyl API
April 7-9:
- ✅ Deploy Worker to production
- ✅ Configure secrets
- ✅ Test Worker endpoint
April 9-11:
- ✅ Update servers.njk frontend
- ✅ Add Copy IP + Auto-refresh features
- ✅ Test on preview extensively
April 11-12:
- ✅ Set up Uptime Kuma monitoring
- ✅ Configure Discord alerts
- ✅ Final QA testing
April 14:
- ✅ Pre-flight checklist verification
- ✅ DNS cutover to firefrostgaming.com
- 🎉 SOFT LAUNCH!
April 15:
- Buffer day for unexpected issues
- Monitor analytics closely
- Celebrate! 🔥⚡❄️
Success Metrics (Post-Launch)
Week 1 (April 15-21):
- Worker uptime: >99%
- Page load time: <2 seconds
- Error rate: <1%
- Zero manual server list updates needed
Month 1 (April-May):
- Player count accuracy verified
- Auto-refresh working smoothly
- Mobile traffic analytics reviewed
- User feedback collected (Discord)
Long-term:
- Add/remove servers without touching website code
- Update modpack versions by changing Pterodactyl description only
- Infrastructure "just works" from anywhere in the USA
Contacts & Resources
Gemini AI Consultation:
- Session 1: Initial architecture recommendation (Cloudflare Workers)
- Session 2: Implementation details and Q&A
- Both consultations saved in
docs/planning/gemini-servers-consultation/
Cloudflare Resources:
- Workers Dashboard: https://dash.cloudflare.com/workers
- Wrangler Docs: https://developers.cloudflare.com/workers/wrangler/
- Workers Examples: https://workers.cloudflare.com/examples
Pterodactyl Resources:
- API Documentation: https://dashflo.net/docs/api/pterodactyl/v1/
- Client API Endpoints: /api/client, /api/client/servers/{id}/resources
- Panel URL: https://panel.firefrostgaming.com
Team:
- Michael "Frostystyle" - Technical implementation
- Claude (Chronicler #56) - Documentation and pair programming
- Gemini AI - Architectural guidance and code review
- Butter No Nutters - CEO approval (royal seal granted! 😺👑)
Conclusion
This implementation transforms the Servers page from a static, manually-maintained list into a living, self-updating system that reflects reality automatically. When we add a new Minecraft server, we:
- Create it in Pterodactyl
- Add Service Account as subuser
- Set description to
Modpack Name | vX.Y.Z - DONE! Website updates automatically within 60 seconds.
Zero code changes. Zero deployments. Zero manual updates.
That's the vision: Build it once, run it forever.
Fire + Frost + Foundation = Where Love Builds Legacy 💙
Document Status: Complete and ready for implementation
Last Updated: April 3, 2026
Next Review: April 15, 2026 (post-launch retrospective)