1
README
MayaChat edited this page 2025-11-24 14:43:28 -05:00
This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Services Homepage

A lightweight, self-hosted dashboard for quick access to your Docker services with a modern holographic UI design.

License Docker

Features

  • 🎨 Holographic Glass Design - Modern liquid glass buttons with animated shimmer effects
  • 🎯 Dynamic Service Loading - Services configured via simple XML file
  • 🔍 Smart URL Resolution - Automatic handling of ports, protocols, and hostnames
  • 🎭 Icon Integration - Includes Simple Icons pack (3000+ brand logos)
  • 📱 Responsive Layout - Works seamlessly on desktop and mobile
  • 🐳 Docker-Ready - Single-container deployment with nginx
  • Lightweight - Minimal resources, fast loading
  • 🔎 Search & Filter - Instant search with keyboard shortcut (press /)
  • Connection Details - Info button shows hostname/port for each service
  • 🎮 Keyboard Navigation - Arrow keys to navigate, Enter to open, Esc to clear
  • 🟢 Status Indicators - Optional visual status (online/offline/maintenance)
  • 🏥 Automatic Health Checks - Real-time ping tests to detect service availability
  • 📂 Service Groups - Organize services into categorized sections

Quick Start

1. Deploy with Docker Compose

docker-compose up -d

The homepage will be available at http://localhost:8088

2. Configure Your Services

Edit services.xml to add your services organized into groups:

<?xml version="1.0" encoding="UTF-8"?>
<services>
  <group name="Management">
    <service 
      name="Portainer" 
      proto="https" 
      port="9443"
      logo="portainer.svg" 
    />
  </group>
  
  <group name="Media">
    <service 
      name="Jellyfin" 
      proto="http" 
      port="8096" 
      host="jellyfin.example.com"
      logo="jellyfin.svg" 
    />
  </group>
</services>

