Server Management
Unified server management hub with config-driven detail pages, provider-aware inventory, and a persisted infrastructure job queue for safe background actions
Server Management
The server management module (v3.1.0) is the unified hub for all infrastructure servers. The index page is a premium glass morphism dashboard with search/filter, network-colored cards, toast notifications, copy-IP-on-click, loading skeletons, import/export JSON, and a persisted background job queue for safety-gated operations. Detail pages are config-driven via D1 database fields — a single dynamic [slug].astro page renders server-specific content based on server_type, with live Proxmox API integration for hypervisors.
Pages
| Route | Content |
|---|---|
/admin/servers | Glass morphism card grid, import/export, stats bar |
/admin/servers/Meridian-Host | Full Unraid admin (6 tabs, dedicated page) |
/admin/servers/[slug] | Dynamic detail page — renders based on server_type from D1 |
Architecture
Config-Driven Detail Pages
In v2.x, each server had a hardcoded .astro file (Tarn-Host.astro, Izar-Host.astro, etc.) with static VM listings and service data baked into source code. In v3.0.0, a single [slug].astro catch-all replaces all 5 static pages with a dynamic page driven by three D1 fields:
| Field | Purpose | Example |
|---|---|---|
slug | URL-friendly identifier for routing | Tarn-Host, sentinel |
server_type | Determines which template to render | proxmox, vps, gateway |
proxy_endpoint | API proxy path for live data (nullable) | /api/Tarn-Host-adminbox/servers/Tarn-Host |
Astro’s file-based routing gives named files priority over [slug], so Meridian-Host.astro still serves the Meridian-Host page — it’s too specialized (6 tabs, Docker management, rTorrent controls, SSH keys) to merge into the generic template.
Server Types
| Type | Rendering | Live Data | Example Servers |
|---|---|---|---|
proxmox | Node status, tabbed VMs/CTs/Storage, actions | Yes (15s refresh) | Tarn-Host, Izar-Host |
unraid | Falls through to Meridian-Host dedicated page | N/A | Meridian-Host |
vps | Service grid from D1 | No | Sentinel VPS |
vm | Service grid from D1 | No | Workbench |
gateway | Services grouped by category | No | Altair-Link |
generic | Basic service grid + notes | No | Any new server |
Open Source Friendly
All server data lives in D1, not in source code. Open source users see an empty server list and can import their own infrastructure via JSON. The private/servers-seed.json file is gitignored — only the owner’s instance has pre-populated data.
Infrastructure Control Queue (Phase 1)
Server operations that can be destructive now flow through a persisted queue table (infra_jobs) instead of immediate direct mutation from the browser.
Why Queue It
- Enables background processing and clear audit history for infra actions
- Adds a safety delay before execution (10 seconds)
- Supports explicit status tracking (
queued,running,succeeded,failed,cancelled) - Decouples UI click events from execution timing
Current Queued Action
delete_server— remove a server record from D1 after typed confirmation (DELETE <server-name>)
Queue APIs
| Route | Method | Purpose |
|---|---|---|
/api/admin/infra/inventory | GET | Unified inventory across server records with provider/type/network summaries |
/api/admin/infra/jobs | GET | List recent infra jobs and opportunistically process due queued jobs |
/api/admin/infra/jobs | POST | Queue or manage jobs (delete_server, process_queue, cancel_job) |
Index Page (/admin/servers)
Premium glass morphism server cards with 3px gradient top accent. Each card shows server icon with hover glow, name, network badge, service count, clickable IP addresses (monospace, copy-on-click), OS, and notes.
Card Design
- Glass morphism:
rgba(15,23,42,0.65)background, thin border, 14px radius - 3px gradient top accent bar (network color → transparent) via
::beforepseudo-element - Network colors: Milky Way=#06b6d4 (cyan), Andromeda=#8b5cf6 (purple), External=#f97316 (orange), Cloud=#f59e0b (amber)
- Hover: translateY(-3px) + multi-layer network-colored box-shadow + icon glow
- Click any IP address to copy to clipboard (toast confirmation)
- Smooth service collapse/expand via
max-heightCSS transition - Collapsible services section with mini-grid of service chips (icon + name + port)
Search & Filter
- Real-time search across server names, IPs, OS, service names, and ports
- Network filter pills: All, Milky Way, Andromeda, External, Cloud
- “No results” state when search/filter returns empty
Toast Notifications
Slide-in notifications replace all alert() calls. Four types: info (cyan), success (green), error (red), warning (amber). Uses bouncy cubic-bezier(0.34, 1.56, 0.64, 1) entrance animation.
Loading Skeleton
Shimmer-animated skeleton cards display while the API response loads, preventing layout shift.
CSS Architecture
Uses <style is:global> because all cards are dynamically created via JavaScript innerHTML — Astro’s default scoped styles don’t apply to dynamic elements. All class names prefixed with srv- to prevent collisions with CosmicLayout globals.
Action Pills
| Button | Color | Action |
|---|---|---|
| Web UI (cyan) | #06b6d4 | Opens web_ui_url in new tab (Proxmox, Unraid, etc.) |
| Terminal (purple) | #8b5cf6 | Opens terminal — new tab for CF tunnel URLs, iframe for direct IPs |
| Details (green) | #10b981 | Navigate to /admin/servers/<slug> detail page |
| Edit (amber) | #f59e0b | Open edit modal |
| Delete (red) | #ef4444 | Queue typed-confirm deletion (DELETE <name>) with safety delay |
Stats Bar
Five stat chips: Total Servers, Milky Way count, Andromeda count, External count, Total Services.
Import / Export
- Import: Paste JSON array or upload
.jsonfile → validates structure → POSTs each server to API → progress bar - Export: Downloads all servers as
Arcturus-Prime-servers-YYYY-MM-DD.json(strips id, timestamps) - User-specific seed data belongs in
private/servers-seed.json(gitignored)
Detail Page Links
Servers with a slug field in D1 get a green “Details” pill button. No hardcoded slug list — the index page reads the slug field directly from the API response.
Add/Edit Modal
The modal form includes all server fields:
| Field | Type | Notes |
|---|---|---|
| Name | Text (required) | Display name |
| IP Address | Text | Primary IP |
| Tailscale IP | Text | VPN IP |
| OS | Text | Operating system |
| Network | Select | Milky Way, Andromeda, External, Cloud |
| Icon | Text | Font Awesome class (e.g., fa-solid fa-server) |
| Color | Color picker + hex | Accent color |
| Terminal URL | Text | URL for terminal access |
| Web UI URL | Text | Direct web UI link |
| Slug | Text | URL identifier for detail page |
| Server Type | Select | proxmox, unraid, vps, vm, gateway, generic |
| Proxy Endpoint | Text | API proxy path for live data |
| Notes | Textarea | Free-text notes |
| Services | Dynamic list | Name, port, type, icon, color, URLs, auth, category |
Dynamic Detail Page (/admin/servers/[slug])
Shared Elements (All Server Types)
Every detail page includes:
- Back link to
/admin/servers - Server header: icon (with color tint), name, network badge, OS badge
- Copy-on-click IPs: Primary IP and Tailscale IP as monospace badges
- Connection indicator (servers with
proxy_endpoint): green pulsing “Connected”, amber “Connecting”, red “Offline” - Web UI button: Opens
web_ui_urlin new tab (shown if set) - Terminal button: Opens
terminal_url— new tab for CF tunnel URLs (*.Arcturus-Prime.com), direct for IP-based URLs - Notes: Italic subtitle from D1 notes field
- Toast notifications: Same system as index page
Proxmox Type
For servers with server_type: "proxmox" and a proxy_endpoint, the page fetches live data from the Tarn-Host-adminbox API via the Arcturus-Prime proxy.
Node Status Cards
Four stat cards in a responsive grid:
| Card | Data | Visual |
|---|---|---|
| CPU | Percentage + core count | Cyan progress bar |
| RAM | Used / Total (formatted) | Purple progress bar |
| Uptime | Days + hours or hours + minutes | Text only |
| Load | 1m / 5m / 15m averages | Text only |
Tabbed Content
Three tabs: VMs, Containers, Storage.
VMs/Containers tabs show entity cards with:
- VMID badge (e.g., “VM 101”, “CT 203”)
- Name
- Status badge (running=green, stopped=red, paused=amber)
- CPU and RAM mini-bars with percentages
- Uptime (running VMs/CTs only)
- Action buttons: Start (green), Stop (red), Restart (amber)
- Running entities have green left border accent; stopped entities are dimmed
Storage tab shows storage pool cards with:
- Pool name (monospace) and type badge
- Utilization bar (green < 75%, amber < 90%, red > 90%)
- Used/Total/Free breakdown
- Critical warning banner when > 90% used
Auto-Refresh
- Data refreshes every 15 seconds via
setInterval - Interval cleared on
astro:before-preparation(View Transitions cleanup) - After VM/CT actions (start/stop/restart), data refreshes after 3-second delay
Graceful Degradation
When the Tarn-Host-adminbox API is unavailable:
- Connection indicator turns red (“Offline”)
- Troubleshooting banner appears with:
- Health check command:
curl http://10.42.0.199:8095/api/health - Tunnel check:
cloudflared tunnel info - Env var check:
TITAN_ADMINBOX_TOKEN
- Health check command:
- Falls back to showing static services from D1 data
API Endpoints Used
| Endpoint | Returns |
|---|---|
GET {proxy_endpoint} | Node status: cpu, maxcpu, mem, maxmem, uptime, load |
GET {proxy_endpoint}/vms | VM list: vmid, name, status, cpu, mem, maxmem, uptime |
GET {proxy_endpoint}/containers | Container list: same fields as VMs |
GET {proxy_endpoint}/storage | Storage pools: storage, type, total, used, avail |
POST {proxy_endpoint}/{vms|containers}/{vmid}/{action} | Power action: start, stop, shutdown, reboot |
All memory/storage values in bytes. CPU usage 0-1 scale. Uptime in seconds.
Gateway Type
For server_type: "gateway" servers, services from D1 are grouped by category field with section headers:
| Category | Icon | Color |
|---|---|---|
| Monitoring | heart-pulse | #22c55e |
| Dev Tools | screwdriver-wrench | #06b6d4 |
| Admin | gauge-high | #8b5cf6 |
| Storage | folder-open | #f59e0b |
| Communication | comments | #f472b6 |
| Networking | globe | #3b82f6 |
Each category section shows a title with icon, service count badge, and a grid of service cards.
VPS / VM / Generic Types
These types render a flat service grid from D1 services JSON. Each service card shows:
- Icon (from service
iconfield or default cube) - Name
- Port chip (monospace)
- Type chip
- Auth indicator (lock icon + method)
- Dev URL link (blue)
- Prod URL link (green)
CSS Architecture
Uses <style is:global> with sd- prefix (server-detail). Glass morphism cards matching the index page aesthetic. Responsive breakpoints at 768px and 480px.
Meridian-Host (/admin/servers/Meridian-Host)
Full Unraid admin page with 7 tabs. This is a dedicated page (not using the dynamic [slug] system) due to its specialized functionality. All API calls go through the /api/mm-Arcturus-Prime/* proxy which injects the Bearer token server-side.
Tabs
| Tab | Content |
|---|---|
| Overview | Array status, disk temps, cache/parity info, alerts |
| Downloads | rTorrent active/completed/stopped torrents, add/remove/start/stop controls |
| Containers | Docker container list, start/stop/restart, status indicators |
| VMs | Virtual machine list, start/stop, state display |
| Storage | SMART data, share listing, disk utilization bars |
| SSH | Key management, authorized_keys display |
| Logs | Syslog and container log viewer (added v3.2.0) |
Logs Tab (v3.2.0)
Live log viewer for host syslog and per-container logs. All data fetched via /api/mm-Arcturus-Prime/logs/* endpoints.
Controls toolbar:
- Source selector — “System Log (syslog)” plus all managed containers (populated dynamically from
/api/mm-Arcturus-Prime/logs/containers) - Filter input — text filter with 400ms debounce, sanitized server-side (alphanumeric + spaces + dashes only)
- Line count — 100, 200 (default), 500, or 1000
- Auto-refresh checkbox — 5-second interval when enabled
- Refresh button — manual fetch
Log output:
- Monospace
<pre>block, dark background (#0a0a14), max-height 70vh with vertical scroll - Color-coded lines: errors (red), warnings (amber), normal (gray/white)
- Auto-scrolls to bottom on new data
- Container list is loaded lazily on first Logs tab click
Backend endpoints used:
| Endpoint | Purpose |
|---|---|
GET /api/mm-Arcturus-Prime/logs/syslog?lines=N&filter=text | Host syslog via nsenter, max 1000 lines |
GET /api/mm-Arcturus-Prime/logs/containers | List managed container names for source dropdown |
GET /api/mm-Arcturus-Prime/logs/container/<name>?lines=N | Container logs via Docker socket API |
Container logs use the Docker multiplexed stream format (8-byte header per frame) parsed server-side. The Docker CLI is not available inside the Alpine container — logs are fetched via the Docker Unix socket API directly.
Technical Details
- Extracts CF JWT from
Cf-Access-Jwt-Assertionheader in frontmatter - Passes JWT to client via
define:vars={{ cfJwt }} - Auto-refreshes data every 15 seconds (cleanup on
astro:before-preparation) - Log auto-refresh timer also cleaned up on
astro:before-preparation - All DOM operations use null-safe
?.checks - Toast notification system for user feedback
- Connection status indicator in header
Terminal Behavior
Terminal buttons detect the URL type and choose the appropriate method:
| URL Pattern | Behavior | Reason |
|---|---|---|
*.Arcturus-Prime.com | Opens in new tab | CF Access sets X-Frame-Options: DENY, blocking iframes |
Direct IP (e.g., http://10.42.0.x:7681) | Iframe overlay (dev mode) | No CF Access restrictions |
API
Server CRUD
/api/admin/servers — requires admin authentication.
| Method | Action | Parameters |
|---|---|---|
GET | List all servers | — |
GET | Get single by ID | ?id=xxx |
GET | Get single by slug | ?slug=xxx |
POST | Create server | Server JSON body |
PUT | Update server | Server JSON body with id |
DELETE | Delete server | ?id=xxx |
Infrastructure Queue & Inventory
/api/admin/infra/inventory and /api/admin/infra/jobs — requires admin authentication.
/api/admin/infra/jobs actions:
delete_server— queue a safe deleteprocess_queue— force a queue processing passcancel_job— cancel queued (not running) jobs
Proxy Routes
| Route | Target | Auth |
|---|---|---|
/api/mm-Arcturus-Prime/[...path] | Meridian-Host container (192.168.20.50:8888) | MM_ARGOBOX_TOKEN |
/api/Tarn-Host-adminbox/[...path] | Tarn-Host-adminbox (10.42.0.199:8095) | TITAN_ADMINBOX_TOKEN |
Both proxies inject Bearer tokens server-side. Dev mode uses direct IPs; prod uses CF tunnel URLs.
Database Schema
Table servers — migrations: 0003_servers_table.sql, 0007_add_web_ui_url.sql, 0015_server_detail_fields.sql
| Column | Type | Description |
|---|---|---|
| id | TEXT PK | UUID |
| name | TEXT | Server display name |
| ip | TEXT | Primary IP address |
| tailscale_ip | TEXT | Tailscale VPN IP (nullable) |
| os | TEXT | Operating system |
| network | TEXT | Network name (Milky Way/Andromeda/External/Cloud) |
| icon | TEXT | Font Awesome icon class |
| color | TEXT | Accent color hex |
| terminal_url | TEXT | URL for terminal access (nullable) |
| web_ui_url | TEXT | Direct web UI link (nullable) |
| slug | TEXT UNIQUE | URL identifier for detail page routing (nullable) |
| server_type | TEXT | Detail page template: proxmox, unraid, vps, vm, gateway, generic |
| proxy_endpoint | TEXT | API proxy path for live data (nullable) |
| notes | TEXT | Free-text notes (nullable) |
| services | TEXT | JSON array of service objects |
Service Object Schema
Each entry in the services JSON array:
{
"name": "Gitea",
"port": 3000,
"type": "Git Hosting",
"icon": "fa-brands fa-git-alt",
"color": "#609926",
"devUrl": "http://10.42.0.199:3000",
"prodUrl": "https://gitea.Arcturus-Prime.com",
"auth": "OAuth",
"category": "dev-tools"
}
Required Environment Variables
| Variable | Purpose |
|---|---|
ADMIN_DB | D1 database binding |
MM_ARGOBOX_URL | Meridian-Host container base URL |
MM_ARGOBOX_TOKEN | Bearer token for MM proxy auth |
TITAN_ADMINBOX_URL | Tarn-Host-adminbox base URL |
TITAN_ADMINBOX_TOKEN | Bearer token for Tarn-Host-adminbox proxy auth |
Version History
| Version | Date | Changes |
|---|---|---|
| 1.0.0 | 2026-02-21 | Initial server CRUD with card grid |
| 2.0.0 | 2026-02-28 | Glass morphism overhaul, import/export, 6 static detail pages |
| 3.0.0 | 2026-02-28 | Dynamic [slug].astro replaces 5 static pages, live Proxmox API, D1-driven config |
| 3.1.0 | 2026-02-28 | Infrastructure control queue, typed-confirm delete, glass morphism polish |
| 3.2.0 | 2026-03-01 | Logs tab on Meridian-Host page — syslog + per-container log viewer with auto-refresh |