version: "3.9" # MileVault — standalone deployment # # 1. Copy this file somewhere on your server (no other files needed) # 2. Run: docker compose up -d # 3. Visit http://localhost # # Images are pulled from your Gitea container registry automatically. # To update to the latest build: docker compose pull && docker compose up -d # ── Replace these with your actual Gitea host and username ─────────────────── x-registry: ®istry gitea.yourdomain.com/yourusername # ───────────────────────────────────────────────────────────────────────────── services: db: image: timescale/timescaledb:latest-pg16 container_name: milevault_db restart: unless-stopped environment: POSTGRES_DB: milevault POSTGRES_USER: ${DB_USER:-milevault} POSTGRES_PASSWORD: ${DB_PASSWORD:-milevault} volumes: - db_data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U ${DB_USER:-milevault} -d milevault"] interval: 10s timeout: 5s retries: 10 start_period: 30s redis: image: redis:7-alpine container_name: milevault_redis restart: unless-stopped command: redis-server --requirepass ${REDIS_PASSWORD:-milevault} volumes: - redis_data:/data healthcheck: test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD:-milevault}", "ping"] interval: 10s timeout: 5s retries: 5 start_period: 10s backend: image: gitea.yourdomain.com/yourusername/milevault-backend:latest container_name: milevault_backend restart: unless-stopped environment: DATABASE_URL: postgresql+asyncpg://${DB_USER:-milevault}:${DB_PASSWORD:-milevault}@db:5432/milevault REDIS_URL: redis://:${REDIS_PASSWORD:-milevault}@redis:6379/0 SECRET_KEY: ${SECRET_KEY:-changeme_run_openssl_rand_hex_32} ADMIN_USERNAME: ${ADMIN_USERNAME:-admin} ADMIN_PASSWORD: ${ADMIN_PASSWORD:-admin} POCKETID_ISSUER: ${POCKETID_ISSUER:-} POCKETID_CLIENT_ID: ${POCKETID_CLIENT_ID:-} POCKETID_CLIENT_SECRET: ${POCKETID_CLIENT_SECRET:-} FILE_STORE_PATH: /data/files ENVIRONMENT: production volumes: - file_data:/data/files depends_on: db: condition: service_healthy redis: condition: service_healthy healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8000/health"] interval: 15s timeout: 5s retries: 10 start_period: 30s worker: image: gitea.yourdomain.com/yourusername/milevault-worker:latest container_name: milevault_worker restart: unless-stopped environment: DATABASE_URL: postgresql+asyncpg://${DB_USER:-milevault}:${DB_PASSWORD:-milevault}@db:5432/milevault REDIS_URL: redis://:${REDIS_PASSWORD:-milevault}@redis:6379/0 SECRET_KEY: ${SECRET_KEY:-changeme_run_openssl_rand_hex_32} FILE_STORE_PATH: /data/files volumes: - file_data:/data/files depends_on: db: condition: service_healthy redis: condition: service_healthy beat: image: gitea.yourdomain.com/yourusername/milevault-worker:latest container_name: milevault_beat restart: unless-stopped command: celery -A app.workers.celery_app beat --loglevel=info environment: DATABASE_URL: postgresql+asyncpg://${DB_USER:-milevault}:${DB_PASSWORD:-milevault}@db:5432/milevault REDIS_URL: redis://:${REDIS_PASSWORD:-milevault}@redis:6379/0 SECRET_KEY: ${SECRET_KEY:-changeme_run_openssl_rand_hex_32} FILE_STORE_PATH: /data/files volumes: - file_data:/data/files depends_on: db: condition: service_healthy redis: condition: service_healthy frontend: image: gitea.yourdomain.com/yourusername/milevault-frontend:latest container_name: milevault_frontend restart: unless-stopped nginx: image: nginx:alpine container_name: milevault_nginx restart: unless-stopped ports: - "${HTTP_PORT:-80}:80" volumes: - ./nginx.conf:/etc/nginx/nginx.conf:ro depends_on: - backend - frontend volumes: db_data: redis_data: file_data: