- CLAUDE.md: Server instructions and service reference - docs/: Persistent documentation (architecture, guides) - .artifacts/: Session-generated notes - playwriter-browser/: Remote browser container config Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
280 lines
17 KiB
Markdown
280 lines
17 KiB
Markdown
# NUC Infrastructure Architecture
|
|
|
|
**Date:** 2026-02-01
|
|
**Context:** Secure self-hosted infrastructure with Tailscale Funnel for public access and Tailscale mesh for private admin access. Designed to bypass Spanish ISP blocks and handle dynamic IPs.
|
|
|
|
---
|
|
|
|
## Architecture Diagram
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────────────────┐
|
|
│ INTERNET │
|
|
└─────────────────────────────────────────────────────────────────────────────┘
|
|
│ │
|
|
│ Public Traffic │ Admin Traffic
|
|
▼ ▼
|
|
┌───────────────────────────────┐ ┌─────────────────────────────────────┐
|
|
│ whyrating.com │ │ TAILSCALE MESH │
|
|
│ │ │ │ (encrypted, private) │
|
|
│ ▼ │ │ │
|
|
│ ┌─────────────────────┐ │ │ ┌───────────┐ ┌───────────┐ │
|
|
│ │ Namecheap DNS │ │ │ │ Your Mac │◄──►│ NUC │ │
|
|
│ │ (301 redirect) │ │ │ │100.x.x.2 │ │100.x.x.1 │ │
|
|
│ └──────────┬──────────┘ │ │ └───────────┘ └───────────┘ │
|
|
│ │ │ │ ▲ ▲ │
|
|
│ ▼ │ │ │ Anywhere │ │
|
|
│ ┌─────────────────────┐ │ │ │ in world │ │
|
|
│ │ Tailscale Funnel │ │ └─────────┴────────────────┴─────────┘
|
|
│ │ nuc-tailscale.ts.net│◄─────┼────────────────────────┘
|
|
│ └──────────┬──────────┘ │
|
|
│ │ HTTPS/443 │
|
|
└─────────────┼─────────────────┘
|
|
│
|
|
▼
|
|
┌─────────────────────────────────────────────────────────────────────────────┐
|
|
│ NUC SERVER │
|
|
│ 192.168.1.3 │
|
|
├─────────────────────────────────────────────────────────────────────────────┤
|
|
│ │
|
|
│ ┌─────────────────────────────────────────────────────────────────────┐ │
|
|
│ │ SECURITY LAYER │ │
|
|
│ │ ┌─────────────┐ │ │
|
|
│ │ │ CrowdSec │ ← Blocks malicious IPs, DDoS protection │ │
|
|
│ │ │ :8083 │ │ │
|
|
│ │ └─────────────┘ │ │
|
|
│ └─────────────────────────────────────────────────────────────────────┘ │
|
|
│ │ │
|
|
│ ▼ │
|
|
│ ┌─────────────────────────────────────────────────────────────────────┐ │
|
|
│ │ COOLIFY (Docker Orchestrator) │ │
|
|
│ │ │ │
|
|
│ │ ┌─────────────────────────────────────────────────────────────┐ │ │
|
|
│ │ │ TRAEFIK (Reverse Proxy) │ │ │
|
|
│ │ │ Routes by domain │ │ │
|
|
│ │ └───────────┬─────────────────┬─────────────────┬─────────────┘ │ │
|
|
│ │ │ │ │ │ │
|
|
│ │ ▼ ▼ ▼ │ │
|
|
│ │ ┌─────────────────────────────────────────────────────────────┐ │ │
|
|
│ │ │ PUBLIC WEBSITES │ │ │
|
|
│ │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │
|
|
│ │ │ │Homepage │ │ App A │ │ App B │ │ App C │ │ │ │
|
|
│ │ │ │ :3000 │ │ :3001 │ │ :3002 │ │ :3003 │ │ │ │
|
|
│ │ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │ │
|
|
│ │ │ (internal ports only, not exposed) │ │ │
|
|
│ │ └─────────────────────────────────────────────────────────────┘ │ │
|
|
│ │ │ │
|
|
│ │ ┌─────────────────────────────────────────────────────────────┐ │ │
|
|
│ │ │ PRIVATE SERVICES (Tailscale only) │ │ │
|
|
│ │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │
|
|
│ │ │ │Coolify │ │ Gitea │ │ MinIO │ │Postgres │ │ │ │
|
|
│ │ │ │ :8000 │ │ :3030 │ │ :9001 │ │ :5432 │ │ │ │
|
|
│ │ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │ │
|
|
│ │ │ │ │ │
|
|
│ │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ │ │
|
|
│ │ │ │Authentik│ │ n8n │ │Vaultwrdn│ │ Outline │ │ │ │
|
|
│ │ │ │ :9090 │ │ :5678 │ │ :8222 │ │ :3080 │ │ │ │
|
|
│ │ │ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ │ │
|
|
│ │ └─────────────────────────────────────────────────────────────┘ │ │
|
|
│ └─────────────────────────────────────────────────────────────────────┘ │
|
|
│ │
|
|
└─────────────────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## Traffic Flows
|
|
|
|
### Public Website Access
|
|
```
|
|
User → whyrating.com → Namecheap 301 → nuc-tailscale.ts.net → Tailscale Funnel
|
|
→ CrowdSec → Traefik → Container (internal port)
|
|
```
|
|
|
|
### Admin Access (Remote)
|
|
```
|
|
Your Mac → Tailscale mesh (encrypted) → NUC Tailscale IP (100.x.x.x)
|
|
→ Direct access to any port (8000, 22, etc.)
|
|
```
|
|
|
|
### Admin Access (Home Network)
|
|
```
|
|
Your Mac → Local network → 192.168.1.3 → Any port
|
|
```
|
|
|
|
---
|
|
|
|
## Component Summary
|
|
|
|
| Component | Port | Access | Purpose |
|
|
|-----------|------|--------|---------|
|
|
| **Tailscale Funnel** | 443 | Public | Single internet entry point |
|
|
| **CrowdSec** | 8083 | Private | DDoS/attack protection |
|
|
| **Traefik** | 80/443 | Internal | Routes domains to containers |
|
|
| **Homepage** | 3000 | Via Funnel | Public dashboard |
|
|
| **Coolify** | 8000 | Tailscale only | Container management |
|
|
| **Databases** | various | Tailscale only | Data storage |
|
|
|
|
---
|
|
|
|
## Security Layers
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────┐
|
|
│ Layer 1: TAILSCALE FUNNEL │
|
|
│ • Only entry point from internet │
|
|
│ • HTTPS termination │
|
|
│ • No open ports on router │
|
|
├─────────────────────────────────────────────────────────┤
|
|
│ Layer 2: CROWDSEC │
|
|
│ • Crowdsourced threat intelligence │
|
|
│ • Blocks known malicious IPs │
|
|
│ • DDoS mitigation │
|
|
├─────────────────────────────────────────────────────────┤
|
|
│ Layer 3: TRAEFIK │
|
|
│ • Domain-based routing │
|
|
│ • Only forwards to valid services │
|
|
│ • Rate limiting (configurable) │
|
|
├─────────────────────────────────────────────────────────┤
|
|
│ Layer 4: DOCKER NETWORK ISOLATION │
|
|
│ • Containers can't access each other unless configured │
|
|
│ • Databases on separate network from public apps │
|
|
├─────────────────────────────────────────────────────────┤
|
|
│ Layer 5: TAILSCALE MESH (Admin) │
|
|
│ • All admin traffic encrypted │
|
|
│ • No admin ports exposed to internet │
|
|
│ • Device authentication required │
|
|
└─────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## Dynamic IP Handling
|
|
|
|
```
|
|
ISP Changes IP
|
|
│
|
|
▼
|
|
┌─────────────┐ auto-update ┌──────────────────────┐
|
|
│ NUC detects │ ────────────────► │ Tailscale Coord │
|
|
│ new IP │ │ Server │
|
|
└─────────────┘ └──────────┬───────────┘
|
|
│
|
|
┌──────────────────────────────────────┘
|
|
│ broadcasts new location
|
|
▼
|
|
┌─────────────────────────────────────────────────────────┐
|
|
│ UNCHANGED │
|
|
│ • Tailscale IP: 100.x.x.x (stable) │
|
|
│ • Funnel URL: nuc-tailscale.tail58f5ad.ts.net (stable)│
|
|
│ • whyrating.com redirect (stable) │
|
|
│ • All tunnels auto-reconnect (~10-30 sec) │
|
|
└─────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
**Key Point:** Your ISP can change your public IP anytime - Tailscale handles this automatically. No DDNS needed.
|
|
|
|
---
|
|
|
|
## Access Reference
|
|
|
|
| From | To | Method |
|
|
|------|----|--------|
|
|
| **Public users** | Websites | `whyrating.com` or `.ts.net` URL |
|
|
| **You (remote)** | NUC admin | `ssh nuc-tailscale` or `http://100.x.x.x:8000` |
|
|
| **You (home)** | NUC admin | `ssh nuc` or `http://192.168.1.3:8000` |
|
|
| **You (remote)** | Router | SSH jump: `ssh -J nuc-tailscale root@192.168.1.1` |
|
|
|
|
---
|
|
|
|
## URLs
|
|
|
|
| Service | Public URL | Private URL (Tailscale) |
|
|
|---------|------------|-------------------------|
|
|
| Main site | `whyrating.com` | - |
|
|
| Direct Funnel | `nuc-tailscale.tail58f5ad.ts.net` | - |
|
|
| Coolify | - | `http://nuc-tailscale:8000` |
|
|
| Homepage | Via Funnel :3000 | `http://nuc-tailscale:3000` |
|
|
| Gitea | - | `http://nuc-tailscale:3030` |
|
|
|
|
---
|
|
|
|
## What's NOT Exposed to Internet
|
|
|
|
- SSH (22)
|
|
- Coolify (8000)
|
|
- Databases (5432, 3306)
|
|
- MinIO (9000/9001)
|
|
- Authentik (9090)
|
|
- Router admin (192.168.1.1)
|
|
- Any direct ports on router
|
|
|
|
---
|
|
|
|
## Coolify Deployment Best Practices
|
|
|
|
### For Public Apps:
|
|
```yaml
|
|
services:
|
|
myapp:
|
|
image: myapp:latest
|
|
# NO ports: section - Traefik routes internally
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.http.routers.myapp.rule=Host(`myapp.whyrating.com`)"
|
|
networks:
|
|
- coolify
|
|
```
|
|
|
|
### For Private Apps:
|
|
```yaml
|
|
services:
|
|
mydb:
|
|
image: postgres:16
|
|
# No traefik labels
|
|
# No exposed ports
|
|
networks:
|
|
- internal # Separate from coolify network
|
|
```
|
|
|
|
---
|
|
|
|
## Quick Commands
|
|
|
|
```bash
|
|
# Check Tailscale status
|
|
tailscale status
|
|
|
|
# Check Funnel status
|
|
ssh nuc "tailscale funnel status"
|
|
|
|
# Access Coolify remotely
|
|
open http://nuc-tailscale:8000
|
|
|
|
# SSH to NUC from anywhere
|
|
ssh nuc-tailscale
|
|
|
|
# Check CrowdSec decisions
|
|
ssh nuc "docker exec crowdsec-* cscli decisions list"
|
|
```
|
|
|
|
---
|
|
|
|
## Related Documents
|
|
|
|
- `.artifacts/2026-02-01_19-11_domain-pre-purchase-check-guide.md` - Domain checking before purchase
|
|
- `.artifacts/domain-check.sh` - Script to check domains for blocks
|
|
- `CLAUDE.md` - Full NUC server documentation
|
|
|
|
---
|
|
|
|
## Why This Architecture?
|
|
|
|
1. **Spanish ISP Blocks** - Cloudflare shared IPs are blocked during LaLiga matches. Tailscale Funnel uses different infrastructure.
|
|
|
|
2. **Dynamic IP** - No need for DDNS or port forwarding. Tailscale handles IP changes automatically.
|
|
|
|
3. **Security** - Zero ports exposed on router. All admin via encrypted Tailscale mesh.
|
|
|
|
4. **Simplicity** - Single entry point (Funnel), single orchestrator (Coolify), single security layer (CrowdSec).
|