security rework and memory optimilizations.

This commit is contained in:
2025-11-17 08:48:00 +01:00
parent 72a653f494
commit e8eb2e954c
55 changed files with 8301 additions and 245 deletions
+194
View File
@@ -0,0 +1,194 @@
version: '3.8'
# Authentik - Identity Provider for SSO (Using Shared Infrastructure)
# Phase 1: Foundation - Google OAuth Integration
# Ports: 9000 (HTTP), 9443 (HTTPS)
# GPU: No
# Dependencies: postgres-shared, redis-shared
services:
authentik-server:
image: ghcr.io/goauthentik/server:latest
container_name: authentik-server
restart: unless-stopped
command: server
ports:
- "9000:9000"
# Port 9443 removed - use NPM for HTTPS termination
environment:
# Database configuration (shared PostgreSQL)
AUTHENTIK_POSTGRESQL__HOST: postgres-shared
AUTHENTIK_POSTGRESQL__PORT: 5432
AUTHENTIK_POSTGRESQL__NAME: authentik
AUTHENTIK_POSTGRESQL__USER: authentik_user
AUTHENTIK_POSTGRESQL__PASSWORD: ${AUTHENTIK_DB_PASSWORD:?database password required}
# Cache configuration (shared Redis, database 1)
AUTHENTIK_REDIS__HOST: redis-shared
AUTHENTIK_REDIS__PORT: 6379
AUTHENTIK_REDIS__DB: 1
# Authentik secret key
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY:?secret key required}
# Error reporting (disabled)
AUTHENTIK_ERROR_REPORTING__ENABLED: "false"
# Performance tuning for home use
WORKERS: 2
# Email configuration (optional - configure later if needed)
# AUTHENTIK_EMAIL__HOST: smtp.gmail.com
# AUTHENTIK_EMAIL__PORT: 587
# AUTHENTIK_EMAIL__USERNAME: your-email@gmail.com
# AUTHENTIK_EMAIL__PASSWORD: your-app-password
# AUTHENTIK_EMAIL__USE_TLS: "true"
# AUTHENTIK_EMAIL__FROM: authentik@schweitz.net
# Timezone
TZ: Europe/Amsterdam
volumes:
- /home/jpmschweitzer/docker-data/authentik/media:/media
- /home/jpmschweitzer/docker-data/authentik/custom-templates:/templates
networks:
- docker-dataplane
depends_on:
- postgres-shared
- redis-shared
deploy:
resources:
limits:
memory: 256M
authentik-worker:
image: ghcr.io/goauthentik/server:latest
container_name: authentik-worker
restart: unless-stopped
command: worker
environment:
# Database configuration (shared PostgreSQL)
AUTHENTIK_POSTGRESQL__HOST: postgres-shared
AUTHENTIK_POSTGRESQL__PORT: 5432
AUTHENTIK_POSTGRESQL__NAME: authentik
AUTHENTIK_POSTGRESQL__USER: authentik_user
AUTHENTIK_POSTGRESQL__PASSWORD: ${AUTHENTIK_DB_PASSWORD}
# Cache configuration (shared Redis, database 1)
AUTHENTIK_REDIS__HOST: redis-shared
AUTHENTIK_REDIS__PORT: 6379
AUTHENTIK_REDIS__DB: 1
# Authentik secret key
AUTHENTIK_SECRET_KEY: ${AUTHENTIK_SECRET_KEY}
# Error reporting (disabled)
AUTHENTIK_ERROR_REPORTING__ENABLED: "false"
# Timezone
TZ: Europe/Amsterdam
user: root
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /home/jpmschweitzer/docker-data/authentik/media:/media
- /home/jpmschweitzer/docker-data/authentik/certs:/certs
- /home/jpmschweitzer/docker-data/authentik/custom-templates:/templates
networks:
- docker-dataplane
depends_on:
- postgres-shared
- redis-shared
deploy:
resources:
limits:
memory: 192M
authentik-proxy-outpost:
image: ghcr.io/goauthentik/proxy:latest
container_name: authentik-proxy-outpost
restart: unless-stopped
network_mode: host
environment:
# Authentik connection
AUTHENTIK_HOST: http://192.168.86.149:9000
AUTHENTIK_INSECURE: "false"
AUTHENTIK_TOKEN: ${AUTHENTIK_OUTPOST_TOKEN:?outpost token required}
# Logging
AUTHENTIK_LOG_LEVEL: info
# Port configuration
AUTHENTIK_LISTEN__HTTP: 0.0.0.0:9001
AUTHENTIK_LISTEN__METRICS: 0.0.0.0:9300
depends_on:
- authentik-server
labels:
- "com.centurylinklabs.watchtower.enable=true"
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "http://localhost:9001/outpost.goauthentik.io/ping"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
networks:
docker-dataplane:
external: true
name: docker-dataplane
# Prerequisites:
#
# 1. Deploy shared-infrastructure stack first!
# docker-compose -f shared-infrastructure.yml up -d
#
# 2. Verify shared services are running:
# docker ps | grep -E 'postgres-shared|redis-shared'
#
# 3. Create Authentik data directories (if not exists):
# mkdir -p ~/docker-data/authentik/{media,certs,custom-templates}
#
# 4. Create .env file with:
# AUTHENTIK_DB_PASSWORD=<from shared-infrastructure .env>
# AUTHENTIK_SECRET_KEY=<generate with: openssl rand -base64 60>
#
# 5. Deploy this stack:
# docker-compose -f authentik-shared.yml --env-file .env.authentik-shared up -d
#
# After Deployment:
#
# 1. Wait for containers to start (may take 30-60 seconds for DB migrations)
#
# 2. Check logs:
# docker logs authentik-server
# docker logs authentik-worker
#
# 3. Access initial setup: http://localhost:9000/if/flow/initial-setup/
# - Create admin account (akadmin recommended)
# - Set strong password
#
# 4. Configure NPM reverse proxy:
# - Domain: auth.schweitz.net
# - Forward to: authentik-server:9000
# - SSL: Let's Encrypt
# - Websockets: Enabled
#
# 5. Access admin interface: https://auth.schweitz.net/if/admin/
#
# Connection Details:
#
# Database:
# - Host: postgres-shared (from containers) / localhost (from host)
# - Port: 5432
# - Database: authentik
# - User: authentik_user
#
# Cache:
# - Host: redis-shared (from containers) / localhost (from host)
# - Port: 6379
# - Database: 1
#
# Resource Usage (optimized for home use):
# - Server: 256MB RAM limit (WORKERS=2 reduces Gunicorn processes)
# - Worker: 192MB RAM limit
# - Proxy Outpost: ~32MB RAM
# - Total Authentik: ~480MB max (vs ~700MB with dedicated PostgreSQL/Redis)
# - Savings: ~400MB by using shared infrastructure!
+19 -6
View File
@@ -3,7 +3,7 @@ version: '3.8'
# Core API - OpenAPI-compatible functions and AI orchestration for Open WebUI
# Purpose: Provides OpenAI-compatible API (/v1/chat/completions) and tool functions (web scraping)
# Port: 8083 (HTTP API)
# Network: ai-dataplane (shared with Open WebUI, Ollama, Qdrant)
# Network: docker-dataplane (shared infrastructure network)
#
# Setup: Create venv before first deployment:
# cd /home/jpmschweitzer/Projects/portainer-core/services/core-api
@@ -17,7 +17,7 @@ services:
container_name: core-api
restart: unless-stopped
# Hot-reload development mode
# Production mode with workers
command: >
sh -c "
if [ ! -f /venv/bin/activate ]; then
@@ -29,8 +29,7 @@ services:
/venv/bin/uvicorn src.main:app
--host 0.0.0.0
--port 8083
--reload
--reload-dir /app/src
--workers 2
"
ports:
@@ -72,6 +71,11 @@ services:
- WEB_SCRAPER_DEFAULT_MAX_LENGTH=10000
- WEB_SCRAPER_MAX_LINKS_TO_EXTRACT=50
# Uptime Kuma Configuration
- KUMA_URL=http://uptime-kuma:3001
- KUMA_USERNAME=${KUMA_USERNAME}
- KUMA_PASSWORD=${KUMA_PASSWORD}
# Python path
- PYTHONPATH=/app
@@ -86,7 +90,15 @@ services:
- /home/jpmschweitzer/docker-data/core-api/logs:/app/logs
networks:
- ai-dataplane
- docker-dataplane
deploy:
resources:
limits:
cpus: '2.0'
memory: 2G
reservations:
memory: 512M
labels:
- "com.centurylinklabs.watchtower.enable=true"
@@ -99,5 +111,6 @@ services:
start_period: 30s
networks:
ai-dataplane:
docker-dataplane:
external: true
name: docker-dataplane
+5 -4
View File
@@ -20,7 +20,7 @@ services:
- POSTGRES_DB=gitea
- TZ=Europe/Amsterdam
networks:
- gitea-network
- docker-dataplane
gitea:
image: gitea/gitea:latest
@@ -46,11 +46,12 @@ services:
depends_on:
- gitea-db
networks:
- gitea-network
- docker-dataplane
networks:
gitea-network:
driver: bridge
docker-dataplane:
external: true
name: docker-dataplane
# ⚠️ SECURITY WARNING:
# Change POSTGRES_PASSWORD and GITEA__database__PASSWD before deploying!
+4 -3
View File
@@ -21,11 +21,12 @@ services:
environment:
- TZ=Europe/Amsterdam
networks:
- headscale-network
- docker-dataplane
networks:
headscale-network:
driver: bridge
docker-dataplane:
external: true
name: docker-dataplane
# Setup Instructions:
# 1. Create directories:
-43
View File
@@ -1,43 +0,0 @@
version: '3.8'
# Heimdall - Application Dashboard
# Phase 3: Monitoring & Management
# Ports: 8888 (HTTP), 8889 (HTTPS)
# GPU: No
# Storage: SSD (configuration)
services:
heimdall:
image: linuxserver/heimdall:latest
container_name: heimdall
restart: unless-stopped
ports:
- "8888:80"
- "8889:443"
volumes:
- /home/jpmschweitzer/docker-data/heimdall:/config
environment:
- PUID=1000 # Your user ID (run: id -u)
- PGID=1000 # Your group ID (run: id -g)
- TZ=Europe/Amsterdam
# After Deployment:
# 1. Access http://localhost:8888
# 2. Add application tiles for quick access:
# - Portainer: http://tower-of-joy:8080
# - NPM: http://tower-of-joy:8000
# - Jellyfin: http://tower-of-joy:8096
# - Nextcloud: http://tower-of-joy:8082
# - AMP: http://tower-of-joy:8081
# - Uptime Kuma: http://tower-of-joy:3001
# - Netdata: http://tower-of-joy:19999
# - Ollama: http://tower-of-joy:11434
# 3. Customize colors and icons for each service
# 4. Set as browser homepage for easy access
#
# Features:
# - Unified dashboard for all services
# - One-click access to any service
# - Custom backgrounds and themes
# - Search functionality
# - Mobile-friendly
+64
View File
@@ -0,0 +1,64 @@
#!/bin/bash
set -e
# PostgreSQL Initialization Script
# Creates databases and users for homelab applications
# Runs once during initial container startup
echo "🔧 Initializing PostgreSQL databases and users..."
# Source environment variables if available
if [ -f /run/secrets/postgres_passwords ]; then
source /run/secrets/postgres_passwords
fi
# Default passwords (override via environment variables)
: ${AUTHENTIK_DB_PASSWORD:=CHANGEME_AUTHENTIK_PASSWORD}
: ${GITEA_DB_PASSWORD:=CHANGEME_GITEA_PASSWORD}
# Create Authentik database and user
echo "📦 Creating Authentik database..."
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <<-EOSQL
CREATE DATABASE authentik;
CREATE USER authentik_user WITH PASSWORD '$AUTHENTIK_DB_PASSWORD';
GRANT ALL PRIVILEGES ON DATABASE authentik TO authentik_user;
-- Grant schema privileges (required for PostgreSQL 15+)
\c authentik
GRANT ALL ON SCHEMA public TO authentik_user;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO authentik_user;
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO authentik_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO authentik_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON SEQUENCES TO authentik_user;
EOSQL
# Create Gitea database and user (for future migration)
echo "📦 Creating Gitea database..."
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <<-EOSQL
CREATE DATABASE gitea;
CREATE USER gitea_user WITH PASSWORD '$GITEA_DB_PASSWORD';
GRANT ALL PRIVILEGES ON DATABASE gitea TO gitea_user;
\c gitea
GRANT ALL ON SCHEMA public TO gitea_user;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO gitea_user;
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO gitea_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO gitea_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON SEQUENCES TO gitea_user;
EOSQL
# Add future databases here as needed
# echo "📦 Creating future_app database..."
# psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <<-EOSQL
# CREATE DATABASE future_app;
# CREATE USER future_user WITH PASSWORD '$FUTURE_APP_PASSWORD';
# GRANT ALL PRIVILEGES ON DATABASE future_app TO future_user;
# EOSQL
echo "✅ PostgreSQL initialization complete!"
echo ""
echo "📊 Database Summary:"
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" -c '\l'
echo ""
echo "👥 User Summary:"
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" -c '\du'
+7
View File
@@ -42,6 +42,13 @@ services:
# crond flags:
# -f: foreground (don't daemonize)
# -l 2: log level 2 (errors and info)
networks:
- docker-dataplane
networks:
docker-dataplane:
external: true
name: docker-dataplane
# Usage:
# 1. Create maintenance scripts in ~/docker-data/maintenance/scripts/
+7
View File
@@ -27,6 +27,13 @@ services:
# Optional: Claim to Netdata Cloud for remote access
# - NETDATA_CLAIM_TOKEN=your-claim-token
# - NETDATA_CLAIM_URL=https://app.netdata.cloud
networks:
- docker-dataplane
networks:
docker-dataplane:
external: true
name: docker-dataplane
# After Deployment:
# 1. Access http://localhost:19999
+398
View File
@@ -0,0 +1,398 @@
# Nextcloud Database Consolidation Plan
**Goal**: Fresh Nextcloud installation using shared PostgreSQL + Redis infrastructure
**Date**: 2025-11-16
**Status**: APPROVED - Complete wipe and fresh start
**Approach**: No migration, no backups - complete fresh installation
---
## Current State
### Existing Setup
```yaml
nextcloud-db (MariaDB 10.11)
├─ Database: nextcloud
├─ User: nextcloud
├─ Data: /home/jpmschweitzer/docker-data/nextcloud/db
└─ Network: docker-dataplane
nextcloud-redis (Redis Alpine)
├─ Standalone instance
├─ Data: In-memory only (no persistence configured)
└─ Network: docker-dataplane
nextcloud (Nextcloud Stable)
├─ Config: /home/jpmschweitzer/docker-data/nextcloud/config
├─ Data: /mnt/media/nextcloud/data
└─ Dependencies: nextcloud-db, nextcloud-redis
```
### Target Setup
```yaml
postgres-shared (PostgreSQL 16)
├─ New database: nextcloud
├─ New user: nextcloud_user
└─ Database allocation: DB 3
redis-shared (Redis Alpine)
├─ Database allocation: DB 3 (Nextcloud)
├─ Existing DB 0: General cache
├─ Existing DB 1: Authentik
└─ Existing DB 2: Gitea
```
---
## Migration Challenges
### Critical Issue: MariaDB → PostgreSQL
⚠️ **Nextcloud cannot simply switch database types!**
Nextcloud's database schema is different between MariaDB and PostgreSQL:
- Different data types (e.g., LONGTEXT vs TEXT)
- Different auto-increment handling
- Different JSON field types
- Different index structures
**Options:**
### Option A: Fresh Install + Data Migration (RECOMMENDED)
✅ **Pros:**
- Clean database schema
- Opportunity to optimize
- Lower risk of corruption
- Can test before switching
❌ **Cons:**
- Must recreate users/settings
- Requires careful data migration
- More complex process
### Option B: Database Conversion
✅ **Pros:**
- Preserves all settings
- Preserves user data
❌ **Cons:**
- Complex conversion process
- High risk of data loss
- Nextcloud doesn't officially support this
- May leave corrupted data
**RECOMMENDATION: Option A (Fresh Install)**
---
## Fresh Installation Plan
### Phase 1: Complete Cleanup - PURGE ALL DATA
**Estimated Time:** 2 minutes
⚠️ **DESTRUCTIVE OPERATION - REQUIRES EXPLICIT APPROVAL** ⚠️
The following will be PERMANENTLY DELETED:
- All Nextcloud containers (nextcloud, nextcloud-db, nextcloud-redis)
- All Nextcloud configuration (/home/jpmschweitzer/docker-data/nextcloud)
- All Nextcloud user files (/mnt/media/nextcloud)
- All Nextcloud database data
**APPROVAL REQUIRED BEFORE EACH DELETION STEP**
```bash
# Step 1: Stop and remove containers
# APPROVAL: Stop containers? (y/n)
docker stop nextcloud nextcloud-db nextcloud-redis 2>/dev/null || true
docker rm nextcloud nextcloud-db nextcloud-redis 2>/dev/null || true
# Step 2: Delete config directory
# APPROVAL: Delete /home/jpmschweitzer/docker-data/nextcloud? (y/n)
sudo rm -rf /home/jpmschweitzer/docker-data/nextcloud
# Step 3: Delete user data directory
# APPROVAL: Delete /mnt/media/nextcloud? (y/n)
sudo rm -rf /mnt/media/nextcloud
# Step 4: Verify complete removal
ls /home/jpmschweitzer/docker-data/ | grep nextcloud # Should be empty
ls /mnt/media/ | grep nextcloud # Should be empty
```
### Phase 2: Prepare Shared Infrastructure
**Estimated Time:** 5 minutes
```bash
# 1. Create Nextcloud database in postgres-shared
docker exec -i postgres-shared psql -U postgres <<'EOF'
-- Nextcloud database
CREATE DATABASE nextcloud;
CREATE USER nextcloud_user WITH PASSWORD 'GENERATE_NEW_PASSWORD_HERE';
GRANT ALL PRIVILEGES ON DATABASE nextcloud TO nextcloud_user;
\c nextcloud
GRANT ALL ON SCHEMA public TO nextcloud_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO nextcloud_user;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON SEQUENCES TO nextcloud_user;
EOF
# 2. Update redis-shared documentation (already supports DB 3)
# No action needed - redis-shared already configured for multi-database
```
### Phase 3: Create Fresh Nextcloud Stack Configuration
**Estimated Time:** 5 minutes
Create new `nextcloud-shared.yml`:
```yaml
services:
nextcloud:
image: nextcloud:stable
container_name: nextcloud
restart: unless-stopped
ports:
- "8082:80"
volumes:
# Fresh config directory
- /home/jpmschweitzer/docker-data/nextcloud/config:/var/www/html/config
# Fresh user data directory
- /mnt/media/nextcloud/data:/var/www/html/data
environment:
# PostgreSQL configuration
- POSTGRES_HOST=postgres-shared
- POSTGRES_DB=nextcloud
- POSTGRES_USER=nextcloud_user
- POSTGRES_PASSWORD=${NEXTCLOUD_DB_PASSWORD}
# Redis configuration (Database 3)
- REDIS_HOST=redis-shared
- REDIS_HOST_PORT=6379
- REDIS_DB_INDEX=3
# Timezone
- TZ=Europe/Amsterdam
depends_on:
- postgres-shared
- redis-shared
networks:
- docker-dataplane
deploy:
resources:
limits:
memory: 1G
networks:
docker-dataplane:
external: true
name: docker-dataplane
```
### Phase 5: Deploy Fresh Nextcloud
**Estimated Time:** 5 minutes
```bash
# 1. Create new config directory
mkdir -p /home/jpmschweitzer/docker-data/nextcloud-shared/config
# 2. Create .env file with database password
cat > /mnt/media/Projects/portainer-core/stacks/.env.nextcloud-shared <<EOF
NEXTCLOUD_DB_PASSWORD=<GENERATED_PASSWORD_FROM_PHASE2>
EOF
# 3. Deploy new stack
cd /mnt/media/Projects/portainer-core/stacks
docker compose -f nextcloud-shared.yml --env-file .env.nextcloud-shared up -d
# 4. Wait for initialization
docker logs -f nextcloud
```
### Phase 6: Initial Setup & Configuration
**Estimated Time:** 10 minutes
```bash
# 1. Access Nextcloud web interface
# Navigate to: http://localhost:8082 or https://cloud.schweitz.net
# 2. First-time setup wizard:
# - Admin username: admin
# - Admin password: <STRONG_PASSWORD>
# - Data folder: /var/www/html/data (default)
# - Database: PostgreSQL
# - Database user: nextcloud_user
# - Database password: <FROM_ENV_FILE>
# - Database name: nextcloud
# - Database host: postgres-shared
# 3. Wait for installation (2-3 minutes)
# 4. Configure trusted domains
docker exec -u www-data nextcloud php occ config:system:set trusted_domains 1 --value=cloud.schweitz.net
docker exec -u www-data nextcloud php occ config:system:set trusted_domains 2 --value=192.168.86.149
# 5. Configure Redis caching
docker exec -u www-data nextcloud php occ config:system:set redis host --value=redis-shared
docker exec -u www-data nextcloud php occ config:system:set redis port --value=6379
docker exec -u www-data nextcloud php occ config:system:set redis dbindex --value=3
docker exec -u www-data nextcloud php occ config:system:set memcache.local --value='\\OC\\Memcache\\APCu'
docker exec -u www-data nextcloud php occ config:system:set memcache.distributed --value='\\OC\\Memcache\\Redis'
docker exec -u www-data nextcloud php occ config:system:set memcache.locking --value='\\OC\\Memcache\\Redis'
# 6. Optimize database
docker exec -u www-data nextcloud php occ db:add-missing-indices
docker exec -u www-data nextcloud php occ db:convert-filecache-bigint
# 7. Configure background jobs
docker exec -u www-data nextcloud php occ background:cron
```
### Phase 7: Verify Fresh Installation
**Estimated Time:** 5 minutes
```bash
# 1. Verify admin user can login via web interface
# Navigate to: https://cloud.schweitz.net
# 2. Check PostgreSQL connection
docker exec postgres-shared psql -U nextcloud_user -d nextcloud -c '\dt'
# 3. Check Redis caching
docker exec redis-shared redis-cli -n 3 DBSIZE
# 4. Verify storage location
docker exec -u www-data nextcloud php occ config:system:get datadirectory
# 5. Test file upload/download
# Upload a test file via web interface
# Download it back
# Delete it
```
### Phase 8: Final Cleanup & Documentation
**Estimated Time:** 2 minutes
```bash
# 1. Update postgres-shared.yml documentation
# Add Nextcloud to "Applications Using This Database" list
# 2. Update redis-shared.yml documentation
# Add "DB 3: Nextcloud (file locking, distributed cache)"
# 3. Rename stack file
cd /mnt/media/Projects/portainer-core/stacks
mv nextcloud.yml nextcloud-mariadb-archived.yml
mv nextcloud-shared.yml nextcloud.yml
# 4. Delete old archived stack (already purged data in Phase 1)
# All old containers and data already removed
```
---
## Rollback Plan
⚠️ **NO ROLLBACK POSSIBLE** ⚠️
Since all old data is purged in Phase 1, there is no rollback option.
If fresh installation fails:
1. Review error logs
2. Fix configuration issues
3. Retry fresh installation
This is acceptable since Nextcloud is not in production use.
---
## Testing Checklist
After fresh installation, verify:
- [ ] Admin login works
- [ ] File upload works
- [ ] File download works
- [ ] File delete works
- [ ] Redis caching active (`docker exec redis-shared redis-cli -n 3 DBSIZE` shows keys)
- [ ] PostgreSQL connection stable (`docker exec postgres-shared psql -U nextcloud_user -d nextcloud -c '\dt'` shows tables)
- [ ] Memory usage acceptable (<1GB for Nextcloud container)
- [ ] Nextcloud accessible via https://cloud.schweitz.net
- [ ] No errors in logs (`docker logs nextcloud`)
---
## Resource Savings
**Before Migration:**
- nextcloud-db (MariaDB): ~117 MB RAM
- nextcloud-redis: ~10 MB RAM
- **Total:** ~127 MB RAM + 2 containers
**After Migration:**
- Shared postgres-shared: Already running (minimal additional overhead for one more DB)
- Shared redis-shared: Already running (DB 3 uses ~5-10 MB additional)
- **Savings:** ~110-120 MB RAM + 2 fewer containers to manage
**Benefits:**
- Simplified infrastructure
- Centralized backups
- Better resource utilization
- Easier monitoring
- Consistent database management
---
## Risks & Mitigation
| Risk | Impact | Mitigation |
|------|--------|------------|
| Data loss during migration | HIGH | Full backups before starting, test on copy first |
| Incompatible plugins/apps | MEDIUM | Fresh install allows clean app selection |
| User resistance to re-setup | LOW | Minimal - same interface, same files |
| Extended downtime | MEDIUM | Plan migration during low-usage window |
| Redis DB conflict | LOW | Using dedicated DB 3, isolated from other apps |
---
## Timeline
**Total estimated time:** 20-30 minutes
- Phase 1: Purge all data: 2 min
- Phase 2: Prepare PostgreSQL/Redis: 5 min
- Phase 3: Create stack config: 2 min
- Phase 4: Create directories: 1 min
- Phase 5: Deploy Nextcloud: 3 min
- Phase 6: Initial setup & config: 10 min
- Phase 7: Testing: 5 min
- Phase 8: Documentation: 2 min
**Can be done anytime** - No production impact, no backups needed
---
## Approval Required
- [ ] Backup strategy approved
- [ ] Fresh install approach approved
- [ ] Downtime window approved
- [ ] Testing checklist reviewed
- [ ] Rollback plan understood
- [ ] Ready to proceed
---
## Notes
- **COMPLETE FRESH START** - All old data deleted
- Clean database, optimal performance from day one
- PostgreSQL generally faster than MariaDB for Nextcloud workloads
- Redis DB 3 dedicated to Nextcloud (isolated from other apps)
- No migration complexity - just a clean installation
- Ready for production use immediately after setup
+6 -5
View File
@@ -22,7 +22,7 @@ services:
- MYSQL_USER=nextcloud
- TZ=Europe/Amsterdam
networks:
- nextcloud-network
- docker-dataplane
nextcloud-redis:
image: redis:alpine
@@ -31,7 +31,7 @@ services:
environment:
- TZ=Europe/Amsterdam
networks:
- nextcloud-network
- docker-dataplane
nextcloud:
image: nextcloud:stable
@@ -56,11 +56,12 @@ services:
- nextcloud-db
- nextcloud-redis
networks:
- nextcloud-network
- docker-dataplane
networks:
nextcloud-network:
driver: bridge
docker-dataplane:
external: true
name: docker-dataplane
# ⚠️ SECURITY WARNING:
# Change MYSQL_ROOT_PASSWORD and MYSQL_PASSWORD before deploying!
+10
View File
@@ -24,11 +24,21 @@ services:
- NVIDIA_DRIVER_CAPABILITIES=all
deploy:
resources:
limits:
memory: 8G
reservations:
memory: 1G
devices:
- driver: nvidia
count: 1
capabilities: [gpu]
networks:
- docker-dataplane
networks:
docker-dataplane:
external: true
name: docker-dataplane
# GPU Requirements:
# - RTX 2080 Ti (11GB VRAM)
+12 -6
View File
@@ -1,5 +1,3 @@
version: '3.8'
services:
open-webui:
image: ghcr.io/open-webui/open-webui:main
@@ -46,13 +44,21 @@ services:
volumes:
- /home/jpmschweitzer/docker-data/open-webui:/app/backend/data
deploy:
resources:
limits:
cpus: '1.0'
memory: 1G
reservations:
memory: 512M
networks:
- ai-dataplane
- docker-dataplane
labels:
- "com.centurylinklabs.watchtower.enable=true"
networks:
ai-dataplane:
driver: bridge
name: ai-dataplane
docker-dataplane:
external: true
name: docker-dataplane
+7
View File
@@ -22,6 +22,13 @@ services:
- PGID=1000
- TZ=Europe/Amsterdam
- fpm=true # Enable PHP-FPM for better performance
networks:
- docker-dataplane
networks:
docker-dataplane:
external: true
name: docker-dataplane
# Setup Instructions:
# 1. Ensure tower-of-joy is connected to Headscale mesh (get mesh IP)
+135
View File
@@ -0,0 +1,135 @@
version: '3.8'
# Shared PostgreSQL Database
# Purpose: Centralized database for all homelab applications
# Port: 5432
# GPU: No
# Storage: SSD (PostgreSQL data and backups)
services:
postgres-shared:
image: postgres:16-alpine
container_name: postgres-shared
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
start_period: 20s
interval: 30s
retries: 5
timeout: 5s
ports:
- "5432:5432"
volumes:
- /home/jpmschweitzer/docker-data/postgres-shared/data:/var/lib/postgresql/data
- /home/jpmschweitzer/docker-data/postgres-shared/backups:/backups
environment:
POSTGRES_PASSWORD: ${POSTGRES_ADMIN_PASSWORD:?admin password required}
TZ: Europe/Amsterdam
# Performance tuning (adjust based on available RAM)
# Shared buffers: 25% of RAM allocated to PostgreSQL
POSTGRES_SHARED_BUFFERS: 512MB
# Effective cache: 50-75% of RAM allocated to PostgreSQL
POSTGRES_EFFECTIVE_CACHE_SIZE: 2GB
# Max connections: adjust based on number of applications
POSTGRES_MAX_CONNECTIONS: 200
deploy:
resources:
limits:
cpus: '2.0'
memory: 2G
reservations:
memory: 512M
networks:
- docker-dataplane
networks:
docker-dataplane:
external: true
name: docker-dataplane
# Setup Instructions:
#
# 1. Create directories:
# mkdir -p ~/docker-data/postgres-shared/{data,backups}
#
# 2. Deploy stack via core-api (recommended) or docker-compose
#
# 3. Initialize databases (run ONCE after first deployment):
# docker exec -i postgres-shared psql -U postgres <<'EOF'
# -- Authentik database
# CREATE DATABASE authentik;
# CREATE USER authentik_user WITH PASSWORD 'F//j0ktck7cX06Vfgh0YXceONOtlSsHvadqROICeDx8=';
# GRANT ALL PRIVILEGES ON DATABASE authentik TO authentik_user;
# \c authentik
# GRANT ALL ON SCHEMA public TO authentik_user;
# ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO authentik_user;
# ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON SEQUENCES TO authentik_user;
#
# -- Gitea database
# \c postgres
# CREATE DATABASE gitea;
# CREATE USER gitea_user WITH PASSWORD 'cCav64d76NX1zdEEAbVOM9uvao14aY8HojjNdxsSpMM=';
# GRANT ALL PRIVILEGES ON DATABASE gitea TO gitea_user;
# \c gitea
# GRANT ALL ON SCHEMA public TO gitea_user;
# ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO gitea_user;
# ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON SEQUENCES TO gitea_user;
# EOF
#
# 4. Verify deployment:
# docker exec postgres-shared pg_isready
# docker exec postgres-shared psql -U postgres -c '\l'
#
# Database Connection Examples:
#
# From containers on docker-dataplane network:
# Host: postgres-shared
# Port: 5432
# Database: authentik (or gitea, etc.)
# User: authentik_user (or gitea_user, etc.)
# Password: <app-specific-password>
#
# From host machine:
# psql -h localhost -U authentik_user -d authentik
#
# Monitoring:
#
# Active connections per database:
# docker exec postgres-shared psql -U postgres -c \
# "SELECT datname, numbackends FROM pg_stat_database;"
#
# Database sizes:
# docker exec postgres-shared psql -U postgres -c \
# "SELECT datname, pg_size_pretty(pg_database_size(datname)) FROM pg_database;"
#
# Backup:
#
# All databases:
# docker exec postgres-shared pg_dumpall -U postgres | \
# gzip > ~/docker-data/postgres-shared/backups/all-$(date +%Y%m%d).sql.gz
#
# Single database:
# docker exec postgres-shared pg_dump -U postgres authentik | \
# gzip > ~/docker-data/postgres-shared/backups/authentik-$(date +%Y%m%d).sql.gz
#
# Restore:
# gunzip < backup.sql.gz | docker exec -i postgres-shared psql -U postgres
#
# Maintenance:
#
# Vacuum analyze (optimize performance):
# docker exec postgres-shared psql -U postgres -c "VACUUM ANALYZE;"
#
# Reindex (if queries slow):
# docker exec postgres-shared psql -U postgres -d authentik -c "REINDEX DATABASE authentik;"
#
# Resource Usage (expected):
# CPU: ~0.5-1.5 cores (depends on query load)
# RAM: ~500MB-1.5GB (depends on active connections and cache)
# Storage: Grows with data (monitor with: df -h ~/docker-data/postgres-shared)
#
# Applications Using This Database:
# - Authentik (identity provider)
# - Gitea (git hosting) - migrated from dedicated instance
# - Future applications as needed
+10 -2
View File
@@ -21,12 +21,20 @@ services:
- /home/jpmschweitzer/docker-data/qdrant/snapshots:/qdrant/snapshots
environment:
- TZ=Europe/Amsterdam
deploy:
resources:
limits:
cpus: '1.0'
memory: 768M
reservations:
memory: 256M
networks:
- ai-dataplane
- docker-dataplane
networks:
ai-dataplane:
docker-dataplane:
external: true
name: docker-dataplane
# Qdrant Performance Notes:
# - Optimized for high-dimensional vectors (embeddings)
+153
View File
@@ -0,0 +1,153 @@
version: '3.8'
# Shared Redis Cache
# Purpose: Centralized cache and session store for all homelab applications
# Port: 6379
# GPU: No
# Storage: SSD (Redis persistence - AOF and RDB)
services:
redis-shared:
image: redis:alpine
container_name: redis-shared
restart: unless-stopped
command: >
redis-server
--appendonly yes
--appendfsync everysec
--maxmemory 512mb
--maxmemory-policy allkeys-lru
--save 60 1000
--save 300 100
--save 900 1
--loglevel warning
healthcheck:
test: ["CMD-SHELL", "redis-cli ping | grep PONG"]
start_period: 20s
interval: 30s
retries: 5
timeout: 3s
ports:
- "6379:6379"
volumes:
- /home/jpmschweitzer/docker-data/redis-shared/data:/data
environment:
TZ: Europe/Amsterdam
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
reservations:
memory: 128M
networks:
- docker-dataplane
networks:
docker-dataplane:
external: true
name: docker-dataplane
# Setup Instructions:
#
# 1. Create directories:
# mkdir -p ~/docker-data/redis-shared/data
#
# 2. Deploy stack:
# docker-compose -f redis-shared.yml up -d
#
# 3. Verify deployment:
# docker exec redis-shared redis-cli ping
#
# Database Allocation:
#
# Redis supports 16 databases (0-15). Assign one per application:
#
# DB 0: General cache (default, shared lightweight caching)
# DB 1: Authentik (sessions, cache, message queue)
# DB 2: Gitea (cache, sessions)
# DB 3: Open WebUI (cache, if needed)
# DB 4-15: Reserved for future applications
#
# Connection Examples:
#
# From containers on docker-dataplane network:
# redis://redis-shared:6379/1 (Authentik, DB 1)
# redis://redis-shared:6379/2 (Gitea, DB 2)
#
# From host machine:
# redis-cli -h localhost
# SELECT 1 (switch to database 1)
#
# Monitoring:
#
# General info:
# docker exec redis-shared redis-cli INFO
#
# Memory usage:
# docker exec redis-shared redis-cli INFO memory
#
# Keyspace (keys per database):
# docker exec redis-shared redis-cli INFO keyspace
#
# Stats:
# docker exec redis-shared redis-cli INFO stats
#
# Per-database keys:
# docker exec redis-shared redis-cli -n 1 DBSIZE (database 1)
# docker exec redis-shared redis-cli -n 2 DBSIZE (database 2)
#
# Backup:
#
# Trigger background save:
# docker exec redis-shared redis-cli BGSAVE
#
# Copy RDB file:
# cp ~/docker-data/redis-shared/data/dump.rdb \
# ~/backups/redis-$(date +%Y%m%d).rdb
#
# Backup AOF (append-only file):
# cp ~/docker-data/redis-shared/data/appendonly.aof \
# ~/backups/redis-aof-$(date +%Y%m%d).aof
#
# Restore:
# docker stop redis-shared
# cp backup-dump.rdb ~/docker-data/redis-shared/data/dump.rdb
# docker start redis-shared
#
# Maintenance:
#
# Clear specific database (DANGER - data loss!):
# docker exec redis-shared redis-cli -n 1 FLUSHDB
#
# Clear all databases (DANGER - total data loss!):
# docker exec redis-shared redis-cli FLUSHALL
#
# Rewrite AOF (compact log file):
# docker exec redis-shared redis-cli BGREWRITEAOF
#
# Configuration Details:
#
# Persistence strategy (dual):
# - AOF (Append Only File): Real-time durability, fsync every second
# - RDB Snapshots: Periodic snapshots (every 60s if 1000+ keys changed)
#
# Memory policy:
# - Max memory: 512MB
# - Eviction: allkeys-lru (Least Recently Used eviction when full)
#
# Resource Usage (expected):
# CPU: ~0.1-0.3 cores (low CPU, very efficient)
# RAM: ~100-400MB (depends on data, capped at 512MB)
# Storage: ~50-200MB (AOF + RDB files)
#
# Applications Using This Cache:
# - Authentik (sessions, policies, background tasks)
# - Gitea (sessions, cache, queues) - if migrated
# - Future applications as needed
#
# Performance Tips:
# - Use pipeline commands for bulk operations
# - Set appropriate TTL (Time To Live) on cached keys
# - Monitor memory usage to prevent eviction storms
# - Use database numbers to isolate application data
+7
View File
@@ -32,6 +32,13 @@ services:
-s "Backups;/share/backups;yes;no;yes;all"
-u "jpmschweitzer;IG3omTybtVW3pVmmBi1D5FjnQ0MnZLUG"
-p
networks:
- docker-dataplane
networks:
docker-dataplane:
external: true
name: docker-dataplane
# ⚠️ SECURITY WARNING:
# Change CHANGEME_SAMBA_PASSWORD before deploying!
+3 -16
View File
@@ -18,25 +18,12 @@ services:
environment:
- TZ=Europe/Amsterdam
networks:
- default
- ai-dataplane
- nextcloud-network
- headscale-network
- samba-network
- docker-dataplane
networks:
ai-dataplane:
docker-dataplane:
external: true
name: ai-dataplane
nextcloud-network:
external: true
name: nextcloud_nextcloud-network
headscale-network:
external: true
name: stacks_headscale-network
samba-network:
external: true
name: samba_default
name: docker-dataplane
# After Deployment:
# 1. Access http://localhost:3001
+7
View File
@@ -23,6 +23,13 @@ services:
# Optional: Monitor only specific containers
# - WATCHTOWER_LABEL_ENABLE=true # Only update containers with label com.centurylinklabs.watchtower.enable=true
networks:
- docker-dataplane
networks:
docker-dataplane:
external: true
name: docker-dataplane
# Schedule Format (cron):
# - 0 0 4 * * * = Daily at 4 AM