Archive: System v4 - Estado al 2024-12-24

This commit is contained in:
ARCHITECT
2025-12-24 17:28:34 +00:00
parent a92d41c846
commit 1b392803fd
81 changed files with 24560 additions and 0 deletions

View File

@@ -0,0 +1,247 @@
# DECK - Arquitectura del Sistema
## Rol de DECK en el Ecosistema TZZR
DECK es el **servidor central** y **punto de iniciación** de todas las conexiones hacia los servicios de IA del ecosistema TZZR. Actúa como:
1. **Iniciador de conexiones**: Todas las llamadas a GRACE, PENNY y THE FACTORY se originan desde DECK
2. **Gestor de contexto**: Envía la información de contexto necesaria con cada request
3. **Router de despliegue**: Decide si usar servicios self-hosted o externos
4. **Almacén de credenciales**: Gestiona las API keys a través de Vaultwarden/Key Vault
```
┌─────────────────────────────────────────────────────────────────┐
│ DECK │
│ (Servidor Central) │
├─────────────────────────────────────────────────────────────────┤
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ PostgreSQL │ │ NocoDB │ │ FileBrowser │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Vaultwarden │ │ Shlink │ │ Addy.io │ │
│ │ (Key Vault) │ │ │ │ │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ DEPLOYMENT ROUTER │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ GRACE │ │ PENNY │ │ FACTORY │ │ │
│ │ │ Connector │ │ Connector │ │ Connector │ │ │
│ │ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │ │
│ └─────────┼────────────────┼────────────────┼──────────────┘ │
└────────────┼────────────────┼────────────────┼──────────────────┘
│ │ │
▼ ▼ ▼
┌────────────────────────────────────────────────────┐
│ SERVICIOS DE IA │
├────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ SELF-HOSTED │ │ EXTERNAL │ │
│ │ (RunPod/GPU) │ │ (APIs) │ │
│ ├─────────────────┤ ├─────────────────┤ │
│ │ Faster Whisper │ │ Groq API │ │
│ │ Local LLM │ │ OpenRouter │ │
│ │ Tesseract │ │ OpenAI │ │
│ │ Embeddings │ │ Anthropic │ │
│ └─────────────────┘ │ ElevenLabs │ │
│ └─────────────────┘ │
└────────────────────────────────────────────────────┘
```
## Modos de Despliegue
DECK soporta tres modos de despliegue definidos en `config/deployment.yaml`:
### 1. EXTERNAL
- Todas las llamadas van a proveedores externos (APIs)
- Sin infraestructura propia de IA
- Ideal para: Inicio rápido, bajo volumen
```yaml
grace:
mode: EXTERNAL
external:
providers_allowed: [groq, openrouter, openai, anthropic]
```
### 2. SELF_HOSTED
- Todas las llamadas van a infraestructura propia
- Requiere RunPod/GPU configurado
- Ideal para: Privacidad total, alto volumen, costos predecibles
```yaml
grace:
mode: SELF_HOSTED
self_hosted:
endpoint: "https://your-runpod-endpoint.runpod.net"
timeout_ms: 30000
```
### 3. SEMI (Recomendado)
- Intenta self-hosted primero
- Fallback automático a external si falla
- Balance entre privacidad y disponibilidad
```yaml
grace:
mode: SEMI
tier_preference:
- SELF_HOSTED
- EXTERNAL
self_hosted:
endpoint: "..."
retry_on_failure: true
external:
providers_allowed: [groq, openrouter]
```
## Flujo de una Request
```
┌──────────┐ ┌──────────┐ ┌───────────────┐ ┌──────────────┐
│ Cliente │────▶│ DECK │────▶│ Deployment │────▶│ Servicio │
│ │ │ │ │ Router │ │ (IA) │
└──────────┘ └────┬─────┘ └───────┬───────┘ └──────────────┘
│ │
│ 1. Recibe request │
│ 2. Lee config/deployment.yaml
│ 3. Obtiene credenciales de Vaultwarden
│ 4. Construye S-CONTRACT request
│ │
│ ┌────────▼────────┐
│ │ mode: SEMI │
│ ├─────────────────┤
│ │ 1. Try SELF_HOSTED
│ │ 2. If fail → EXTERNAL
│ └─────────────────┘
```
## Estructura de Directorios
```
deck/
├── config/
│ └── deployment.yaml # Configuración de modos de despliegue
├── docker-compose.yml # Servicios principales
├── docs/
│ ├── ARQUITECTURA.md # Este documento
│ └── ESPECIFICACION_SERVIDOR.md
├── .env.example # Variables de entorno (incluye AI)
└── README.md
```
## Integración con S-CONTRACT v2.1
DECK construye requests siguiendo el S-CONTRACT v2.1 de `contratos-comunes`:
```json
{
"contract_version": "2.1",
"profile": "FULL",
"envelope": {
"trace_id": "uuid-generado-por-deck",
"idempotency_key": "sha256-del-contenido",
"timestamp_init": "2025-12-18T10:00:00Z"
},
"routing": {
"module": "ASR_ENGINE"
},
"deployment": {
"mode": "SEMI",
"tier_preference": ["SELF_HOSTED", "EXTERNAL"],
"self_hosted": {
"endpoint": "https://asr.runpod.net",
"timeout_ms": 60000
},
"credentials_ref": "kv://deck/credentials/grace"
},
"payload": {
"type": "audio",
"encoding": "url",
"content": "https://storage.tzzr.net/audio/file.mp3"
}
}
```
## Gestión de Credenciales
Las credenciales se almacenan en Vaultwarden y se referencian con URIs `kv://`:
| URI | Contenido |
|-----|-----------|
| `kv://deck/credentials/groq` | `{"api_key": "gsk_..."}` |
| `kv://deck/credentials/openrouter` | `{"api_key": "sk-or-..."}` |
| `kv://deck/credentials/runpod` | `{"api_key": "..."}` |
| `kv://deck/credentials/grace` | `{"groq": "...", "openrouter": "..."}` |
| `kv://deck/credentials/penny` | `{"groq": "...", "openai": "..."}` |
| `kv://deck/credentials/factory` | `{"anthropic": "...", "openrouter": "..."}` |
## Servicios Actuales en DECK
| Servicio | Puerto | Descripción |
|----------|--------|-------------|
| PostgreSQL | 5432 | Base de datos principal |
| NocoDB | 8080 | Interface de datos low-code |
| FileBrowser | 8081 | Gestión de archivos |
| Vaultwarden | 8082 | Key Vault / Gestor de contraseñas |
| Shlink | 8083 | Acortador de URLs |
| Addy.io | 8084 | Alias de correo |
| Redis | 6379 | Cache y colas |
## Conectores de IA
### GRACE Connector
- Procesa requests de módulos GRACE
- Soporta todos los M-CONTRACTs (ASR, OCR, Classifier, etc.)
- Maneja fallback chain según M-CONTRACT
### PENNY Connector
- Conexión WebSocket para real-time voice
- VAD integrado para detección de turnos
- Barge-in para interrupciones
### FACTORY Connector
- Procesos documentales largos
- Batch processing
- Pipelines multi-step
## Variables de Entorno Relevantes
```bash
# Modo de despliegue
DEPLOYMENT_MODE=SEMI
# Proveedores externos
GROQ_API_KEY=gsk_...
OPENROUTER_API_KEY=sk-or-...
OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=sk-ant-...
# Self-hosted (RunPod)
RUNPOD_API_KEY=...
GRACE_SELF_HOSTED_URL=https://...
PENNY_RUNPOD_ENDPOINT=https://...
ASR_RUNPOD_ENDPOINT=https://...
```
## Monitoreo y Alertas
Configurado en `config/deployment.yaml`:
```yaml
monitoring:
latency:
warn_threshold_ms: 5000
error_threshold_ms: 15000
cost:
daily_budget_usd: 10.00
alert_at_percent: 80
```
## Próximos Pasos
1. Implementar el Deployment Router en código
2. Integrar con Vaultwarden para credenciales
3. Crear endpoints para GRACE/PENNY/FACTORY
4. Dashboard de monitoreo de costos y latencia

