# Services Homepage A lightweight, self-hosted dashboard for quick access to your Docker services with a modern holographic UI design. ![License](https://img.shields.io/badge/license-MIT-blue.svg) ![Docker](https://img.shields.io/badge/docker-required-blue.svg) ## 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 ```bash 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 ``` Or use services without groups (they'll appear in a single grid): ```xml ``` ### 3. Restart to Apply Changes ```bash 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 ```xml ``` ## 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: ```xml ``` 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: ```xml ``` ### 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`: ```xml ``` ### Icon Styling All icons are automatically styled white using CSS filters. To customize: Edit `styles.css` and modify the `.card .logo` rule: ```css .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`: ```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: ```css .card::before { animation: shimmer 8s infinite linear; /* Change 8s to adjust speed */ } ``` ### Layout Change grid responsiveness in `styles.css`: ```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 ```bash 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 ```bash 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: ```bash 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: ```bash xmllint --noout services.xml ``` 2. Check browser console for errors (F12) 3. Verify file permissions: ```bash chmod 644 services.xml index.html styles.css chmod 755 logos/ ``` ### Icons Not Displaying 1. Verify icon exists: ```bash ls -lh logos/youricon.svg ``` 2. Check icon reference in `services.xml` matches filename exactly 3. Clear browser cache (Ctrl+Shift+R) ### Container Issues ```bash # 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: ```yaml volumes: - ./nginx.conf:/etc/nginx/nginx.conf:ro ``` ### Adding Authentication Use a reverse proxy (Nginx Proxy Manager, Caddy, Traefik) with basic auth: ```nginx 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: ```xml ``` 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](https://simpleicons.org/) (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