9.7 KiB
9.7 KiB
CoopCredits Infrastructure Documentation
Network Architecture
┌─────────────────────────────────────────────────────────────────────────┐
│ External Access │
│ coop.hobokenchicken.com │
└─────────────────────────────────┬───────────────────────────────────────┘
│ HTTPS (443)
▼
┌─────────────────────────────────────────────────────────────────────────┐
│ CoopCredits Server (172.20.1.238) │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Caddy │ │ Frontend │ │ Backend │ │ PostgreSQL │ │
│ │ (reverse) │──│ (Next.js) │ │ (Express) │──│ (5432) │ │
│ │ Proxy │ │ :3000 │ │ :3002 │ │ │ │
│ └──────────────┘ └──────────────┘ └──────┬───────┘ └──────────────┘ │
│ │ │
│ ┌──────────────┐ │ ┌──────────────┐ │
│ │ Redis │◀────────┘ │ (Ko-fi) │ │
│ │ (6379) │ │ (Webhooks) │ │
│ └──────────────┘ └──────────────┘ │
└──────────────────────────────────┬──────────────────────────────────────┘
│
│ Local Network (172.20.1.0/24)
┌──────────────────────────┼──────────────────────────┐
│ │ │
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Plex │ │ Tautulli │ │ Overseer │
│172.20.1.220 │ │172.20.1.255 │ │172.20.1.225 │
│ :32400 │ │ :8181 │ │ :5055 │
└──────────────┘ └──────────────┘ └──────────────┘
Important: Backend runs in
network_mode: hostto reach Tautulli/Overseer on172.20.1.0/24. Docker bridge networking cannot route to this subnet.
Service Details
Caddy Reverse Proxy (Separate Machine)
- Handles: SSL termination (Let's Encrypt), routing
- Routes:
/*→ Frontend:3000/api/*→ Backend:3002(preserves/api/prefix — usehandle, nothandle_path)/webhooks/*→ Backend:3002
Frontend (coop-frontend, port 3000)
- Next.js 16 with standalone output
- Bridge network — exposed on
0.0.0.0:3000 - Static files served from
.next/standalone
Backend (coop-backend, port 3002)
- Express.js API
- Host network mode — required to reach
172.20.1.xservices - Connects to: PostgreSQL on
localhost:5432, Redis onlocalhost:6379 - Health check:
GET /healthonlocalhost:3002
PostgreSQL (coop-postgres, port 5432)
- User:
coop - Database:
coop_credits - Password:
coop_password(change in production) - Health check:
pg_isready
Redis (coop-redis, port 6379)
- Used for: Session store, Socket.io adapter
- No auth in current config (trusted local network)
Plex Server (172.20.1.220:32400)
- Purpose: Content streaming and user authentication
- Integration: OAuth 2.0 login for website
Tautulli (172.20.1.255:8181)
- Purpose: Plex analytics and watch event tracking
- Integration: Webhook notifications to CoopCredits on watch events
- API Key: Required for backfill queries
Overseer (172.20.1.225:5055)
- Purpose: Content request management
- Integration: API for creating requests, webhooks for status updates
- API Key: Required for search and request creation
- Disk Space: Used for dynamic pricing scarcity calculation
Communication Flow
1. User Authentication
User → Caddy → Frontend → Backend → Plex OAuth (172.20.1.220:32400)
↓
User authenticated, JWT issued
Session stored in PostgreSQL
2. Watch Event Processing
Plex → Tautulli → Webhook → Caddy → Backend → PostgreSQL
↓
WatchEvent + Transaction created
Socket.io → User notified
3. Content Request
User → Caddy → Frontend → Backend → Overseer API (172.20.1.225:5055)
↓
Request created, $COOP deducted immediately
ContentRequest stored as PENDING
↓
Overseer webhook → Backend → Status updated
4. Ko-fi Purchase
User → Ko-fi Store → Payment → Ko-fi Webhook → Caddy → Backend
↓
KofiPayment record created
If email matches user →
Transaction (PURCHASE) + credits added
Socket.io → User notified
Security Considerations
Network Security
- Backend host mode — Required for local network access, but exposes host network
- Caddy handles SSL — Only HTTPS externally
- Internal services — PostgreSQL/Redis not exposed externally (except through Docker ports)
API Security
- Tautulli Webhook — Optional secret verification (
TAUTULLI_WEBHOOK_SECRET) - Overseer Webhook — No secret currently configured
- Plex OAuth — Standard OAuth 2.0 flow
- JWT — Secure tokens with nonce for session deduplication
- Rate Limiting — 1000 requests per 15 minutes per IP
Data Security
- No wallet keys — Solana removed, no private keys stored
- Database — Localhost only, password protected
- Redis — Localhost only
- Ko-fi verification — Token check on webhook endpoint
Firewall Configuration
# Web traffic (Caddy handles SSL)
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# Internal service access (from Docker containers)
sudo ufw allow from 172.20.0.0/16 to 172.20.1.0/24
# Block external access to internal services
sudo ufw deny 3000/tcp # Frontend (should be localhost only)
sudo ufw deny 3002/tcp # Backend (should be localhost only)
sudo ufw deny 5432/tcp # PostgreSQL
sudo ufw deny 6379/tcp # Redis
Docker Network Configuration
Bridge Network (coop-network)
- Frontend container uses this
- Isolated from external network
- Connects: frontend ↔ Caddy proxy
Host Network (backend only)
- Backend container uses
network_mode: host - Shares host's network stack
- Required to reach
172.20.1.xservices (Tautulli, Overseer) - Connects directly to PostgreSQL/Redis on
localhost
Monitoring and Logging
Log Locations
- Backend:
docker logs coop-backend - Frontend:
docker logs coop-frontend - Database: Inside container (
/var/log/postgresql/)
Health Checks
# Backend health
curl http://localhost:3002/health
# Database connection
docker exec coop-postgres pg_isready -U coop
# Service status
docker ps
Backup and Recovery
Database Backup
# Automated backup
docker exec -T coop-postgres pg_dump -U coop coop_credits > backup_$(date +%Y%m%d).sql
Configuration Backup
.envfile (contains all secrets)docker-compose.ymlservice config- Caddy config (on separate machine)
Troubleshooting
Cannot reach local services
- Check backend is in host network mode:
docker inspect coop-backend | grep NetworkMode - Verify IP connectivity from host:
ping 172.20.1.255 - Check backend logs:
docker logs --tail 50 coop-backend
Webhook not received
- Verify Caddy routes
/webhooks/*to backend - Check backend logs for webhook handler output
- Test manually:
curl -X POST https://coop.hobokenchicken.com/webhooks/tautulli -d '{"test":true}'
CORS errors
- Verify
FRONTEND_URLandAPI_URLin.env - Check backend CORS origins include your domain
- Caddy should pass through headers without modification