Docker Deployment

Memory Service is distributed as a Docker image, making it easy to deploy in any container environment. Before adapting these examples for a real environment, review the Security Hardening guide for image pinning, secret handling, TLS, management endpoints, and attachment-download safety.

Quick Start

Use a pinned release image and pass generated local credentials through environment variables:

export DB_PASSWORD="$(openssl rand -base64 32)"
docker run -d \
  --name memory-service \
  -p 8080:8080 \
  -p 127.0.0.1:8085:8085 \
  --read-only \
  --user 10001:10001 \
  --cap-drop ALL \
  --security-opt no-new-privileges:true \
  --tmpfs /var/lib/memory-service/tmp:uid=10001,gid=10001,mode=0700 \
  -e MEMORY_SERVICE_DB_URL="postgres://postgres:${DB_PASSWORD}@host.docker.internal:5432/memoryservice?sslmode=disable" \
  -e MEMORY_SERVICE_HOST=0.0.0.0 \
  -e MEMORY_SERVICE_TLS=false \
  -e MEMORY_SERVICE_MANAGEMENT_PORT=8085 \
  -e MEMORY_SERVICE_MANAGEMENT_HOST=0.0.0.0 \
  -e MEMORY_SERVICE_MANAGEMENT_TLS=false \
  -e MEMORY_SERVICE_MANAGEMENT_ALLOW_NON_LOOPBACK=true \
  -e MEMORY_SERVICE_TEMP_DIR=/var/lib/memory-service/tmp \
  ghcr.io/chirino/memory-service:${PROJECT_VERSION}

Docker Compose

For a complete local setup with all dependencies, use the repository compose file:

docker compose up -d

A minimal production-style compose file should keep secrets outside the file and pin the service image. Keep browser-facing deployments behind TLS and keep management endpoints on an internal path; see Security Hardening for the full production checklist.

services:
  memory-service:
    image: ghcr.io/chirino/memory-service:${PROJECT_VERSION}
    read_only: true
    user: "10001:10001"
    cap_drop:
      - ALL
    security_opt:
      - no-new-privileges:true
    ports:
      - "127.0.0.1:8080:8080"
    environment:
      - MEMORY_SERVICE_DB_URL=postgres://postgres:${DB_PASSWORD}@postgres:5432/memoryservice?sslmode=disable
      - MEMORY_SERVICE_DB_MIGRATE_AT_START=true
      - MEMORY_SERVICE_HOST=0.0.0.0
      - MEMORY_SERVICE_TLS=false
      - MEMORY_SERVICE_MANAGEMENT_PORT=8085
      - MEMORY_SERVICE_MANAGEMENT_HOST=0.0.0.0
      - MEMORY_SERVICE_MANAGEMENT_TLS=false
      - MEMORY_SERVICE_MANAGEMENT_ALLOW_NON_LOOPBACK=true
      - MEMORY_SERVICE_TEMP_DIR=/var/lib/memory-service/tmp
    volumes:
      - memory_service_tmp:/var/lib/memory-service/tmp
    depends_on:
      postgres:
        condition: service_healthy

  postgres:
    image: pgvector/pgvector:pg18
    environment:
      - POSTGRES_DB=memoryservice
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=${DB_PASSWORD}
    volumes:
      - postgres_data:/var/lib/postgresql
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 5s
      retries: 5

volumes:
  postgres_data:
  memory_service_tmp:

Environment Variables

Database Configuration

VariableDescriptionDefault
MEMORY_SERVICE_DB_KINDDatabase type (postgres, sqlite, or mongo)postgres
MEMORY_SERVICE_DB_URLDatabase connection URL-
MEMORY_SERVICE_DB_MIGRATE_AT_STARTRun schema migrations on startuptrue
MEMORY_SERVICE_DB_MAX_OPEN_CONNSMaximum open database connections25
MEMORY_SERVICE_DB_MAX_IDLE_CONNSIdle/minimum connections in pool5

Vector Store Configuration

VariableDescriptionDefault
MEMORY_SERVICE_VECTOR_KINDVector store type (none, pgvector, qdrant, sqlite)none
MEMORY_SERVICE_EMBEDDING_KINDEmbedding provider (none, local, openai)local
MEMORY_SERVICE_EMBEDDING_OPENAI_API_KEYOpenAI API key for embeddings-

SQLite Example

