242 lines
6.8 KiB
Markdown
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
|