Add multi-service Docker setup, Postgres migrations, and messaging API cleanup

This commit is contained in:
2026-01-16 00:25:22 +03:00
Unverified
parent 0b683e3c83
commit 618f55e057
22 changed files with 473 additions and 154 deletions
+111
View File
@@ -0,0 +1,111 @@
# ============================================================================
# COMPLIANCE ARCHITECTURE - Unified Dockerfile
# ============================================================================
# Base stage with common dependencies for all services
FROM python:3.12-slim AS base
# Create common directories
RUN mkdir -p /app && \
useradd -u 1000 -m app && \
useradd -u 1001 -m messaging && \
useradd -u 1002 -m -s /bin/false filestorage
# Set working directory
WORKDIR /app
# Copy health check script
COPY --chown=app:app deployment/healthcheck.py /usr/local/bin/healthcheck.py
RUN chmod +x /usr/local/bin/healthcheck.py
# Copy and install Python dependencies with pip cache
COPY --chown=app:app backend/requirements.txt .
RUN --mount=type=cache,target=/root/.cache/pip \
pip install --no-cache-dir -r requirements.txt
# ============================================================================
# MAIN SERVICE - User-facing operations
# ============================================================================
FROM base AS main
# Copy main service code
COPY --chown=app:app backend/services/main/ ./services/main/
COPY --chown=app:app backend/services/shared/ ./services/shared/
COPY --chown=app:app backend/alembic/ ./alembic/
COPY --chown=app:app backend/alembic.ini ./
# Create data directories for main service
RUN mkdir -p /app/data /app/logs /app/alembic/versions && \
chown -R app:app /app/data /app/logs /app/alembic
# Switch to non-root user
USER app
# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
CMD python3 /usr/local/bin/healthcheck.py
# Expose port
EXPOSE ${PORT:-8300}
# Run main service
CMD ["python", "-m", "services.main.main"]
# ============================================================================
# MESSAGING SERVICE - Secure cryptographic processing
# ============================================================================
FROM base AS messaging
# Copy messaging service code
COPY --chown=messaging:messaging backend/services/messaging/ ./services/messaging/
COPY --chown=messaging:messaging backend/services/shared/ ./services/shared/
# Create directories with restricted permissions
RUN mkdir -p /app/logs && \
chown -R messaging:messaging /app && \
chmod 700 /app
# Switch to non-root user
USER messaging
# Health check - only accessible internally
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
CMD python3 /usr/local/bin/healthcheck.py
# Expose port (internal only)
EXPOSE ${PORT:-8301}
# Run messaging service
CMD ["python", "-m", "services.messaging.main"]
# ============================================================================
# FILE STORAGE SERVICE - Secure file storage with execution prevention
# ============================================================================
FROM base AS file_storage
# Copy file storage service code
COPY --chown=filestorage:filestorage backend/services/file_storage/ ./services/file_storage/
COPY --chown=filestorage:filestorage backend/services/shared/ ./services/shared/
COPY --chown=filestorage:filestorage backend/services/main/db.py ./services/main/
COPY --chown=filestorage:filestorage backend/services/main/dependencies.py ./services/main/
COPY --chown=filestorage:filestorage backend/services/main/models.py ./services/main/
COPY --chown=filestorage:filestorage backend/services/main/constants.py ./services/main/
COPY --chown=filestorage:filestorage backend/services/main/utils.py ./services/main/
# Create secure file storage directories
RUN mkdir -p /app/files /app/logs && \
chown -R filestorage:filestorage /app && \
chmod 700 /app
# Switch to non-root user
USER filestorage
# Health check - only accessible internally
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
CMD python3 /usr/local/bin/healthcheck.py
# Expose port (internal only)
EXPOSE ${PORT:-8302}
# Run file storage service with permission fix
CMD ["sh", "-c", "chown -R filestorage:filestorage /app/files /app/logs 2>/dev/null || true && exec python -m services.file_storage.main"]
+98
View File
@@ -0,0 +1,98 @@
# FromChat Compliance Architecture - Docker Deployment
This directory contains the Docker configuration for the 3-service compliance architecture.
## Architecture Overview
```
┌─────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Clients │────│ Main Service │────│ Messaging │
│ │ │ (Port 8300) │ │ Service │
│ Web/Apps │ │ │ │ (Port 8301) │
│ │ │ • User auth │ │ • Encryption │
└─────────────┘ │ • WebSocket │ │ • Compliance │
│ • API proxy │ │ • No ext access │
└─────────────────┘ └─────────────────┘
│ │
│ │
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ File Storage │ │ PostgreSQL │
│ Service │ │ Database │
│ (Port 8302) │ │ • Main schema │
│ • Secure files │ │ • Messaging │
│ • No ext access │ │ • File schema │
└─────────────────┘ └─────────────────┘
```
## Docker Build Optimization
- **Unified Dockerfile**: Single Dockerfile with multi-stage builds for all services
- **Shared Base**: Common Python dependencies cached in base stage
- **Zero System Dependencies**: No gcc, curl, or system packages - pure Python
- **Python Health Checks**: Built-in health monitoring using urllib
- **Aggressive Caching**: Pip cache and layer optimization
- **Security**: Non-root users, restricted permissions per service
## Security Features
- **Network Isolation**: Messaging and file storage services have NO external network access
- **Database Separation**: Each service has its own schema with minimal required permissions
- **Secure File Storage**: File storage uses restricted permissions and user isolation
- **Ephemeral Keys**: Messaging service generates temporary keys (never persisted)
## Environment Variables Required
Create a `.env` file in this directory with the following variables:
```bash
# Database
POSTGRES_PASSWORD=your_secure_postgres_password
MAIN_DB_PASSWORD=separate_password_for_main_service
MESSAGING_DB_PASSWORD=separate_password_for_messaging
FILE_STORAGE_DB_PASSWORD=separate_password_for_file_storage
# Security
JWT_SECRET=your_jwt_secret_key
VAPID_PUBLIC_KEY=generated_vapid_public_key
VAPID_PRIVATE_KEY=generated_vapid_private_key
FIREBASE_CERT='{"type":"service_account",...}'
# Compliance (public key only - private key stays offline)
COMPLIANCE_PUBLIC_KEY=base64_encoded_public_key
```
## Deployment Commands
```bash
# Start all services
docker compose up -d
# View logs
docker compose logs -f
# Stop services
docker compose down
# Rebuild and restart
docker compose up -d --build
```
## Development Mode
For local development, set `SERVICE_MODE=development` to run all services in a single Python process instead of containers.
## Network Architecture
- **public**: External client access (main service, frontend, reverse proxy)
- **services**: Internal service communication only (database, messaging, file storage)
- Messaging and file storage services have NO external network access
- All inter-service communication is HTTP-based with proper authentication
## Database Schema Separation
- `fromchat_main`: User data, authentication, profiles
- `fromchat_messaging`: Encrypted messages, keys, compliance data
- `fromchat_files`: File metadata, storage references
Each service has minimal required database permissions for security isolation.
-1
View File
@@ -196,7 +196,6 @@ services:
- db:/var/lib/postgresql/data
networks:
- services
- public
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
+4 -1
View File
@@ -33,7 +33,10 @@ RUN npm run build
# 3. Put it all together
FROM node:24-slim
# 3.1. Non-root user
# 3.1. Install curl for health checks
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
# 3.2. Non-root user
RUN useradd -u 1001 app && \
mkdir -p /app && \
chown -R app /app && \
+7
View File
@@ -5,6 +5,7 @@ import { resolve } from 'path';
const app = express();
const port = process.env.PORT || 3000;
const backendHost = process.env.BACKEND_HOST || "http://localhost:8300";
const fileStorageHost = process.env.FILE_STORAGE_HOST || "http://localhost:8302";
const filePath = process.env.STATIC_FILE_PATH || ".";
// API proxy middleware
@@ -15,6 +16,12 @@ app.use('/api', createProxyMiddleware({
ws: true
}));
// File serving proxy middleware
app.use('/uploads/files', createProxyMiddleware({
target: fileStorageHost,
changeOrigin: true
}));
// Serve static files
app.use(express.static(resolve(filePath)));
+28
View File
@@ -0,0 +1,28 @@
#!/usr/bin/env python3
"""
Simple health check script using built-in urllib
Replaces curl dependency in Docker health checks
"""
import sys
import urllib.request
import os
def main():
port = os.getenv('PORT', '8300')
url = f'http://localhost:{port}/health'
try:
with urllib.request.urlopen(url, timeout=10) as response:
if response.status == 200:
print("OK")
sys.exit(0)
else:
print(f"HTTP {response.status}")
sys.exit(1)
except Exception as e:
print(f"FAILED: {e}")
sys.exit(1)
if __name__ == '__main__':
main()