# Unified Dashboard & External Access Strategy > "One page to rule them all" - Unified interface for tower-of-joy services > Created: 2025-11-11 ## Overview This document defines the strategy for creating a unified web interface that provides access to all tower-of-joy services through a single page with tabbed navigation. ## Solution: Organizr + Nginx Proxy Manager **Organizr** provides the unified tabbed interface **NPM** provides secure external access with SSL ## Architecture ``` Internet ↓ [DNS: home.schweitz.net] ↓ [Router: Port Forward 443 → 192.168.86.149:443] ↓ [Nginx Proxy Manager: 443] ↓ [Organizr: 9999] ←→ [Service Tabs via iframe] ├── Portainer (8001) ├── Uptime Kuma (3001) ├── Netdata (19999) ├── Heimdall (8888) └── More services... ``` ## URL Pattern: Single Domain Approach **Recommended Pattern:** ``` https://home.schweitz.net → Organizr unified interface ``` **All services accessed through Organizr tabs:** - Click "Portainer" tab → loads in iframe - Click "Netdata" tab → loads in iframe - Click "Uptime Kuma" tab → loads in iframe **Why this pattern?** - ✅ True "one page" experience - ✅ Single SSL certificate - ✅ Single URL to remember - ✅ Centralized authentication - ✅ Simple to maintain ## Alternative: Hybrid Subdomain Pattern If some services need direct access (bypassing Organizr): ``` https://home.schweitz.net → Organizr (main interface) https://portainer.home.schweitz.net → Direct Portainer access https://netdata.home.schweitz.net → Direct Netdata access ``` **Requires:** - Wildcard DNS: `*.home.schweitz.net → 192.168.86.149` - Wildcard SSL cert OR individual certs per subdomain ## Service Configuration in Organizr ### Infrastructure Services (Primary Tabs) | Service | Internal URL | Tab Name | Notes | |---------|-------------|----------|-------| | **Portainer** | http://192.168.86.149:8001 | Portainer | Container management | | **Uptime Kuma** | http://192.168.86.149:3001 | Uptime | Service monitoring | | **Netdata** | http://192.168.86.149:19999 | Metrics | System metrics | | **Heimdall** | http://192.168.86.149:8888 | Dashboard | Alternative launcher | ### Optional Services (Additional Tabs) | Service | Internal URL | Tab Name | Expose? | |---------|-------------|----------|---------| | **NPM Admin** | http://192.168.86.149:81 | NPM | Admin only - local access | | **Headscale** | http://192.168.86.149:8085 | VPN | Admin only | | **Ollama** | http://192.168.86.149:11434 | AI | API only, no UI | ### Future Application Services | Service | Internal URL | Tab Name | Notes | |---------|-------------|----------|-------| | **Jellyfin** | http://192.168.86.149:8096 | Media | GPU transcoding | | **Nextcloud** | http://192.168.86.149:8082 | Cloud | File storage | ## Iframe Embedding Challenges ### Known Issues Some services block iframe embedding via `X-Frame-Options` header: - **Netdata**: Can be configured to allow embedding - **Portainer**: May require configuration - **Uptime Kuma**: Generally works fine ### Solutions **Option 1: Configure services to allow embedding** Add to docker-compose environment: ```yaml environment: - X_FRAME_OPTIONS=SAMEORIGIN # Allow same-origin iframes ``` **Option 2: NPM header manipulation** Configure NPM to strip/modify headers for internal access **Option 3: Organizr "direct link" mode** Services that don't work in iframes can open in new tab ## Security Layers ### Level 1: External Access (NPM) - HTTPS with Let's Encrypt SSL - External port 443 only - DDoS protection via Cloudflare (optional) ### Level 2: Application Authentication (Organizr) - User authentication in Organizr - Role-based access control - SSO integration (optional) ### Level 3: Service-Level Authentication - Each service keeps its own auth - Organizr can pass auth tokens (for supported services) ### Level 4: Network Security (Headscale) - VPN access for sensitive admin tools - Public: Jellyfin, Nextcloud - Private (VPN only): Portainer, NPM, Netdata ## Implementation Steps ### Phase 1: Deploy Organizr ```bash make deploy-organizr ``` ### Phase 2: Configure Organizr 1. Access http://192.168.86.149:9999 2. Complete setup wizard 3. Create admin user 4. Add tabs for each service ### Phase 3: Configure NPM for External Access 1. Access NPM admin: http://192.168.86.149:81 2. Add proxy host: - Domain: `home.schweitz.net` - Forward to: `192.168.86.149:9999` - Enable SSL with Let's Encrypt - Force HTTPS redirect ### Phase 4: Configure Router Port Forwarding ``` External Port 443 → Internal 192.168.86.149:443 (NPM HTTPS) External Port 80 → Internal 192.168.86.149:80 (NPM HTTP redirect) ``` ### Phase 5: DNS Configuration Point `home.schweitz.net` to your public IP ### Phase 6: Test & Secure - Test external access: https://home.schweitz.net - Verify SSL certificate - Test all service tabs - Configure Organizr authentication - Review security settings ## Service Tab Recommendations ### Homepage Tab - Quick status dashboard - Links to most-used services - System health indicators ### Essential Tabs (Always Visible) - Portainer (container management) - Uptime Kuma (monitoring) - Netdata (metrics) ### Application Tabs (After deployment) - Jellyfin (media) - Nextcloud (files) ### Admin Tabs (Restricted) - NPM (reverse proxy config) - Headscale (VPN management) ## Maintenance ### Adding New Services 1. Deploy service via Portainer/Docker Compose 2. Add tab in Organizr settings 3. Test iframe embedding 4. Update this documentation ### SSL Certificate Renewal - Automatic via Let's Encrypt (NPM handles this) - Check NPM dashboard for expiry dates ### Security Updates - Watchtower auto-updates containers (Phase 4) - Review Organizr user access monthly ## Troubleshooting ### Service won't load in iframe **Problem:** `X-Frame-Options` header blocking **Solution:** Configure service to allow embedding, or use "open in new tab" mode ### External access not working **Check:** 1. Router port forwarding configured (443 → 192.168.86.149:443) 2. DNS pointing to correct public IP 3. NPM proxy host configured correctly 4. SSL certificate generated successfully ### Authentication issues **Check:** 1. Organizr user permissions 2. Service-specific authentication (each service has own login) 3. Consider implementing SSO for seamless experience ## Future Enhancements ### Potential Upgrades - **Authelia**: Centralized authentication with 2FA - **Cloudflare Tunnel**: Avoid port forwarding entirely - **Custom Theme**: Brand Organizr to match preferences - **API Integration**: Show live stats in Organizr homepage --- **Next Steps:** 1. Deploy Organizr: `make deploy-organizr` 2. Configure tabs for existing services 3. Set up NPM proxy for external access 4. Test the unified interface