services:
  memory-service:
    image: ghcr.io/chirino/memory-service:${PROJECT_VERSION}
    environment:
      MEMORY_SERVICE_DB_KIND: sqlite
      MEMORY_SERVICE_DB_URL: /data/memory-service.sqlite
      MEMORY_SERVICE_ATTACHMENTS_KIND: fs
      MEMORY_SERVICE_VECTOR_KIND: sqlite
      MEMORY_SERVICE_EMBEDDING_KIND: local
    volumes:
      - ./data:/data

With this configuration, attachment bytes are stored under /data/memory-service.sqlite.attachments unless MEMORY_SERVICE_ATTACHMENTS_FS_DIR is set explicitly.

Authentication

VariableDescriptionDefault
MEMORY_SERVICE_OIDC_ISSUEROIDC issuer URL-
MEMORY_SERVICE_OIDC_ALLOWED_CLIENTSOptional comma-separated OIDC client IDs allowed to call Memory Service; empty allows any client from the configured issuer-
MEMORY_SERVICE_OIDC_ALLOWED_AUDIENCESRequired comma-separated OIDC audiences accepted by Memory Service when OIDC is enabled-
MEMORY_SERVICE_OIDC_ROLE_CLAIMSJSON array of RFC 6901 claim paths used for claim-derived roles["/realm_access/roles"]
MEMORY_SERVICE_OIDC_TLS_INSECURE_SKIP_VERIFYSkip TLS certificate verification for OIDC discovery/JWKS requests; rejected outside testing modefalse
MEMORY_SERVICE_API_KEYS_<CLIENT>API key(s) for a client ID-

Health Checks

The container exposes health endpoints:

# Liveness
curl http://localhost:8080/health

# Readiness
curl http://localhost:8080/ready

Configure in Docker Compose:

healthcheck:
  test: ["CMD", "curl", "-f", "http://localhost:8080/ready"]
  interval: 30s
  timeout: 10s
  retries: 3
  start_period: 10s

Resource Limits

Set appropriate resource limits:

services:
  memory-service:
    deploy:
      resources:
        limits:
          cpus: "2"
          memory: 1G
        reservations:
          cpus: "0.5"
          memory: 512M

Production Configuration

For production deployments:

services:
  memory-service:
    image: ghcr.io/chirino/memory-service:999-SNAPSHOT
    restart: unless-stopped
    read_only: true
    user: "10001:10001"
    cap_drop:
      - ALL
    security_opt:
      - no-new-privileges:true
    environment:
      - MEMORY_SERVICE_DB_URL=postgres://postgres:${DB_PASSWORD}@postgres:5432/memoryservice?sslmode=disable
      - MEMORY_SERVICE_HOST=0.0.0.0
      - MEMORY_SERVICE_PLAIN_TEXT=false
      - MEMORY_SERVICE_MANAGEMENT_PORT=8085
      - MEMORY_SERVICE_MANAGEMENT_HOST=0.0.0.0
      - MEMORY_SERVICE_MANAGEMENT_PLAIN_TEXT=false
      - MEMORY_SERVICE_MANAGEMENT_ALLOW_NON_LOOPBACK=true
      - MEMORY_SERVICE_TEMP_DIR=/var/lib/memory-service/tmp
      - MEMORY_SERVICE_TLS_CERT_FILE=/certs/server.crt
      - MEMORY_SERVICE_TLS_KEY_FILE=/certs/server.key
    volumes:
      - ./certs:/certs:ro
      - memory_service_tmp:/var/lib/memory-service/tmp

volumes:
memory_service_tmp:

This example is a starting point, not a complete security boundary. Add a real database, OIDC audience configuration, non-plain encryption, trusted TLS material, exact CORS origins when browser clients are used, and deployment-specific network controls as described in Security Hardening.

Multi-Container Setup

With separate embedding service:

services:
  memory-service:
    image: ghcr.io/chirino/memory-service:${PROJECT_VERSION}
    environment:
      - MEMORY_SERVICE_EMBEDDING_URL=http://embedding-service:8000
    depends_on:
      - embedding-service
      - postgres

  embedding-service:
    image: your-embedding-service:latest
    environment:
      - MODEL=text-embedding-ada-002
      - OPENAI_API_KEY=${OPENAI_API_KEY}

  postgres:
    image: pgvector/pgvector:pg18
    # ... configuration

Logging

View container logs:

docker logs -f memory-service

The service writes structured log output to stdout. Use your container runtime’s log driver or a sidecar to ship logs to your preferred backend.

Networking

For inter-container communication:

networks:
  memory-network:
    driver: bridge

services:
  memory-service:
    networks:
      - memory-network

  postgres:
    networks:
      - memory-network

  my-agent:
    networks:
      - memory-network
    environment:
      - MEMORY_SERVICE_URL=http://memory-service:8080

Next Steps