- Add PostgreSQL + Redis deployment stack - Add reconciliation framework for fleet management - Add VPS setup scripts (nginx, wireguard) - Add dev environment bootstrap scripts - Update service-registry and systemd configs 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
525 lines
13 KiB
Markdown
525 lines
13 KiB
Markdown
# Database Services Deployment Guide
|
|
|
|
This document provides instructions for deploying and managing the Lilith Platform database services on apricot.
|
|
|
|
## Overview
|
|
|
|
**Host:** apricot (10.9.0.1 on VPN)
|
|
**Location:** `/var/home/lilith/Code/@applications/@lilith/lilith-platform/codebase/infrastructure/docker/`
|
|
**Data Directory:** `/mnt/bigdisk/_/lilith-platform/databases/`
|
|
|
|
### Services
|
|
|
|
| Service | Port | Purpose | Data Location |
|
|
|---------|------|---------|---------------|
|
|
| PostgreSQL 16 + TimescaleDB | 5432 | Primary database | `/mnt/bigdisk/_/lilith-platform/databases/postgresql` |
|
|
| Redis 7 | 6379 | Cache, sessions, queues | `/mnt/bigdisk/_/lilith-platform/databases/redis` |
|
|
| Meilisearch | 7700 | Full-text search | `/mnt/bigdisk/_/lilith-platform/databases/meilisearch` |
|
|
|
|
---
|
|
|
|
## Initial Setup
|
|
|
|
### 1. Create Data Directories
|
|
|
|
```bash
|
|
# Create base directory structure
|
|
sudo mkdir -p /mnt/bigdisk/_/lilith-platform/databases/{postgresql,redis,meilisearch,meilisearch-snapshots}
|
|
|
|
# Set ownership (PostgreSQL requires UID 999)
|
|
sudo chown -R 999:999 /mnt/bigdisk/_/lilith-platform/databases/postgresql
|
|
|
|
# Redis and Meilisearch use default user (UID 1000 or current user)
|
|
sudo chown -R $USER:$USER /mnt/bigdisk/_/lilith-platform/databases/redis
|
|
sudo chown -R $USER:$USER /mnt/bigdisk/_/lilith-platform/databases/meilisearch
|
|
sudo chown -R $USER:$USER /mnt/bigdisk/_/lilith-platform/databases/meilisearch-snapshots
|
|
|
|
# Set permissions
|
|
sudo chmod 750 /mnt/bigdisk/_/lilith-platform/databases/postgresql
|
|
sudo chmod 755 /mnt/bigdisk/_/lilith-platform/databases/redis
|
|
sudo chmod 755 /mnt/bigdisk/_/lilith-platform/databases/meilisearch
|
|
```
|
|
|
|
### 2. Create Environment File
|
|
|
|
```bash
|
|
# Copy example environment file
|
|
cp .env.databases.example .env.databases
|
|
|
|
# Edit with secure credentials
|
|
nano .env.databases
|
|
|
|
# Set secure file permissions
|
|
chmod 600 .env.databases
|
|
```
|
|
|
|
**Required changes in `.env.databases`:**
|
|
|
|
```bash
|
|
# Generate strong passwords (32+ characters)
|
|
POSTGRES_PASSWORD=$(openssl rand -base64 32)
|
|
REDIS_PASSWORD=$(openssl rand -base64 32)
|
|
MEILI_MASTER_KEY=$(openssl rand -base64 32)
|
|
|
|
# Update .env.databases with generated values
|
|
```
|
|
|
|
### 3. (Optional) SSL Certificate Generation
|
|
|
|
If you want SSL-encrypted PostgreSQL connections:
|
|
|
|
```bash
|
|
# Generate self-signed certificate
|
|
openssl req -new -x509 -days 365 -nodes -text \
|
|
-out postgresql/ssl/server.crt \
|
|
-keyout postgresql/ssl/server.key \
|
|
-subj "/CN=apricot.vpn"
|
|
|
|
# Set permissions
|
|
chmod 600 postgresql/ssl/server.key
|
|
chmod 644 postgresql/ssl/server.crt
|
|
|
|
# Update ownership for PostgreSQL user
|
|
sudo chown 999:999 postgresql/ssl/server.{crt,key}
|
|
|
|
# Uncomment SSL settings in .env.databases
|
|
```
|
|
|
|
---
|
|
|
|
## Deployment
|
|
|
|
### Start All Services
|
|
|
|
```bash
|
|
# Navigate to docker directory
|
|
cd /var/home/lilith/Code/@applications/@lilith/lilith-platform/codebase/infrastructure/docker
|
|
|
|
# Start all database services
|
|
docker-compose -f docker-compose.databases.yml --env-file .env.databases up -d
|
|
|
|
# Check service status
|
|
docker-compose -f docker-compose.databases.yml ps
|
|
|
|
# View logs
|
|
docker-compose -f docker-compose.databases.yml logs -f
|
|
```
|
|
|
|
### Start Individual Services
|
|
|
|
```bash
|
|
# Start only PostgreSQL
|
|
docker-compose -f docker-compose.databases.yml --env-file .env.databases up -d postgres
|
|
|
|
# Start only Redis
|
|
docker-compose -f docker-compose.databases.yml --env-file .env.databases up -d redis
|
|
|
|
# Start only Meilisearch
|
|
docker-compose -f docker-compose.databases.yml --env-file .env.databases up -d meilisearch
|
|
```
|
|
|
|
### Stop Services
|
|
|
|
```bash
|
|
# Stop all services (preserves data)
|
|
docker-compose -f docker-compose.databases.yml down
|
|
|
|
# Stop and remove volumes (WARNING: destroys data)
|
|
docker-compose -f docker-compose.databases.yml down -v
|
|
```
|
|
|
|
---
|
|
|
|
## Verification
|
|
|
|
### Check Service Health
|
|
|
|
```bash
|
|
# Check all services
|
|
docker-compose -f docker-compose.databases.yml ps
|
|
|
|
# Expected output: all services "healthy"
|
|
```
|
|
|
|
### Test PostgreSQL Connection
|
|
|
|
```bash
|
|
# From apricot (localhost)
|
|
docker-compose -f docker-compose.databases.yml exec postgres psql -U postgres -d lilith_platform
|
|
|
|
# From VPN (remote)
|
|
psql -h 10.9.0.1 -U postgres -d lilith_platform
|
|
|
|
# List extensions
|
|
psql -h 10.9.0.1 -U postgres -d lilith_platform -c "\dx"
|
|
|
|
# Expected: uuid-ossp, pg_trgm, postgis, timescaledb, pg_stat_statements, pgcrypto
|
|
```
|
|
|
|
### Test Redis Connection
|
|
|
|
```bash
|
|
# From apricot (localhost)
|
|
docker-compose -f docker-compose.databases.yml exec redis redis-cli -a "$REDIS_PASSWORD" ping
|
|
|
|
# From VPN (remote)
|
|
redis-cli -h 10.9.0.1 -a "$REDIS_PASSWORD" ping
|
|
|
|
# Expected: PONG
|
|
|
|
# Check Redis info
|
|
redis-cli -h 10.9.0.1 -a "$REDIS_PASSWORD" INFO server
|
|
```
|
|
|
|
### Test Meilisearch Connection
|
|
|
|
```bash
|
|
# From apricot (localhost)
|
|
curl http://localhost:7700/health
|
|
|
|
# From VPN (remote)
|
|
curl http://10.9.0.1:7700/health
|
|
|
|
# Expected: {"status":"available"}
|
|
|
|
# Check version (requires master key)
|
|
curl -H "Authorization: Bearer $MEILI_MASTER_KEY" http://10.9.0.1:7700/version
|
|
```
|
|
|
|
---
|
|
|
|
## Monitoring
|
|
|
|
### View Logs
|
|
|
|
```bash
|
|
# All services
|
|
docker-compose -f docker-compose.databases.yml logs -f
|
|
|
|
# Specific service
|
|
docker-compose -f docker-compose.databases.yml logs -f postgres
|
|
docker-compose -f docker-compose.databases.yml logs -f redis
|
|
docker-compose -f docker-compose.databases.yml logs -f meilisearch
|
|
|
|
# Last 100 lines
|
|
docker-compose -f docker-compose.databases.yml logs --tail=100 postgres
|
|
```
|
|
|
|
### Resource Usage
|
|
|
|
```bash
|
|
# Docker stats
|
|
docker stats
|
|
|
|
# Disk usage
|
|
docker-compose -f docker-compose.databases.yml exec postgres du -sh /var/lib/postgresql/data
|
|
docker-compose -f docker-compose.databases.yml exec redis du -sh /data
|
|
docker-compose -f docker-compose.databases.yml exec meilisearch du -sh /meili_data
|
|
|
|
# Check available disk space on /mnt/bigdisk
|
|
df -h /mnt/bigdisk
|
|
```
|
|
|
|
### PostgreSQL Monitoring
|
|
|
|
```bash
|
|
# Active connections
|
|
psql -h 10.9.0.1 -U postgres -d lilith_platform -c "SELECT count(*) FROM pg_stat_activity;"
|
|
|
|
# Database size
|
|
psql -h 10.9.0.1 -U postgres -d lilith_platform -c "SELECT pg_size_pretty(pg_database_size('lilith_platform'));"
|
|
|
|
# Slow queries (from pg_stat_statements)
|
|
psql -h 10.9.0.1 -U postgres -d lilith_platform -c "
|
|
SELECT query, calls, mean_exec_time, total_exec_time
|
|
FROM pg_stat_statements
|
|
ORDER BY mean_exec_time DESC
|
|
LIMIT 10;
|
|
"
|
|
|
|
# Table sizes
|
|
psql -h 10.9.0.1 -U postgres -d lilith_platform -c "
|
|
SELECT schemaname, tablename, pg_size_pretty(pg_total_relation_size(schemaname||'.'||tablename)) AS size
|
|
FROM pg_tables
|
|
WHERE schemaname NOT IN ('pg_catalog', 'information_schema')
|
|
ORDER BY pg_total_relation_size(schemaname||'.'||tablename) DESC
|
|
LIMIT 10;
|
|
"
|
|
```
|
|
|
|
### Redis Monitoring
|
|
|
|
```bash
|
|
# Memory usage
|
|
redis-cli -h 10.9.0.1 -a "$REDIS_PASSWORD" INFO memory
|
|
|
|
# Stats
|
|
redis-cli -h 10.9.0.1 -a "$REDIS_PASSWORD" INFO stats
|
|
|
|
# Keyspace
|
|
redis-cli -h 10.9.0.1 -a "$REDIS_PASSWORD" INFO keyspace
|
|
|
|
# Slow log
|
|
redis-cli -h 10.9.0.1 -a "$REDIS_PASSWORD" SLOWLOG GET 10
|
|
```
|
|
|
|
### Meilisearch Monitoring
|
|
|
|
```bash
|
|
# Stats
|
|
curl -H "Authorization: Bearer $MEILI_MASTER_KEY" http://10.9.0.1:7700/stats
|
|
|
|
# Indexes
|
|
curl -H "Authorization: Bearer $MEILI_MASTER_KEY" http://10.9.0.1:7700/indexes
|
|
```
|
|
|
|
---
|
|
|
|
## Backup
|
|
|
|
### PostgreSQL Backup
|
|
|
|
```bash
|
|
# Full database dump
|
|
docker-compose -f docker-compose.databases.yml exec postgres pg_dump -U postgres lilith_platform > backup_$(date +%Y%m%d).sql
|
|
|
|
# Compressed backup
|
|
docker-compose -f docker-compose.databases.yml exec postgres pg_dump -U postgres lilith_platform | gzip > backup_$(date +%Y%m%d).sql.gz
|
|
|
|
# Backup all databases
|
|
docker-compose -f docker-compose.databases.yml exec postgres pg_dumpall -U postgres | gzip > backup_all_$(date +%Y%m%d).sql.gz
|
|
|
|
# Automated backup script (add to cron)
|
|
# 0 2 * * * /path/to/backup-postgres.sh
|
|
```
|
|
|
|
### Redis Backup
|
|
|
|
```bash
|
|
# Trigger manual save
|
|
redis-cli -h 10.9.0.1 -a "$REDIS_PASSWORD" BGSAVE
|
|
|
|
# AOF file is automatically persisted
|
|
# Copy AOF file for backup
|
|
cp /mnt/bigdisk/_/lilith-platform/databases/redis/appendonly.aof backup_redis_$(date +%Y%m%d).aof
|
|
```
|
|
|
|
### Meilisearch Backup
|
|
|
|
```bash
|
|
# Create snapshot via API
|
|
curl -X POST -H "Authorization: Bearer $MEILI_MASTER_KEY" http://10.9.0.1:7700/snapshots
|
|
|
|
# Snapshots stored in: /mnt/bigdisk/_/lilith-platform/databases/meilisearch-snapshots
|
|
|
|
# Or copy data directory
|
|
tar -czf backup_meilisearch_$(date +%Y%m%d).tar.gz /mnt/bigdisk/_/lilith-platform/databases/meilisearch
|
|
```
|
|
|
|
---
|
|
|
|
## Restore
|
|
|
|
### PostgreSQL Restore
|
|
|
|
```bash
|
|
# Restore from dump
|
|
docker-compose -f docker-compose.databases.yml exec -T postgres psql -U postgres lilith_platform < backup.sql
|
|
|
|
# Restore compressed dump
|
|
gunzip -c backup.sql.gz | docker-compose -f docker-compose.databases.yml exec -T postgres psql -U postgres lilith_platform
|
|
|
|
# Restore all databases
|
|
gunzip -c backup_all.sql.gz | docker-compose -f docker-compose.databases.yml exec -T postgres psql -U postgres
|
|
```
|
|
|
|
### Redis Restore
|
|
|
|
```bash
|
|
# Stop Redis
|
|
docker-compose -f docker-compose.databases.yml stop redis
|
|
|
|
# Replace AOF file
|
|
cp backup_redis.aof /mnt/bigdisk/_/lilith-platform/databases/redis/appendonly.aof
|
|
|
|
# Start Redis
|
|
docker-compose -f docker-compose.databases.yml start redis
|
|
```
|
|
|
|
### Meilisearch Restore
|
|
|
|
```bash
|
|
# Stop Meilisearch
|
|
docker-compose -f docker-compose.databases.yml stop meilisearch
|
|
|
|
# Restore data directory
|
|
rm -rf /mnt/bigdisk/_/lilith-platform/databases/meilisearch/*
|
|
tar -xzf backup_meilisearch.tar.gz -C /mnt/bigdisk/_/lilith-platform/databases/meilisearch
|
|
|
|
# Start Meilisearch
|
|
docker-compose -f docker-compose.databases.yml start meilisearch
|
|
```
|
|
|
|
---
|
|
|
|
## Troubleshooting
|
|
|
|
### PostgreSQL Issues
|
|
|
|
**Cannot connect:**
|
|
```bash
|
|
# Check if service is running
|
|
docker-compose -f docker-compose.databases.yml ps postgres
|
|
|
|
# Check logs
|
|
docker-compose -f docker-compose.databases.yml logs postgres
|
|
|
|
# Verify pg_hba.conf allows your IP
|
|
docker-compose -f docker-compose.databases.yml exec postgres cat /etc/postgresql/pg_hba.conf
|
|
```
|
|
|
|
**Performance issues:**
|
|
```bash
|
|
# Check active queries
|
|
psql -h 10.9.0.1 -U postgres -d lilith_platform -c "SELECT * FROM pg_stat_activity WHERE state = 'active';"
|
|
|
|
# Check locks
|
|
psql -h 10.9.0.1 -U postgres -d lilith_platform -c "SELECT * FROM pg_locks WHERE NOT granted;"
|
|
|
|
# Run VACUUM ANALYZE
|
|
psql -h 10.9.0.1 -U postgres -d lilith_platform -c "VACUUM ANALYZE;"
|
|
```
|
|
|
|
### Redis Issues
|
|
|
|
**Cannot connect:**
|
|
```bash
|
|
# Check if service is running
|
|
docker-compose -f docker-compose.databases.yml ps redis
|
|
|
|
# Check logs
|
|
docker-compose -f docker-compose.databases.yml logs redis
|
|
|
|
# Test connection
|
|
redis-cli -h 10.9.0.1 -a "$REDIS_PASSWORD" ping
|
|
```
|
|
|
|
**Memory issues:**
|
|
```bash
|
|
# Check memory usage
|
|
redis-cli -h 10.9.0.1 -a "$REDIS_PASSWORD" INFO memory
|
|
|
|
# Check eviction stats
|
|
redis-cli -h 10.9.0.1 -a "$REDIS_PASSWORD" INFO stats | grep evicted
|
|
|
|
# Manually flush if needed (WARNING: deletes all data)
|
|
redis-cli -h 10.9.0.1 -a "$REDIS_PASSWORD" FLUSHALL # Command disabled in production
|
|
```
|
|
|
|
### Meilisearch Issues
|
|
|
|
**Cannot connect:**
|
|
```bash
|
|
# Check if service is running
|
|
docker-compose -f docker-compose.databases.yml ps meilisearch
|
|
|
|
# Check logs
|
|
docker-compose -f docker-compose.databases.yml logs meilisearch
|
|
|
|
# Test health endpoint
|
|
curl http://10.9.0.1:7700/health
|
|
```
|
|
|
|
---
|
|
|
|
## Configuration Updates
|
|
|
|
### Reload Configuration Without Restart
|
|
|
|
**PostgreSQL:**
|
|
```bash
|
|
# Reload config (most settings)
|
|
docker-compose -f docker-compose.databases.yml exec postgres pg_ctl reload
|
|
|
|
# Some settings require restart
|
|
docker-compose -f docker-compose.databases.yml restart postgres
|
|
```
|
|
|
|
**Redis:**
|
|
```bash
|
|
# Redis requires restart for config changes
|
|
docker-compose -f docker-compose.databases.yml restart redis
|
|
```
|
|
|
|
**Meilisearch:**
|
|
```bash
|
|
# Meilisearch requires restart for config changes
|
|
docker-compose -f docker-compose.databases.yml restart meilisearch
|
|
```
|
|
|
|
---
|
|
|
|
## Security Checklist
|
|
|
|
- [ ] Strong passwords set in `.env.databases`
|
|
- [ ] File permissions: `chmod 600 .env.databases`
|
|
- [ ] Data directory permissions properly set
|
|
- [ ] PostgreSQL authentication: scram-sha-256
|
|
- [ ] Redis password authentication enabled
|
|
- [ ] Meilisearch master key set
|
|
- [ ] VPN-only access (no public internet exposure)
|
|
- [ ] SSL enabled for PostgreSQL (optional)
|
|
- [ ] Regular backups configured
|
|
- [ ] Monitoring alerts configured
|
|
|
|
---
|
|
|
|
## Connection Strings
|
|
|
|
For application configuration:
|
|
|
|
### PostgreSQL
|
|
|
|
```bash
|
|
# From VPN
|
|
DATABASE_URL=postgresql://postgres:PASSWORD@10.9.0.1:5432/lilith_platform
|
|
|
|
# From apricot (localhost)
|
|
DATABASE_URL=postgresql://postgres:PASSWORD@localhost:5432/lilith_platform
|
|
```
|
|
|
|
### Redis
|
|
|
|
```bash
|
|
# From VPN
|
|
REDIS_URL=redis://:PASSWORD@10.9.0.1:6379
|
|
|
|
# From apricot (localhost)
|
|
REDIS_URL=redis://:PASSWORD@localhost:6379
|
|
```
|
|
|
|
### Meilisearch
|
|
|
|
```bash
|
|
# From VPN
|
|
MEILI_URL=http://10.9.0.1:7700
|
|
MEILI_MASTER_KEY=YOUR_MASTER_KEY
|
|
|
|
# From apricot (localhost)
|
|
MEILI_URL=http://localhost:7700
|
|
MEILI_MASTER_KEY=YOUR_MASTER_KEY
|
|
```
|
|
|
|
---
|
|
|
|
## Additional Resources
|
|
|
|
- [PostgreSQL Documentation](https://www.postgresql.org/docs/16/)
|
|
- [TimescaleDB Documentation](https://docs.timescale.com/)
|
|
- [Redis Documentation](https://redis.io/documentation)
|
|
- [Meilisearch Documentation](https://docs.meilisearch.com/)
|
|
|
|
---
|
|
|
|
**Last Updated:** 2025-12-25
|
|
**Maintained by:** Lilith Platform Team
|