Files
portainer-core/plans/completed/dashboard-strategy.md
T

242 lines
6.8 KiB
Markdown

# 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