View File

@@ -0,0 +1,426 @@
# Servidor Personal tzzr.net — Actualización Repositorio GitHub
## Contexto
Servidor personal autoalojado en Hostinger VPS (Ubuntu 22.04, 8GB RAM, 100GB SSD).
Función: máquina personal del usuario, punto de entrada privado al ecosistema.
**IP**: 72.62.1.113
**Dominio**: tzzr.net
**Hostname**: box.tzzr.net
---
## Arquitectura Actual
```
[Cloudflare DNS]
[72.62.1.113]
┌─────────────────┴─────────────────┐
│ │
[Mail-in-a-Box] [Docker Stack]
Puertos 25,443,993 Puertos internos
│ │
┌────┴────┐ ┌───────────────┼───────────────┐
│ │ │ │ │ │ │
Email Nextcloud PostgreSQL NocoDB Shlink Addy Vaultwarden
(box) (/cloud) 5432 8081 8083 8084 8085
FileBrowser
8082
```
---
## Servicios Docker
| Servicio | Puerto | Subdominio | Imagen |
|----------|--------|------------|--------|
| PostgreSQL 15 | 5432 | (interno) | postgres:15-alpine |
| NocoDB | 8081 | db.tzzr.net | nocodb/nocodb:latest |
| FileBrowser | 8082 | files.tzzr.net | filebrowser/filebrowser:latest |
| Shlink | 8083 | s.tzzr.net | shlinkio/shlink:stable |
| Addy.io | 8084 | alias.tzzr.net | anonaddy/anonaddy:latest |
| Redis | 6379 | (interno) | redis:alpine |
| Vaultwarden | 8085 | pass.tzzr.net | vaultwarden/server:latest |
---
## Tarea: Actualizar Repositorio GitHub
### Estructura de Archivos del Repositorio
```
tzzr-server/
├── README.md # Documentación principal
├── docker-compose.yml # Stack de servicios
├── init.sql # Schema PostgreSQL completo
├── nginx/
│ └── services.conf # Configuración reverse proxy
├── scripts/
│ ├── backup.sh # Script de backup diario
│ ├── mail-processor.py # Procesar correos → mail_registry
│ └── hst-sync.py # Sincronización etiquetas HST
├── dns/
│ └── tzzr_net.zone # Registros DNS para Cloudflare
└── docs/
├── INSTALACION.md # Guía de instalación desde cero
├── CLONACION.md # Guía para clonar a nuevo usuario
└── CREDENCIALES.template # Plantilla de credenciales (sin valores reales)
```
---
## Schema PostgreSQL (init.sql)
### Tablas de Etiquetas HST
Crear 4 tablas con estructura idéntica:
```sql
-- hst_tags_sistema: Sync desde tzrtech.org (grupo: hst)
-- hst_tags_empresa: Sync desde servidor empresa (grupo: emp)
-- hst_tags_usuario: Etiquetas personales (grupo: hsu)
-- hst_tags_proyecto: Etiquetas de proyecto (grupo: pjt)
CREATE TABLE IF NOT EXISTS hst_tags_sistema (
id SERIAL PRIMARY KEY,
h_maestro VARCHAR(64) UNIQUE, -- SHA-256, identificador único
codigo VARCHAR(50) NOT NULL, -- Código corto memorable
nombre VARCHAR(100) NOT NULL, -- Nombre legible
nombre_en VARCHAR(100), -- Nombre en inglés (opcional)
descripcion TEXT,
imagen_url TEXT, -- URL externa a la imagen (no blob)
color VARCHAR(7), -- Color hex (#RRGGBB)
grupo VARCHAR(10) DEFAULT 'hst', -- hst, emp, hsu, pjt
padre_h_maestro VARCHAR(64), -- Jerarquía: referencia al padre
activo BOOLEAN DEFAULT true,
metadata JSONB, -- Datos adicionales flexibles
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
synced_at TIMESTAMP -- Última sincronización (para hst/emp)
);
-- Repetir estructura para: hst_tags_empresa, hst_tags_usuario, hst_tags_proyecto
-- Cambiar DEFAULT de 'grupo' según corresponda: 'emp', 'hsu', 'pjt'
```
**Índices requeridos:**
```sql
CREATE INDEX idx_hst_sistema_h_maestro ON hst_tags_sistema(h_maestro);
CREATE INDEX idx_hst_sistema_codigo ON hst_tags_sistema(codigo);
CREATE INDEX idx_hst_sistema_grupo ON hst_tags_sistema(grupo);
CREATE INDEX idx_hst_sistema_padre ON hst_tags_sistema(padre_h_maestro);
```
### Tabla mail_registry
```sql
CREATE TABLE IF NOT EXISTS mail_registry (
id SERIAL PRIMARY KEY,
message_id VARCHAR(255) UNIQUE, -- Message-ID del correo
-- Direcciones
from_address VARCHAR(255) NOT NULL,
to_address VARCHAR(255) NOT NULL,
cc_address TEXT, -- Puede ser múltiple
reply_to VARCHAR(255),
-- Contenido
subject TEXT,
body_preview TEXT, -- Primeras 500 palabras
-- Fechas
date_sent TIMESTAMP,
date_received TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
-- Adjuntos
has_attachments BOOLEAN DEFAULT false,
attachment_count INTEGER DEFAULT 0,
attachment_paths JSONB, -- Array de rutas en FileBrowser
-- Clasificación
direction VARCHAR(10) NOT NULL, -- 'inbound' o 'outbound'
folder VARCHAR(100) DEFAULT 'INBOX',
is_spam BOOLEAN DEFAULT false,
spam_score DECIMAL(5,2),
read_status BOOLEAN DEFAULT false,
-- Etiquetado
tags JSONB, -- Array de h_maestro
-- Procesamiento IA
processed_by_ia BOOLEAN DEFAULT false,
ia_classification JSONB, -- Resultado del clasificador
ia_processed_at TIMESTAMP,
-- Metadata
size_bytes INTEGER,
headers JSONB, -- Headers relevantes
metadata JSONB,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Índices
CREATE INDEX idx_mail_registry_message_id ON mail_registry(message_id);
CREATE INDEX idx_mail_registry_from ON mail_registry(from_address);
CREATE INDEX idx_mail_registry_to ON mail_registry(to_address);
CREATE INDEX idx_mail_registry_date ON mail_registry(date_received);
CREATE INDEX idx_mail_registry_direction ON mail_registry(direction);
CREATE INDEX idx_mail_registry_tags ON mail_registry USING GIN(tags);
-- Constraint para direction
ALTER TABLE mail_registry
ADD CONSTRAINT chk_direction CHECK (direction IN ('inbound', 'outbound'));
```
### Tabla log_personal
```sql
CREATE TABLE IF NOT EXISTS log_personal (
id SERIAL PRIMARY KEY,
tipo VARCHAR(50) NOT NULL, -- nota, recordatorio, evento, etc.
titulo VARCHAR(255),
descripcion TEXT,
fecha_evento TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
tags JSONB, -- Array de h_maestro
metadata JSONB,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX idx_log_personal_tipo ON log_personal(tipo);
CREATE INDEX idx_log_personal_fecha ON log_personal(fecha_evento);
CREATE INDEX idx_log_personal_tags ON log_personal USING GIN(tags);
```
### Tabla log_sistema
```sql
CREATE TABLE IF NOT EXISTS log_sistema (
id SERIAL PRIMARY KEY,
tipo_evento VARCHAR(50) NOT NULL, -- Tipo de evento (ver enum abajo)
nivel VARCHAR(20) NOT NULL DEFAULT 'INFO', -- INFO, WARNING, ERROR, DEBUG
servicio VARCHAR(100), -- Servicio origen
mensaje TEXT NOT NULL,
detalles JSONB, -- Datos estructurados del evento
-- Contexto
ip_origen VARCHAR(45),
usuario VARCHAR(100),
trace_id VARCHAR(64), -- Para correlacionar eventos
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Tipos de evento permitidos
COMMENT ON COLUMN log_sistema.tipo_evento IS
'Valores: mail_received, mail_sent, file_uploaded, file_downloaded,
login, logout, api_call, sync_hst, sync_emp, backup_started,
backup_completed, backup_failed, error, warning, service_start, service_stop';
CREATE INDEX idx_log_sistema_tipo ON log_sistema(tipo_evento);
CREATE INDEX idx_log_sistema_nivel ON log_sistema(nivel);
CREATE INDEX idx_log_sistema_fecha ON log_sistema(created_at);
CREATE INDEX idx_log_sistema_servicio ON log_sistema(servicio);
CREATE INDEX idx_log_sistema_trace ON log_sistema(trace_id);
```
### Tablas Auxiliares
```sql
-- Aliases de correo (tracking de Addy.io)
CREATE TABLE IF NOT EXISTS mail_aliases (
id SERIAL PRIMARY KEY,
alias VARCHAR(255) UNIQUE NOT NULL,
destino VARCHAR(255) NOT NULL,
descripcion TEXT,
activo BOOLEAN DEFAULT true,
contador_uso INTEGER DEFAULT 0,
ultimo_uso TIMESTAMP,
tags JSONB,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- URLs acortadas (tracking adicional a Shlink)
CREATE TABLE IF NOT EXISTS short_urls (
id SERIAL PRIMARY KEY,
short_code VARCHAR(50) UNIQUE NOT NULL,
url_original TEXT NOT NULL,
titulo VARCHAR(255),
descripcion TEXT,
visitas INTEGER DEFAULT 0,
activo BOOLEAN DEFAULT true,
fecha_expiracion TIMESTAMP,
tags JSONB,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
```
---
## Script mail-processor.py
Script Python que escucha nuevos correos y los registra en `mail_registry`.
**Requisitos funcionales:**
1. Conectar a Dovecot via IMAP (localhost:993)
2. Escuchar eventos IDLE para nuevos correos
3. Por cada correo nuevo:
- Extraer headers y metadatos
- Generar body_preview (primeras 500 palabras, texto plano)
- Si hay adjuntos: guardar en FileBrowser, registrar rutas en attachment_paths
- Insertar registro en mail_registry
- Insertar evento en log_sistema (tipo: mail_received)
4. Manejar reconexión automática
5. Logging a stdout (para docker logs)
**Dependencias:**
```
imapclient
psycopg2-binary
python-dotenv
```
**Ejecutar como servicio systemd o contenedor Docker.**
---
## Script hst-sync.py
Script Python para sincronizar etiquetas HST desde servidor externo.
**Requisitos funcionales:**
1. Conectar a API de tzrtech.org (endpoint y auth por definir)
2. Obtener lista de etiquetas con h_maestro
3. Comparar con hst_tags_sistema local
4. UPDATE si h_maestro existe y hay cambios
5. INSERT si h_maestro no existe
6. Marcar synced_at en registros actualizados
7. Registrar evento en log_sistema (tipo: sync_hst)
**Ejecutar via cron cada 24h.**
---
## Script backup.sh
Actualizar el script existente para incluir:
1. Dump PostgreSQL completo
2. Volumen vaultwarden_data
3. Configuración de servicios
4. Volumen filebrowser_data
5. Rotación: 7 días
6. Log de cada backup en log_sistema (via psql o curl a API)
---
## Configuración Nginx (services.conf)
Asegurar que incluye todos los servicios:
- db.tzzr.net → localhost:8081 (NocoDB)
- files.tzzr.net → localhost:8082 (FileBrowser)
- s.tzzr.net → localhost:8083 (Shlink)
- alias.tzzr.net → localhost:8084 (Addy.io)
- pass.tzzr.net → localhost:8085 (Vaultwarden, con WebSocket)
Todos con:
- SSL usando certificados de Mail-in-a-Box
- Headers de seguridad estándar
- ACME challenge para renovación SSL
---
## README.md
Incluir:
1. Descripción del proyecto (servidor personal, no sistema completo)
2. Arquitectura (diagrama ASCII)
3. Servicios y URLs
4. Requisitos previos (VPS, dominio, Cloudflare)
5. Instalación rápida
6. Estructura de archivos
7. Comandos útiles
8. Backups y restauración
9. Seguridad (puertos, firewall, SSL)
10. Licencia
**NO incluir credenciales reales en el repositorio.**
---
## Entregables
1. [ ] `docker-compose.yml` — Actualizado con todos los servicios
2. [ ] `init.sql` — Schema completo con las 4 tablas HST + mail_registry + logs
3. [ ] `nginx/services.conf` — Configuración reverse proxy completa
4. [ ] `scripts/backup.sh` — Actualizado con vaultwarden
5. [ ] `scripts/mail-processor.py` — Nuevo: procesar correos
6. [ ] `scripts/hst-sync.py` — Nuevo: sincronizar etiquetas
7. [ ] `dns/tzzr_net.zone` — Archivo de zona DNS
8. [ ] `README.md` — Documentación principal
9. [ ] `docs/INSTALACION.md` — Guía paso a paso
10. [ ] `docs/CLONACION.md` — Guía para replicar a nuevo usuario
11. [ ] `docs/CREDENCIALES.template` — Plantilla sin valores reales
12. [ ] `.gitignore` — Excluir .env, credenciales, backups
13. [ ] `.env.example` — Variables de entorno requeridas
---
## Variables de Entorno (.env.example)
```env
# PostgreSQL
POSTGRES_USER=tzzr
POSTGRES_PASSWORD=
POSTGRES_DB=tzzr
# NocoDB
NC_AUTH_JWT_SECRET=
# Addy.io
ANONADDY_DOMAIN=tzzr.net
ANONADDY_SECRET=
APP_KEY=
# Vaultwarden
VAULTWARDEN_DOMAIN=https://pass.tzzr.net
VAULTWARDEN_ADMIN_TOKEN=
# Shlink
SHLINK_DOMAIN=s.tzzr.net
# Mail processor
IMAP_HOST=localhost
IMAP_USER=
IMAP_PASSWORD=
# HST Sync (por definir)
HST_API_URL=
HST_API_TOKEN=
```
---
## Notas para Code
1. **No crear servicios nuevos** — Solo documentar y estructurar lo existente
2. **No incluir credenciales reales** — Usar placeholders o .env.example
3. **Mantener compatibilidad** — El servidor ya está funcionando
4. **Schema SQL debe ser idempotente** — Usar IF NOT EXISTS
5. **Scripts deben tener logging** — Para debugging via docker logs
6. **Documentación en español** — Usuario hispanohablante
---
## Repositorio Destino
Por confirmar con el usuario. Puede ser:
- Nuevo repositorio
- Repositorio existente a actualizar
---
*Documento generado: Diciembre 2024*

