Docker Deployment
Deploy Open Receipt OCR using Docker and Docker Compose.
Prerequisites
- Docker 20.10+
- Docker Compose 2.0+
- 2GB free disk space (for image and data)
Quick Start
1. Prepare Environment
Create .env in the project root:
# OCR Providers
GEMINI_API_KEY=your_gemini_key
OPENAI_API_KEY=your_openai_key
MISTRAL_API_KEY=your_mistral_key
TAB_SCANNER_API_KEY=your_tabscanner_key
# Optional: Local OCR
PADDLE_OCR_LOCAL_ENABLED=true
TESSERACT_LANGUAGE=eng+por
# Storage
STORAGE_PROVIDER=local
2. Build and Start
docker-compose up -d --build
This starts:
- API Server on
http://localhost:9999 - Frontend served by the API at
http://localhost:9999 - Redis for background jobs
- Database (SQLite in
./data/db/)
3. Access the Application
http://localhost:9999
The frontend is automatically served by the backend.
Docker Compose Configuration
The docker-compose.yaml includes:
services:
app:
build: .
ports:
- "9999:3000"
volumes:
- ./data:/app/data
environment:
- NODE_ENV=production
- REDIS_URL=redis://redis:6379
depends_on:
- redis
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- redis_data:/data
volumes:
redis_data:
File Structure After Deployment
open-receipt-ocr/
├── data/
│ ├── db/
│ │ └── ocr.sqlite # SQLite database
│ └── uploads/ # Uploaded files
└── docker-compose.yaml
Configuration
Environment Variables
All configuration is done via environment variables in the .env file:
# Application
NODE_ENV=production
SERVER_PORT=3000
# Database
DATABASE_URL=sqlite:./data/db/ocr.sqlite
# Redis
REDIS_URL=redis://redis:6379
# OCR Providers
PADDLE_OCR_LOCAL_ENABLED=false
TESSERACT_LANGUAGE=eng
GEMINI_API_KEY=
OPENAI_API_KEY=
MISTRAL_API_KEY=
XAI_API_KEY=
TAB_SCANNER_API_KEY=
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
AWS_REGION=
# Storage
STORAGE_PROVIDER=local
ONEDRIVE_CLIENT_ID=
ONEDRIVE_CLIENT_SECRET=
ONEDRIVE_TENANT_ID=
ONEDRIVE_FOLDER_ID=
# Secrets
SECRET_PROVIDER=env
Volumes
Mount volumes to persist data:
volumes:
- ./data/db:/app/data/db # Database
- ./data/uploads:/app/uploads # Uploaded files
Ports
Change the exposed port in docker-compose.yaml:
services:
app:
ports:
- "8080:3000" # Change from 9999 to 8080
Deployment Scenarios
Development Environment
docker-compose -f docker-compose.yml up
Includes:
- Hot reload (if configured)
- Debug logging
- SQLite database
Production Environment
For production, consider:
- Use PostgreSQL instead of SQLite:
services:
postgres:
image: postgres:15-alpine
environment:
POSTGRES_DB: ocr
POSTGRES_PASSWORD: secure_password
volumes:
- postgres_data:/var/lib/postgresql/data
# In app service:
DATABASE_URL: postgresql://user:password@postgres:5432/ocr
- Add SSL/TLS:
Use a reverse proxy like Nginx:
server {
listen 443 ssl;
server_name yourdomain.com;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
location / {
proxy_pass http://app:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
- Set resource limits:
services:
app:
deploy:
resources:
limits:
cpus: '2'
memory: 4G
reservations:
cpus: '1'
memory: 2G
- Configure logging:
services:
app:
logging:
driver: "json-file"
options:
max-size: "100m"
max-file: "10"
Monitoring and Logs
View Logs
# All services
docker-compose logs -f
# Specific service
docker-compose logs -f app
# Last 100 lines
docker-compose logs --tail=100 app
Health Check
curl http://localhost:9999/health
Monitor Resources
docker stats
Maintenance
Backup Database
# Create backup
cp data/db/ocr.sqlite data/db/ocr.sqlite.backup
# Or compress
tar czf ocr_db_backup.tar.gz data/db/
Database Migration
To upgrade TypeORM migrations:
# Stop services
docker-compose down
# Run migrations in container
docker-compose run --rm app npm run typeorm:migration:run
# Restart
docker-compose up -d
Clean Up
# Stop containers
docker-compose down
# Remove volumes (⚠️ deletes data)
docker-compose down -v
# Remove images
docker-compose down --rmi all
Troubleshooting
Container Won’t Start
# Check logs
docker-compose logs app
# Common issues:
# - Port already in use: Change port in docker-compose.yaml
# - Redis not running: docker-compose up redis
# - Permission denied: Ensure data/ directory is writable
Permission Denied Errors
# Fix directory ownership
sudo chown -R $USER:$USER ./data
chmod -R 755 ./data
Redis Connection Failed
# Verify Redis is running
docker-compose ps
# Check Redis logs
docker-compose logs redis
# Ensure REDIS_URL matches service name
REDIS_URL=redis://redis:6379
Out of Disk Space
# Check disk usage
df -h
# Clean up Docker
docker system prune -a
# Remove old images
docker image prune
Database Locked
SQLite can lock if accessed by multiple processes. For production, migrate to PostgreSQL.
Advanced Configuration
Custom Docker Build
FROM node:18-alpine
WORKDIR /app
# Copy and install dependencies
COPY package*.json ./
RUN npm ci --only=production
# Copy application
COPY . .
# Build
RUN npm run build
# Start
CMD ["node", "dist/main.js"]
Build and tag:
docker build -t my-registry/ocr:v1.0.0 .
docker push my-registry/ocr:v1.0.0
Using Environment Files
# Create .env files for different environments
cat > .env.prod << EOF
NODE_ENV=production
GEMINI_API_KEY=prod_key
EOF
# Use with docker-compose
docker-compose --env-file .env.prod up
Health Checks
services:
app:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
Auto-restart on Failure
services:
app:
restart: unless-stopped
Restart policies:
no- Don’t automatically restartalways- Always restart if stoppedunless-stopped- Restart unless explicitly stoppedon-failure- Restart only on failure
Security Best Practices
- Use environment variables for all secrets, not hardcoded values
- Limit API access with authentication/authorization
- Use HTTPS in production (see SSL/TLS example above)
- Regular backups of the database
- Keep images updated:
docker-compose pull && docker-compose up -d - Run as non-root user in production
- Scan for vulnerabilities:
docker scan yourdomain/ocr:latest
Performance Tips
- Use PostgreSQL instead of SQLite for better concurrency
- Enable Redis persistence for better reliability
- Set resource limits to prevent runaway containers
- Use Alpine-based images for smaller footprint
- Implement caching for API responses
- Monitor and optimize slow database queries
Getting Help
If you encounter issues:
- Check the Troubleshooting section
- Review container logs:
docker-compose logs app - Check Development Guide for debugging tips
- Open an issue on GitHub