Or use services without groups (they'll appear in a single grid):

<?xml version="1.0" encoding="UTF-8"?>
<services>
  <service name="Portainer" proto="https" port="9443" logo="portainer.svg" />
  <service name="Jellyfin" proto="http" port="8096" logo="jellyfin.svg" />
</services>

3. Restart to Apply Changes

docker-compose restart

Configuration Guide

Service Attributes

Attribute Required Description Example
name Yes Display name for the service "Nextcloud"
proto No Protocol (http/https) "https" (default: "http")
port No Port number "8080"
host No Custom hostname or full URL "nextcloud.example.com"
logo No Icon filename in /logos/ "nextcloud.svg"
status No Set to "maintenance" to skip health check "maintenance"
check-health No Enable/disable auto health check "true" (default) or "false"

URL Resolution Logic

The service URL is built using this priority:

  1. Full URL - If host starts with http:// or https://, use as-is
  2. Hostname with Port - If host contains :port, use proto://host:port
  3. Hostname Only - If host is set (no port), use https://host (ignores proto and port)
  4. Fallback - Use current page hostname with specified proto and port

Examples

<!-- Full URL (ignores proto and port) -->
<service name="Example" host="https://example.com/app" />

<!-- Public domain (defaults to HTTPS) -->
<service name="Nextcloud" host="cloud.example.com" logo="nextcloud.svg" />

<!-- Custom port on domain -->
<service name="Jellyfin" host="media.example.com:8096" proto="http" logo="jellyfin.svg" />

<!-- Local service (uses page hostname) -->
<service name="Portainer" proto="https" port="9443" logo="portainer.svg" />

<!-- Service with status indicator -->
<service name="Home Assistant" proto="http" port="8123" logo="homeassistant.svg" status="online" />

Keyboard Shortcuts

  • / - Focus the search bar (press from anywhere)
  • Arrow Keys - Navigate between service cards (Up/Down/Left/Right)
  • Enter - Open the selected service in a new tab
  • Esc - Clear the current selection

Info Button

When a service has both a hostname and port configured, a small info button (ⓘ) appears in the bottom-right corner of the card. Click it to view connection details including:

  • Service name
  • Hostname
  • Port number
  • Protocol

Status Indicators

Services are automatically checked for availability when the page loads. Status indicators appear in the top-right corner of each card:

<!-- Automatic health check (default behavior) -->
<service name="Jellyfin" proto="http" port="8096" logo="jellyfin.svg" />

<!-- Manual maintenance mode (skips health check) -->
<service name="Nextcloud" status="maintenance" host="cloud.example.com" logo="nextcloud.svg" />

<!-- Disable health check for a service -->
<service name="Legacy App" check-health="false" proto="http" port="8080" logo="app.svg" />

Status colors:

  • Gray spinning (checking) - Currently testing service availability
  • Green pulsing (online) - Service responded successfully to health check
  • Red (offline) - Service failed to respond or timed out (5 seconds)
  • Orange (maintenance) - Manual maintenance mode, health check skipped

How Health Checks Work

  • Each service is automatically pinged when the page loads
  • Uses a 5-second timeout per service
  • Checks run in parallel for all services
  • Services marked status="maintenance" skip the health check
  • Set check-health="false" to disable checking for specific services
  • No server-side component needed - runs entirely in the browser

Service Groups

Organize your services into categorized sections for better organization:

<services>
  <group name="Management">
    <service name="Portainer" proto="https" port="9443" logo="portainer.svg" />
    <service name="Uptime Kuma" proto="http" port="3001" logo="uptime-kuma.svg" />
  </group>

  <group name="Media">
    <service name="Jellyfin" proto="http" port="8096" logo="jellyfin.svg" />
    <service name="Transmission" proto="http" port="9091" logo="transmission.svg" />
  </group>

  <group name="Storage">
    <service name="Nextcloud" host="cloud.example.com" logo="nextcloud.svg" />
    <service name="FileBrowser" proto="http" port="8986" logo="filebrowser.svg" />
  </group>
</services>

Group Features

  • Categorization: Group related services together (Media, Management, Development, etc.)
  • Visual Separation: Each group has a styled header with an accent underline
  • Smart Search: Searching filters services and hides empty groups automatically
  • Backward Compatible: Services without groups still work (displayed in a single grid)
  • Flexible: Use as many or as few groups as needed

Group Tips

  • Use clear, descriptive group names (e.g., "Media Services" instead of "Group 1")
  • Keep related services together for easier navigation
  • Groups appear in the order defined in the XML
  • Empty groups (no services) are automatically hidden

Icon Management

Using Included Icons

The repository includes Simple Icons (3000+ brand logos). Available icons are in:

logos/simple-icons/icons/

Adding Custom Icons

  1. Add your SVG file to the logos/ directory
  2. Reference it in services.xml:
<service name="MyApp" logo="myapp.svg" />

Icon Styling

All icons are automatically styled white using CSS filters. To customize:

Edit styles.css and modify the .card .logo rule:

.card .logo {
  filter: brightness(0) invert(1);  /* White icons */
  /* OR */
  filter: hue-rotate(180deg);       /* Color shift */
}

Customization

Theme Colors

Edit CSS variables in styles.css:

:root {
  --bg: #0f1720;           /* Background color */
  --card: #0b1220;         /* Card background */
  --accent: #4f46e5;       /* Accent color (purple) */
  --muted: #94a3b8;        /* Muted text */
}

Holographic Effects

The holographic button effects include:

  • Shimmer Animation - Continuous light sweep (8s loop, 3s on hover)
  • Gradient Background - Purple/pink gradient blend
  • Glowing Border - Animated gradient border on hover
  • Backdrop Blur - Glass-like frosted effect

To adjust shimmer speed, modify the @keyframes shimmer animation:

.card::before {
  animation: shimmer 8s infinite linear;  /* Change 8s to adjust speed */
}

Layout

Change grid responsiveness in styles.css:

.grid {
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  /* Adjust minmax() to change card width */
}

File Structure

services-homepage/
├── docker-compose.yml      # Docker deployment config
├── Dockerfile             # Custom nginx build (if needed)
├── index.html             # Main HTML page
├── styles.css             # Holographic UI styles
├── services.xml           # Service definitions
├── README.md              # This file
├── LICENSE                # License information
└── logos/                 # Icon directory
    ├── simple-icons/      # Simple Icons pack (3000+ logos)
    ├── default.svg        # Fallback icon
    ├── gitea.svg
    ├── jellyfin.svg
    ├── nextcloud.svg
    └── ...

Updating Icons

Replace All Icons with Simple Icons

cd logos
for f in *.svg; do
  basename=$(basename "$f" .svg)
  match=$(find simple-icons/icons -type f -iname "*${basename}*.svg" -print -quit)
  [ -n "$match" ] && cp "$match" "$f" && echo "Updated: $f"
done

Find Available Icons

ls logos/simple-icons/icons/ | grep -i "keyword"

Backup and Recovery

Icon backups are automatically created in:

logos/backup-YYYYMMDD-HHMMSS/

To restore from backup:

cp logos/backup-20251123-231406/*.svg logos/
docker-compose restart

Troubleshooting

Cloudflare, HTTPS and Mixed Content

If you're serving the homepage over HTTPS (for example, via Cloudflare), your browser will block active (programmatic) HTTP requests to local IPs — this is "mixed content". That can cause the health checks for local services to fail or to be marked offline.

Recommendations:

  • Enable HTTPS for your local services (e.g., configure TLS or use a reverse proxy with a valid certificate) and/or use Cloudflare Tunnel to serve the service with a domain and TLS.
  • Or configure a server-side proxy that performs health checks and serves the results over HTTPS (for example, add a proxy endpoint in your nginx config and proxy_pass to the local IP/port); the browser will then make a same-origin secure request to the proxy rather than directly to the IP.
  • In services.xml, use the tailscale-ip attribute to supply an easily-editable Tailscale IP for local services that should be used for links and health checks.
  • In services.xml, use the tailscale-ip attribute to supply an easily-editable Tailscale IP for local services that should be used for links and health checks.

Per-service local-ip override:

  • If a specific service has a local-ip attribute (for example, local-ip="192.168.2.180"), the server-side health proxy will use that local IP for the health check. This allows per-service control when the internal IP differs from the household-wide Tailscale IP or when services are bound to different hosts.

Cloudflare Insights & CORS:

  • If you see console errors about static.cloudflareinsights.com or messages like "CORS request did not succeed" or "integrity mismatch", this is likely a script injected by Cloudflare. This is not part of the homepage codebase and is injected by Cloudflare's edge. You can disable Cloudflare Analytics/Insights or adjust settings in the Cloudflare dashboard to remove or avoid that script if it's causing issues with CSP or integrity.

Services Not Loading

  1. Check services.xml syntax:
xmllint --noout services.xml
  1. Check browser console for errors (F12)

  2. Verify file permissions:

chmod 644 services.xml index.html styles.css
chmod 755 logos/

Icons Not Displaying

  1. Verify icon exists:
ls -lh logos/youricon.svg
  1. Check icon reference in services.xml matches filename exactly

  2. Clear browser cache (Ctrl+Shift+R)

Container Issues

# View logs
docker logs services-homepage

# Restart container
docker-compose restart

# Rebuild if files changed
docker-compose up -d --force-recreate

Performance

  • Image Size: ~45MB (nginx:alpine base)
  • Memory Usage: ~5-10MB
  • Load Time: <100ms (local network)
  • Icons: Cached by browser after first load

Browser Support

  • Chrome/Edge 90+
  • Firefox 88+
  • Safari 14+
  • Mobile browsers (iOS Safari, Chrome Android)

Security

  • All volumes mounted read-only (:ro)
  • No external dependencies at runtime
  • Logs automatically rotated (5MB max, 2 files)
  • CORS not enabled (same-origin only)

Advanced Usage

Custom Nginx Config

Create nginx.conf and mount it:

volumes:
  - ./nginx.conf:/etc/nginx/nginx.conf:ro

Adding Authentication

Use a reverse proxy (Nginx Proxy Manager, Caddy, Traefik) with basic auth:

location / {
  auth_basic "Services";
  auth_basic_user_file /etc/nginx/.htpasswd;
  proxy_pass http://services-homepage:80;
}

Dynamic Port Updates

For services with dynamic ports (e.g., Transmission behind VPN), use environment variables:

<service name="Transmission" proto="http" port="${TRANS_PORT}" logo="transmission.svg" />

Then update via script or use a template processor.

Contributing

Contributions welcome! Completed features:

  • Search/filter functionality with keyboard shortcut
  • Keyboard navigation (arrow keys, Enter, Esc)
  • Service status indicators (online/offline/maintenance)
  • Automatic health checks with ping tests
  • Info button showing connection details
  • Service groups/categories

Areas for future improvement:

  • Service health checks via custom endpoints
  • Drag-and-drop reordering within groups
  • Collapsible group sections
  • Custom themes/color schemes
  • Export/import service configurations
  • Dashboard widgets (time, weather, etc.)

License

MIT License - See LICENSE file for details

Credits

  • Icons: Simple Icons (CC0 1.0 Universal)
  • Design Inspiration: Holographic UI by vishnu137 on CodePen
  • Web Server: nginx Alpine

Support

For issues, questions, or suggestions:

  1. Check this README first
  2. Review browser console for errors
  3. Check Docker logs: docker logs services-homepage
  4. Verify services.xml syntax

Version: 1.0.0
Last Updated: November 23, 2025