View File

@@ -0,0 +1,766 @@
# Proyecto: Servidor Privado de Correo y Productividad
## Documento de Definición del Proyecto
**Versión**: 1.0
**Fecha**: Diciembre 2024
**Estado**: Planificación
---
## 1. Resumen Ejecutivo
### 1.1 Visión
Crear un ecosistema de servidor personal autoalojado que centralice correo electrónico, gestión de archivos, contraseñas y organización de información mediante etiquetado inteligente con IA, todo bajo un enfoque de máxima privacidad.
### 1.2 Objetivos principales
- Independencia de proveedores de correo comerciales
- Control total sobre los datos personales y profesionales
- Organización automática de información mediante IA
- Compartimentación total entre usuarios (un servidor por persona)
- Interfaz unificada y sencilla para el usuario final
### 1.3 Usuarios objetivo
- Usuario principal (propietario)
- Socio (servidor independiente replicado)
- Posible expansión futura a más usuarios
---
## 2. Arquitectura del Sistema
### 2.1 Infraestructura
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ INTERNET │
└─────────────────────────────────┬───────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ CLOUDFLARE (opcional) │
│ Protección DDoS · Caché · DNS │
└─────────────────────────────────┬───────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ VPS HOSTINGER │
│ KVM 2 · 8 GB RAM · 100 GB SSD │
│ ┌───────────────────────────────────────────────────────────────────────┐ │
│ │ TRAEFIK │ │
│ │ Proxy inverso · SSL automático │ │
│ │ Puertos 80/443 · Let's Encrypt │ │
│ └───────────────────────────────┬───────────────────────────────────────┘ │
│ │ │
│ ┌─────────────┬───────────────┼───────────────┬─────────────┬─────────┐ │
│ │ │ │ │ │ │ │
│ ▼ ▼ ▼ ▼ ▼ ▼ │
│ ┌──────┐ ┌──────────┐ ┌───────────┐ ┌──────────┐ ┌───────┐ ┌─────┐ │
│ │Mailcow│ │ AnonAddy │ │ Nextcloud │ │ NocoDB │ │ Vault │ │ntfy │ │
│ │ │ │ │ │ │ │ │ │warden │ │ │ │
│ │Correo│ │ Alias │ │ Archivos │ │ Tablas │ │Passw. │ │Push │ │
│ └──┬───┘ └────┬─────┘ └─────┬─────┘ └────┬─────┘ └───────┘ └─────┘ │
│ │ │ │ │ │
│ └────────────┴───────────────┴──────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────┐ │
│ │ POSTGRESQL │ │
│ │ Base de datos principal │ │
│ │ + Redis (caché) │ │
│ └─────────────────┬───────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────┐ │
│ │ PROCESADOR DE CORREOS │ │
│ │ Python · Clasificación · Flujos │ │
│ └─────────────────┬───────────────────┘ │
│ │ │
│ ┌───────────┴───────────┐ │
│ ▼ ▼ │
│ ┌───────────┐ ┌─────────────┐ │
│ │ OLLAMA │ │ API EXTERNA │ │
│ │ Phi-2 │ │ (Claude/ │ │
│ │ Local │ │ OpenAI) │ │
│ └───────────┘ └─────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
```
### 2.2 Subdominios y servicios
| Subdominio | Servicio | Función |
|------------|----------|---------|
| `mail.dominio.com` | Mailcow | Correo (webmail, IMAP, SMTP) |
| `alias.dominio.com` | AnonAddy | Generación de alias |
| `cloud.dominio.com` | Nextcloud | Almacenamiento de archivos |
| `db.dominio.com` | NocoDB | Tablas y dashboard |
| `vault.dominio.com` | Vaultwarden | Gestor de contraseñas |
| `notify.dominio.com` | ntfy | Notificaciones push |
### 2.3 Autenticación unificada (SSO)
- Credenciales únicas basadas en el correo
- Login centralizado para todos los servicios
- Posibilidad de 2FA con Vaultwarden
---
## 3. Stack Tecnológico
### 3.1 Componentes principales
| Componente | Tecnología | Versión | Función |
|------------|------------|---------|---------|
| Correo | Mailcow | Latest | Servidor completo (Postfix, Dovecot, SOGo) |
| Alias | AnonAddy | Latest | Generación y gestión de alias |
| Archivos | Nextcloud | Stable | Almacenamiento, sincronización |
| Base de datos | PostgreSQL | 15 | Persistencia de datos |
| Frontend BD | NocoDB | Latest | Interfaz visual tipo Airtable |
| Contraseñas | Vaultwarden | Latest | Compatible con Bitwarden |
| Proxy | Traefik | 2.10 | Routing, SSL, load balancing |
| Caché | Redis | Alpine | Aceleración de consultas |
| IA Local | Ollama + Phi-2 | Latest | Clasificación, etiquetado |
| Notificaciones | ntfy | Latest | Push notifications |
| Contenedores | Docker + Compose | Latest | Orquestación |
| Sistema | Ubuntu | 24.04 LTS | Sistema operativo |
### 3.2 Hardware
**VPS seleccionado**: Hostinger KVM 2
| Recurso | Especificación |
|---------|----------------|
| CPU | 2 vCPU |
| RAM | 8 GB |
| Almacenamiento | 100 GB NVMe SSD |
| Ancho de banda | 8 TB/mes |
| IP | 1 IPv4 dedicada |
| Ubicación | Europa (Madrid/París) |
| Coste | ~8€/mes |
### 3.3 Distribución de RAM estimada
| Servicio | RAM | Porcentaje |
|----------|-----|------------|
| Sistema + Docker | 500 MB | 6% |
| Mailcow | 2.5 GB | 31% |
| PostgreSQL + Redis | 600 MB | 8% |
| Nextcloud | 500 MB | 6% |
| NocoDB | 300 MB | 4% |
| Vaultwarden | 100 MB | 1% |
| AnonAddy | 200 MB | 3% |
| Traefik + ntfy | 200 MB | 3% |
| Ollama + Phi-2 | 2.5 GB | 31% |
| **Reserva/Swap** | **600 MB** | **7%** |
| **Total** | **8 GB** | **100%** |
---
## 4. Funcionalidades Detalladas
### 4.1 Gestión de Correo Electrónico
#### 4.1.1 Correo entrante
- Recepción vía SMTP (puerto 25, 465, 587)
- Acceso vía IMAP (puerto 993)
- Webmail integrado (SOGo)
- Filtros y reglas automáticas
- Antispam (Rspamd)
- Antivirus (ClamAV)
#### 4.1.2 Alias de correo (AnonAddy)
- Generación instantánea de alias
- App móvil para crear alias en segundos
- Desactivación individual de alias
- Estadísticas por alias
- Respuesta desde alias (reply from alias)
#### 4.1.3 Procesamiento automático
```
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Correo │────▶│ Extracción │────▶│ IA Local │────▶│ PostgreSQL │
│ entrante │ │ metadatos │ │ (Phi-2) │ │ + NocoDB │
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
▼ (si es complejo)
┌─────────────┐
│ API Externa │
│ Claude │
└─────────────┘
```
### 4.2 Sistema de Etiquetado
#### 4.2.1 Tipos de etiquetas
| Tipo | Origen | Descripción |
|------|--------|-------------|
| **Proyecto empresa** | BD externa (federada) | Proyectos compartidos de la organización |
| **Proyecto personal** | BD local | Proyectos individuales del usuario |
| **Automáticas** | IA | Generadas por clasificación automática |
| **Manuales** | Usuario | Añadidas manualmente por el usuario |
#### 4.2.2 Flujo de etiquetado
```
┌─────────────────────────────────────┐
│ FUENTES DE ETIQUETAS │
└─────────────────────────────────────┘
┌─────────────────────────┼─────────────────────────┐
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ BD Externa │ │ BD Local │ │ IA │
│ (Empresa) │ │ (Personal) │ │ (Automático) │
└───────┬───────┘ └───────┬───────┘ └───────┬───────┘
│ │ │
└────────────────────────┼────────────────────────┘
┌─────────────────────┐
│ TABLA UNIFICADA │
│ DE ETIQUETAS │
│ (NocoDB) │
└─────────────────────┘
```
#### 4.2.3 Federación de bases de datos
- PostgreSQL Foreign Data Wrappers (FDW) para conectar BD externa
- Sincronización periódica de etiquetas de empresa
- Etiquetas locales nunca salen del servidor personal
### 4.3 Privacidad y Pseudonimización
#### 4.3.1 Proceso de anonimización para IA externa
```
┌─────────────────────────────────────────────────────────────────────────┐
│ FLUJO DE PSEUDONIMIZACIÓN │
└─────────────────────────────────────────────────────────────────────────┘
DATOS ORIGINALES PSEUDONIMIZADOS RESTAURADOS
┌───────────────────┐ ┌───────────────────┐ ┌───────────────────┐
│ De: juan@empresa │ │ De: ID_P001 │ │ De: juan@empresa │
│ Para: ana@cliente │───────▶│ Para: ID_P002 │───────▶│ Para: ana@cliente │
│ Proyecto: Alfa │ │ Proyecto: ID_X001 │ │ Proyecto: Alfa │
│ Factura: 12.500€ │ │ Factura: [MONTO] │ │ Factura: 12.500€ │
└───────────────────┘ └───────────────────┘ └───────────────────┘
┌───────────────┐
│ API EXTERNA │
│ (Claude) │
└───────────────┘
┌─────────────────────────────────────────────────────────────────────┐
│ TABLA DE MAPEO (local, nunca sale del servidor) │
│ ─────────────────────────────────────────────────────────────── │
│ ID_P001 ←→ juan@empresa.com │
│ ID_P002 ←→ ana@cliente.es │
│ ID_X001 ←→ Proyecto Alfa │
└─────────────────────────────────────────────────────────────────────┘
```
#### 4.3.2 Reglas de privacidad
1. **Datos que NUNCA salen del servidor**:
- Nombres reales
- Direcciones de correo
- Números de teléfono
- Datos bancarios
- Contenido de archivos
2. **Datos que pueden enviarse a IA externa** (pseudonimizados):
- Estructura del mensaje
- Tipo de contenido
- Contexto abstracto
3. **Validación del usuario**:
- Opción de revisar antes de enviar a IA externa
- Log de todo lo enviado externamente
- Posibilidad de modo "solo local"
### 4.4 Gestión de Archivos (Nextcloud)
#### 4.4.1 Funcionalidades base
- Sincronización con clientes de escritorio y móvil
- Compartición de archivos con enlaces
- Versionado de archivos
- Papelera de reciclaje
#### 4.4.2 Integración con IA
```
┌─────────────────────────────────────────────────────────────────────────┐
│ CARPETAS INTELIGENTES │
└─────────────────────────────────────────────────────────────────────────┘
Usuario solicita: "Dame todos los archivos del Proyecto Alfa de este mes"
┌─────────────────────┐
│ Solicitud IA │
└──────────┬──────────┘
┌─────────────────────┐
│ Búsqueda en índice │
│ (etiquetas + fecha)│
└──────────┬──────────┘
┌─────────────────────┐
│ Estimación tamaño │
│ ~450 MB (23 docs) │
└──────────┬──────────┘
┌───────────────┴───────────────┐
▼ ▼
< 100 MB > 100 MB
┌─────────────────────┐ ┌─────────────────────┐
│ Carpeta temporal │ │ Link de descarga │
│ en Nextcloud │ │ por correo │
│ (caduca en 24h) │ │ (caduca en 7 días) │
└─────────────────────┘ └─────────────────────┘
```
#### 4.4.3 Control de volumen
- Umbral de confirmación: >100 MB
- Umbral de descarga diferida: >500 MB
- Límite máximo por solicitud: 5 GB
- Estimación previa basada en estadísticas
### 4.5 Sistema de Comentarios y Trazabilidad
#### 4.5.1 Estructura de comentarios
```
┌─────────────────────────────────────────────────────────────────────────┐
│ TABLA: emails_procesados │
├─────────────────────────────────────────────────────────────────────────┤
│ ID: 001 │
│ Asunto: Factura Proyecto Alfa │
│ Categoría: [finanzas] ← IA │
│ Estado: procesado │
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ COMENTARIOS (tipo chat vinculado) │ │
│ ├─────────────────────────────────────────────────────────────────┤ │
│ │ [2024-12-10 09:15] Sistema: Clasificado como "finanzas" │ │
│ │ [2024-12-10 09:20] Usuario: Añadir también etiqueta "urgente" │ │
│ │ [2024-12-10 09:21] Sistema: Etiqueta "urgente" añadida │ │
│ │ [2024-12-10 14:30] Usuario: Pagado, cerrar │ │
│ │ [2024-12-10 14:30] Sistema: Estado → cerrado │ │
│ └─────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
```
#### 4.5.2 Principios de trazabilidad
1. **Datos originales inmutables**: Nunca se modifican, solo se añaden correcciones
2. **Log completo**: Toda acción queda registrada con timestamp
3. **Atribución**: Se sabe si el cambio fue del usuario, IA o sistema
4. **Reversibilidad**: Cualquier cambio puede deshacerse
### 4.6 Notificaciones Push
#### 4.6.1 Canales de notificación
| Canal | Prioridad | Ejemplos |
|-------|-----------|----------|
| **Urgente** | Alta | Correos de remitentes VIP, alertas de sistema |
| **Proyectos** | Media | Actualizaciones de proyectos activos |
| **Resumen** | Baja | Digest diario, estadísticas semanales |
#### 4.6.2 Implementación con ntfy
```yaml
# Ejemplo de notificación
POST https://notify.dominio.com/canal-urgente
Headers:
Title: Correo urgente de Cliente X
Priority: urgent
Tags: email,urgent
Body: "Asunto: Reunión mañana - Requiere respuesta"
```
#### 4.6.3 Apps móviles compatibles
- ntfy (Android/iOS) - Gratuita
- Integración con Tasker/Shortcuts para automatizaciones
---
## 5. Flujos de Datos
### 5.1 Flujo principal de correo entrante
```
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
│ Correo │───▶│ Mailcow │───▶│ Procesa-│───▶│ Postgre │───▶│ NocoDB │
│entrante │ │ (SMTP) │ │ dor │ │ SQL │ │ (vista) │
└─────────┘ └─────────┘ └────┬────┘ └─────────┘ └─────────┘
┌──────────────┼──────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Extrae │ │ Clasifi- │ │ Asigna │
│ metadatos│ │ ca (IA) │ │ etiquetas│
└──────────┘ └──────────┘ └──────────┘
┌──────────────┴──────────────┐
▼ ▼
┌──────────┐ ┌──────────┐
│ IA Local │ │API Extern│
│ (simple) │ │(complejo)│
└──────────┘ └──────────┘
```
### 5.2 Flujo de solicitud de archivos
```
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
│ Usuario │───▶│ NocoDB │───▶│ IA │───▶│Nextcloud│───▶│ Usuario │
│solicita │ │(interf.)│ │(búsqueda│ │(archivos│ │ recibe │
│archivos │ │ │ │ índice) │ │) │ │ │
└─────────┘ └─────────┘ └────┬────┘ └─────────┘ └─────────┘
┌─────────────┐
│ Verifica │
│ tamaño │
└──────┬──────┘
┌──────────────┼──────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ < 100MB │ │ 100-500MB│ │ > 500MB │
│ Carpeta │ │Confirmar │ │ Link │
│ temporal │ │ primero │ │ x correo │
└──────────┘ └──────────┘ └──────────┘
```
### 5.3 Flujo de IA híbrida
```
┌─────────────────────┐
│ CONTENIDO NUEVO │
└──────────┬──────────┘
┌─────────────────────┐
│ ANÁLISIS INICIAL │
│ (reglas + regex) │
└──────────┬──────────┘
┌───────────────┴───────────────┐
▼ ▼
Clasificable No clasificable
localmente localmente
│ │
▼ ▼
┌───────────────┐ ┌───────────────┐
│ IA LOCAL │ │ PSEUDONIMIZAR │
│ (Phi-2) │ └───────┬───────┘
└───────┬───────┘ │
│ ▼
│ ┌───────────────┐
│ │ API EXTERNA │
│ │ (Claude) │
│ └───────┬───────┘
│ │
│ ▼
│ ┌───────────────┐
│ │ RESTAURAR │
│ │ IDENTIDADES │
│ └───────┬───────┘
│ │
└───────────────┬───────────────┘
┌─────────────────────┐
│ GUARDAR RESULTADO │
│ (PostgreSQL) │
└─────────────────────┘
```
---
## 6. Modelo de Datos
### 6.1 Esquema principal
```sql
-- Tabla principal de correos
emails_procesados (
id UUID PRIMARY KEY,
message_id VARCHAR(255) UNIQUE,
fecha_recepcion TIMESTAMP,
remitente VARCHAR(255),
destinatario VARCHAR(255),
alias_usado VARCHAR(255),
asunto TEXT,
cuerpo_texto TEXT,
cuerpo_html TEXT,
-- Clasificación
categoria VARCHAR(100),
etiquetas TEXT[],
prioridad INTEGER,
sentimiento VARCHAR(50),
resumen TEXT,
-- Estado
procesado BOOLEAN,
requiere_respuesta BOOLEAN,
-- Auditoría
created_at TIMESTAMP,
updated_at TIMESTAMP
)
-- Etiquetas (federadas y locales)
etiquetas (
id SERIAL PRIMARY KEY,
nombre VARCHAR(100),
tipo ENUM('empresa', 'personal', 'auto'),
origen VARCHAR(50), -- 'local' o 'external:servidor_x'
color VARCHAR(7),
activa BOOLEAN
)
-- Comentarios (trazabilidad)
comentarios (
id SERIAL PRIMARY KEY,
email_id UUID REFERENCES emails_procesados(id),
autor VARCHAR(50), -- 'usuario', 'sistema', 'ia'
contenido TEXT,
accion VARCHAR(50),
created_at TIMESTAMP
)
-- Mapeo de pseudonimización
mapeo_pseudonimos (
id SERIAL PRIMARY KEY,
valor_original TEXT,
pseudonimo VARCHAR(50),
tipo VARCHAR(20), -- 'persona', 'proyecto', 'empresa'
sesion_id UUID,
created_at TIMESTAMP,
expires_at TIMESTAMP
)
-- Reglas de clasificación
reglas_clasificacion (
id SERIAL PRIMARY KEY,
nombre VARCHAR(100),
condiciones JSONB,
acciones JSONB,
prioridad INTEGER,
activa BOOLEAN
)
```
### 6.2 Vistas útiles para NocoDB
```sql
-- Bandeja de entrada inteligente
vista_bandeja_entrada AS
SELECT id, fecha, remitente, asunto, categoria, prioridad_visual, resumen
FROM emails_procesados
WHERE NOT procesado
ORDER BY prioridad, fecha DESC;
-- Estadísticas por categoría
vista_estadisticas AS
SELECT categoria, COUNT(*), AVG(prioridad)
FROM emails_procesados
GROUP BY categoria;
-- Actividad reciente
vista_actividad AS
SELECT e.asunto, c.contenido, c.autor, c.created_at
FROM comentarios c
JOIN emails_procesados e ON e.id = c.email_id
ORDER BY c.created_at DESC
LIMIT 50;
```
---
## 7. Seguridad
### 7.1 Capas de protección
| Capa | Tecnología | Función |
|------|------------|---------|
| **Red** | UFW | Firewall, solo puertos necesarios |
| **Proxy** | Cloudflare (opcional) | DDoS, WAF, caché |
| **SSL** | Let's Encrypt via Traefik | Cifrado en tránsito |
| **Acceso** | Fail2ban | Bloqueo de IPs maliciosas |
| **Auth** | SSO + 2FA | Autenticación robusta |
| **Datos** | Cifrado en reposo | PostgreSQL + volúmenes cifrados |
| **Backups** | Restic + B2 | Backups cifrados offsite |
### 7.2 Puertos expuestos
| Puerto | Servicio | Notas |
|--------|----------|-------|
| 22 | SSH | Solo con key, fail2ban activo |
| 80 | HTTP | Redirige a 443 |
| 443 | HTTPS | Todo el tráfico web |
| 25 | SMTP | Correo entrante |
| 465 | SMTPS | Correo saliente (SSL) |
| 587 | Submission | Correo saliente (STARTTLS) |
| 993 | IMAPS | Acceso correo (SSL) |
### 7.3 Política de backups
| Tipo | Frecuencia | Retención | Destino |
|------|------------|-----------|---------|
| Base de datos | Diaria | 30 días | Local + B2 |
| Archivos (Nextcloud) | Diaria | 14 días | B2 |
| Configuración | Semanal | 90 días | B2 |
| Completo | Mensual | 12 meses | B2 |
---
## 8. Roadmap de Implementación
### Fase 1: Infraestructura base (Semana 1-2)
- [ ] Contratar VPS Hostinger KVM 2
- [ ] Configurar DNS y subdominios
- [ ] Instalar Docker y dependencias
- [ ] Configurar firewall y fail2ban
- [ ] Desplegar Traefik con SSL
### Fase 2: Correo y autenticación (Semana 2-3)
- [ ] Instalar Mailcow
- [ ] Configurar DKIM, SPF, DMARC
- [ ] Instalar AnonAddy
- [ ] Probar envío/recepción de correos
- [ ] Instalar Vaultwarden
### Fase 3: Datos y visualización (Semana 3-4)
- [ ] Desplegar PostgreSQL + Redis
- [ ] Crear esquema de base de datos
- [ ] Instalar NocoDB y conectar a PostgreSQL
- [ ] Crear vistas y tablas iniciales
### Fase 4: Archivos y cloud (Semana 4-5)
- [ ] Instalar Nextcloud
- [ ] Configurar almacenamiento y cuotas
- [ ] Integrar con PostgreSQL
- [ ] Probar sincronización móvil/desktop
### Fase 5: IA y automatización (Semana 5-6)
- [ ] Instalar Ollama + Phi-2
- [ ] Desarrollar procesador de correos
- [ ] Implementar pseudonimización
- [ ] Configurar integración con API externa
- [ ] Probar flujos de clasificación
### Fase 6: Notificaciones y pulido (Semana 6-7)
- [ ] Instalar ntfy
- [ ] Configurar canales de notificación
- [ ] Implementar reglas de alertas
- [ ] Testing completo
- [ ] Documentación de usuario
### Fase 7: Replicación para socio (Semana 7-8)
- [ ] Contratar segundo VPS
- [ ] Replicar configuración
- [ ] Personalizar para segundo usuario
- [ ] Configurar federación de etiquetas (si aplica)
---
## 9. Estimación de Costes
### 9.1 Costes mensuales recurrentes
| Concepto | Coste/mes | Notas |
|----------|-----------|-------|
| VPS Hostinger KVM 2 | 8€ | Por servidor |
| Dominio | ~1€ | Prorrateado anual |
| Backups B2 (50GB) | ~0.50€ | Backblaze B2 |
| API IA externa | ~5€ | Uso moderado (estimado) |
| **Total por servidor** | **~15€/mes** | |
| **Total 2 servidores** | **~30€/mes** | |
### 9.2 Costes únicos iniciales
| Concepto | Coste | Notas |
|----------|-------|-------|
| Dominio (primer año) | 10-15€ | Por dominio |
| Tiempo de configuración | ~20 horas | Valorar según caso |
---
## 10. Riesgos y Mitigaciones
| Riesgo | Probabilidad | Impacto | Mitigación |
|--------|--------------|---------|------------|
| VPS caído | Baja | Alto | Backups diarios, alertas de monitoreo |
| Correo en spam | Media | Medio | DKIM/SPF/DMARC bien configurados |
| Quedarse sin RAM | Media | Medio | Swap de 4GB, monitoreo de recursos |
| Fallo de IA local | Baja | Bajo | Fallback a clasificación por reglas |
| Brecha de seguridad | Baja | Alto | Actualizaciones, fail2ban, backups cifrados |
| Pérdida de datos | Muy baja | Muy alto | Backups 3-2-1, verificación periódica |
---
## 11. Métricas de Éxito
| Métrica | Objetivo | Medición |
|---------|----------|----------|
| Uptime del correo | >99.5% | Monitoreo externo |
| Precisión clasificación IA | >85% | Revisión manual mensual |
| Tiempo creación alias | <10 segundos | App móvil |
| Tiempo respuesta NocoDB | <2 segundos | Métricas internas |
| Satisfacción usuario | >8/10 | Encuesta trimestral |
---
## 12. Anexos
### A. Comandos útiles
```bash
# Ver estado de servicios
docker compose ps
# Logs en tiempo real
docker compose logs -f [servicio]
# Backup manual
./scripts/backup.sh
# Actualizar servicios
docker compose pull && docker compose up -d
# Espacio en disco
df -h && docker system df
# Uso de RAM
free -h && docker stats --no-stream
```
### B. Contactos y recursos
- Documentación Mailcow: https://docs.mailcow.email
- Documentación AnonAddy: https://anonaddy.com/help
- Documentación Nextcloud: https://docs.nextcloud.com
- Documentación NocoDB: https://docs.nocodb.com
- Documentación Vaultwarden: https://github.com/dani-garcia/vaultwarden/wiki
---
**Documento preparado para**: Implementación de servidor de correo privado
**Próxima revisión**: Tras completar Fase 1

View File

@@ -0,0 +1,483 @@
# Documentacion Servidor tzzr.net
## Resumen Ejecutivo
Servidor self-hosted con email, base de datos, gestor de archivos, acortador de URLs, alias de correo y gestor de contrasenas.
**IP**: 72.62.1.113
**Hostname**: box.tzzr.net
**OS**: Ubuntu (Mail-in-a-Box)
**Dominio principal**: tzzr.net
---
## Arquitectura
```
[Cloudflare DNS]
|
[72.62.1.113]
|
+-----------------+-----------------+
| |
[Mail-in-a-Box] [Docker Stack]
Puerto 25,443 Puertos internos
| |
+----+----+ +---------------+---------------+
| | | | | | |
Email Nextcloud Postgres NocoDB Shlink Addy Vaultwarden
| |
FileBrowser Redis
```
---
## Servicios Activos
### Mail-in-a-Box (Nativo)
| Componente | URL/Puerto | Descripcion |
|------------|------------|-------------|
| Webmail | https://box.tzzr.net/mail | Roundcube |
| Admin Panel | https://box.tzzr.net/admin | Gestion usuarios/DNS |
| Nextcloud | https://box.tzzr.net/cloud | Archivos/Calendario |
| SMTP | Puerto 25, 587 | Envio de correo |
| IMAP | Puerto 993 | Recepcion de correo |
### Docker Stack (/opt/services)
| Servicio | Puerto Interno | URL Publica | Descripcion |
|----------|---------------|-------------|-------------|
| PostgreSQL | 5432 | - | Base de datos compartida |
| Redis | 6379 | - | Cache para Addy.io |
| NocoDB | 8081 | https://db.tzzr.net | Airtable self-hosted |
| FileBrowser | 8082 | https://files.tzzr.net | Explorador de archivos |
| Shlink | 8083 | https://s.tzzr.net | Acortador de URLs |
| Addy.io | 8084 | https://alias.tzzr.net | Alias de email |
| Vaultwarden | 8085 | https://pass.tzzr.net | Gestor de contrasenas |
---
## Credenciales
### Mail-in-a-Box
- **Admin**: admin@tzzr.net
- **Password**: (configurada durante instalacion)
### PostgreSQL
- **Host**: postgres (interno) / 127.0.0.1:5432
- **Usuario**: tzzr
- **Password**: TzzrDB-2024-Secure
- **Base de datos**: tzzr
### NocoDB
- **URL**: https://db.tzzr.net
- **JWT Secret**: TzzrNocoDB-JWT-2024-SecureKey
- **Primer usuario**: se crea en primer acceso
### FileBrowser
- **URL**: https://files.tzzr.net
- **Usuario inicial**: admin
- **Password inicial**: admin (cambiar inmediatamente)
### Shlink
- **URL**: https://s.tzzr.net
- **API**: usar `shlink api-key:generate` en el contenedor
### Addy.io
- **URL**: https://alias.tzzr.net
- **App Key**: base64:TzzrAddyAppKey2024SecureBase64KeyHere==
- **Secret**: TzzrAddySecret2024Secure
### Vaultwarden
- **URL**: https://pass.tzzr.net
- **Admin Panel**: https://pass.tzzr.net/admin
- **Admin Token**: TzzrVault-Admin-2024-SuperSecureToken
- **Registros publicos**: Desactivados
- **Invitaciones**: Activadas (via admin panel)
---
## Configuracion DNS (Cloudflare)
| Tipo | Nombre | Contenido | Proxy | TTL |
|------|--------|-----------|-------|-----|
| A | @ | 72.62.1.113 | OFF | Auto |
| A | box | 72.62.1.113 | OFF | Auto |
| A | db | 72.62.1.113 | ON | Auto |
| A | files | 72.62.1.113 | ON | Auto |
| A | s | 72.62.1.113 | ON | Auto |
| A | alias | 72.62.1.113 | ON | Auto |
| A | pass | 72.62.1.113 | ON | Auto |
| MX | @ | box.tzzr.net | - | Auto |
| TXT | @ | v=spf1 mx -all | - | Auto |
| TXT | _dmarc | v=DMARC1; p=quarantine... | - | Auto |
**Importante**: Los registros MX y el dominio raiz (@, box) deben tener proxy OFF para que funcione el email.
---
## Estructura de Archivos
```
/opt/services/
├── docker-compose.yml # Definicion de servicios
├── init.sql # Schema inicial PostgreSQL
├── backup.sh # Script de backups
└── backups/ # Directorio de backups
/home/user-data/ # Datos de Mail-in-a-Box
├── mail/ # Buzones de correo
├── ssl/ # Certificados SSL
├── backup/ # Backups automaticos MiaB
└── www/ # Archivos web estaticos
/etc/nginx/conf.d/
└── services.conf # Reverse proxy para Docker
```
---
## Backups
### Automaticos (Mail-in-a-Box)
- **Ubicacion**: /home/user-data/backup/
- **Incluye**: Email, Nextcloud, certificados, configuracion
- **Frecuencia**: Diaria
### Script personalizado (/opt/services/backup.sh)
- **Frecuencia**: Diaria a las 3:00 AM
- **Retencion**: 7 dias
- **Incluye**:
- Dump de PostgreSQL
- Volumenes Docker
- **Ubicacion**: /opt/services/backups/
### Cron job
```
0 3 * * * /opt/services/backup.sh >> /var/log/tzzr-backup.log 2>&1
```
---
## Decisiones Tecnicas
### Por que Mail-in-a-Box?
- Solucion todo-en-uno para email self-hosted
- Incluye Nextcloud, DNS, certificados SSL automaticos
- Panel de administracion simple
- Backups integrados
### Por que PostgreSQL compartido?
- Reduce uso de RAM (vs multiples instancias)
- Facilita backups centralizados
- NocoDB, Shlink y Addy.io lo soportan nativamente
### Por que puertos solo en 127.0.0.1?
- Seguridad: servicios no expuestos directamente
- Todo el trafico pasa por nginx con SSL
- Mail-in-a-Box maneja los certificados
### Por que Vaultwarden en lugar de Bitwarden oficial?
- Menor consumo de recursos (escrito en Rust)
- Compatible 100% con apps de Bitwarden
- Ideal para uso personal/pequenos equipos
- Una sola imagen Docker vs multiple contenedores
---
## Comandos Utiles
```bash
# Ver estado de contenedores
docker ps
# Ver logs de un servicio
docker logs -f nocodb
# Reiniciar stack completo
cd /opt/services && docker compose restart
# Backup manual de PostgreSQL
docker exec postgres pg_dump -U tzzr tzzr > backup.sql
# Reiniciar nginx
systemctl restart nginx
# Ver certificados SSL
certbot certificates
# Estado de Mail-in-a-Box
mailinabox
```
---
# Plan de Clonacion para Nuevos Usuarios
## Estrategia de Dominios para la Organizacion
### Arquitectura Multi-Tenant
```
[Dominio Principal]
juntis.com
|
Email principal para TODOS los usuarios
usuario@juntis.com
|
+-------------------+-------------------+
| | |
[Servidor 1] [Servidor 2] [Servidor N]
tzzr.net otro.net nuevo.net
| | |
Alias propios Alias propios Alias propios
*@tzzr.net *@otro.net *@nuevo.net
```
### Justificacion
1. **Email principal centralizado** (juntis.com):
- Identidad corporativa unificada
- Todos los usuarios tienen @juntis.com
- Facilita comunicacion interna
- Un solo servidor de mail principal
2. **Dominios de alias separados** (tzzr.net, otro.net, etc.):
- Cada persona/servidor tiene su propio dominio
- Evita colisiones de alias (dos personas no crearan el mismo alias)
- Privacidad: cada quien gestiona sus alias
- Escalabilidad: agregar nuevos usuarios = nuevo dominio
### Ejemplo Practico
| Usuario | Email Principal | Dominio Alias | Ejemplos de Alias |
|---------|-----------------|---------------|-------------------|
| Pablo | pablo@juntis.com | tzzr.net | amazon@tzzr.net, netflix@tzzr.net |
| Maria | maria@juntis.com | maria.net | amazon@maria.net, spotify@maria.net |
| Juan | juan@juntis.com | juan.net | amazon@juan.net, github@juan.net |
Todos reciben email en @juntis.com, pero cada uno tiene alias unicos en su dominio.
---
## Checklist de Clonacion
### Prerequisitos
- [ ] VPS nuevo (minimo 2GB RAM, 20GB disco)
- [ ] Dominio nuevo registrado (ej: nuevo-usuario.net)
- [ ] Acceso a Cloudflare (o DNS del dominio)
- [ ] IP publica del nuevo servidor
### Paso 1: Preparar el Servidor Base
```bash
# Conectar al nuevo servidor
ssh root@NUEVA_IP
# Actualizar sistema
apt update && apt upgrade -y
# Configurar hostname
hostnamectl set-hostname box.NUEVO-DOMINIO.net
```
### Paso 2: Instalar Mail-in-a-Box
```bash
# Instalar MiaB
curl -s https://mailinabox.email/setup.sh | sudo bash
```
Durante la instalacion:
- **Hostname**: box.NUEVO-DOMINIO.net
- **Email admin**: admin@NUEVO-DOMINIO.net (temporal, luego se configura el principal)
### Paso 3: Configurar DNS en Cloudflare
Crear estos registros para NUEVO-DOMINIO.net:
| Tipo | Nombre | Contenido | Proxy |
|------|--------|-----------|-------|
| A | @ | NUEVA_IP | OFF |
| A | box | NUEVA_IP | OFF |
| A | db | NUEVA_IP | ON |
| A | files | NUEVA_IP | ON |
| A | s | NUEVA_IP | ON |
| A | alias | NUEVA_IP | ON |
| A | pass | NUEVA_IP | ON |
| MX | @ | box.NUEVO-DOMINIO.net | - |
| TXT | @ | v=spf1 mx -all | - |
### Paso 4: Instalar Docker
```bash
curl -fsSL https://get.docker.com | sh
```
### Paso 5: Crear Estructura de Directorios
```bash
mkdir -p /opt/services/backups
cd /opt/services
```
### Paso 6: Configurar docker-compose.yml
Copiar el archivo base y modificar:
```yaml
# Cambiar estas variables por cada servidor:
# - Passwords de PostgreSQL
# - JWT secrets
# - Dominios (s.DOMINIO, alias.DOMINIO, pass.DOMINIO)
# - App keys
```
**Variables a personalizar por servidor**:
| Variable | Descripcion | Ejemplo |
|----------|-------------|---------|
| POSTGRES_PASSWORD | Password de DB | NuevoUsuario-DB-2024 |
| NC_AUTH_JWT_SECRET | JWT de NocoDB | NuevoUsuario-JWT-Secret |
| DEFAULT_DOMAIN | Dominio Shlink | s.nuevo-usuario.net |
| ANONADDY_DOMAIN | Dominio alias | nuevo-usuario.net |
| APP_KEY | Key de Addy | base64:NuevoKeyAqui... |
| DOMAIN (Vaultwarden) | URL Vaultwarden | https://pass.nuevo-usuario.net |
| ADMIN_TOKEN | Token admin Vault | NuevoUsuario-Vault-Token |
### Paso 7: Configurar Nginx
Copiar /etc/nginx/conf.d/services.conf y reemplazar:
- Todos los `tzzr.net` por `NUEVO-DOMINIO.net`
- Verificar que los puertos coincidan
```bash
# Recargar nginx
nginx -t && systemctl reload nginx
```
### Paso 8: Iniciar Servicios
```bash
cd /opt/services
docker compose up -d
```
### Paso 9: Configurar Email Principal
Si el email principal es juntis.com (servidor central):
1. En el servidor central (juntis.com), crear cuenta: usuario@juntis.com
2. En Addy.io del nuevo servidor, configurar el reenvio a usuario@juntis.com
3. Los alias de NUEVO-DOMINIO.net reenviaran a usuario@juntis.com
### Paso 10: Verificacion Final
```bash
# Verificar contenedores
docker ps
# Probar cada servicio
curl -I https://db.NUEVO-DOMINIO.net
curl -I https://files.NUEVO-DOMINIO.net
curl -I https://s.NUEVO-DOMINIO.net
curl -I https://alias.NUEVO-DOMINIO.net
curl -I https://pass.NUEVO-DOMINIO.net
```
---
## Script de Clonacion Automatizada
Para facilitar el proceso, se puede crear un script interactivo:
```bash
#!/bin/bash
# clone-server.sh - Script de clonacion de servidor tzzr
echo "=== Clonacion de Servidor ==="
read -p "Nuevo dominio (ej: nuevo-usuario.net): " DOMAIN
read -p "IP del servidor: " SERVER_IP
read -p "Email admin: " ADMIN_EMAIL
# Generar passwords aleatorios
DB_PASS=$(openssl rand -base64 16)
JWT_SECRET=$(openssl rand -base64 32)
APP_KEY=$(openssl rand -base64 32)
VAULT_TOKEN=$(openssl rand -base64 32)
echo ""
echo "=== Configuracion Generada ==="
echo "Dominio: $DOMAIN"
echo "IP: $SERVER_IP"
echo "DB Password: $DB_PASS"
echo "JWT Secret: $JWT_SECRET"
echo "Vault Token: $VAULT_TOKEN"
echo ""
echo "Guarda estas credenciales en un lugar seguro!"
```
---
## Mantenimiento Post-Clonacion
### Tareas Semanales
- Verificar que backups se ejecutan
- Revisar logs de errores
- Actualizar contenedores si hay parches de seguridad
### Tareas Mensuales
- Renovar certificados SSL (automatico con MiaB)
- Revisar uso de disco
- Actualizar sistema operativo
### Actualizacion de Contenedores
```bash
cd /opt/services
docker compose pull
docker compose up -d
```
---
## Resolucion de Problemas Comunes
### SSL no funciona
1. Verificar que DNS apunta correctamente
2. Esperar propagacion (hasta 24h)
3. Ejecutar: `mailinabox` para regenerar certificados
### Contenedor no inicia
```bash
docker logs NOMBRE_CONTENEDOR
# Verificar si es problema de dependencias o configuracion
```
### Email no llega
1. Verificar registros MX en DNS
2. Revisar logs: `docker logs postfix` o `/var/log/mail.log`
3. Verificar que puerto 25 no esta bloqueado
### Base de datos llena
```bash
# Ver espacio
docker exec postgres psql -U tzzr -c "SELECT pg_size_pretty(pg_database_size('tzzr'));"
# Limpiar si es necesario
docker exec postgres vacuumdb -U tzzr -d tzzr -f
```
---
## Contacto y Soporte
- **Repositorio**: (agregar si se crea)
- **Documentacion Mail-in-a-Box**: https://mailinabox.email/guide.html
- **Documentacion Vaultwarden**: https://github.com/dani-garcia/vaultwarden/wiki
---
*Documento generado: Diciembre 2024*
*Ultima actualizacion: Incluye Vaultwarden y plan de clonacion*