Files
portainer-core/docs/unified-dashboard-strategy.md
T

6.8 KiB

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:

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

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