This guide explains how to deploy embapi using Docker containers.
- Quick Start
- Configuration
- Deployment Options
- Building the Image
- Running with Docker Compose
- Running Standalone Container
- Connecting to External Database
- Data Persistence
- Security Considerations
- Troubleshooting
The fastest way to get started with embapi using Docker:
# Run the quick setup script (generates secure keys automatically)
./docker-setup.sh
# Start the services
docker-compose up -d
# Check logs
docker-compose logs -f embapi
# Access the API
curl http://localhost:8880/docs# 1. Copy the environment template
cp .env.docker.template .env
# 2. Edit .env and set required values:
# - SERVICE_ADMINKEY (admin API key)
# - ENCRYPTION_KEY (at least 32 characters)
# - SERVICE_DBPASSWORD (database password)
# 3. Start the services
docker-compose up -d
# 4. Check logs
docker-compose logs -f embapi
# 5. Access the API
curl http://localhost:8880/docsAll configuration is done via environment variables. You can set them:
- In a
.envfile (recommended) - see.env.docker.template - In docker-compose.yml - under the
environmentsection - Via command line - using
-eflag withdocker run
| Variable | Description | Example |
|---|---|---|
SERVICE_ADMINKEY |
Admin API key for administrative operations | Ch4ngeM3SecureKey! |
ENCRYPTION_KEY |
Encryption key for API keys (min 32 chars) | openssl rand -hex 32 |
| Variable | Description | Default |
|---|---|---|
SERVICE_DEBUG |
Enable debug logging | false |
SERVICE_HOST |
Hostname to bind to | 0.0.0.0 |
SERVICE_PORT |
Internal service port | 8880 |
SERVICE_DBHOST |
Database hostname | postgres |
SERVICE_DBPORT |
Database port | 5432 |
SERVICE_DBUSER |
Database username | postgres |
SERVICE_DBPASSWORD |
Database password | postgres |
SERVICE_DBNAME |
Database name | embapi |
API_PORT |
External port to expose API | 8880 |
POSTGRES_PORT |
External port to expose PostgreSQL | 5432 |
This is the easiest option for getting started. It includes both embapi and a PostgreSQL database with pgvector support.
docker-compose up -dThis will:
- Start a PostgreSQL 16 container with pgvector extension
- Build and start the embapi container
- Set up networking between the containers
- Persist database data in a Docker volume
If you have an existing PostgreSQL database with pgvector support, you can run just the embapi container:
# Build the image
docker build -t embapi:latest .
# Run the container
docker run -d \
--name embapi \
-p 8880:8880 \
-e SERVICE_DBHOST=your-db-host \
-e SERVICE_DBPORT=5432 \
-e SERVICE_DBUSER=your-db-user \
-e SERVICE_DBPASSWORD=your-db-password \
-e SERVICE_DBNAME=your-db-name \
-e SERVICE_ADMINKEY=your-admin-key \
-e ENCRYPTION_KEY=your-encryption-key \
embapi:latestModify docker-compose.yml to comment out or remove the postgres service, then set SERVICE_DBHOST to your external database hostname in the .env file:
# Comment out the postgres service in docker-compose.yml
# services:
# postgres:
# ...
services:
embapi:
# ... rest of the configuration
environment:
SERVICE_DBHOST: external-db.example.com # Your external database
# ... other environment variablesTo build the Docker image manually:
# Build with default tag
docker build -t embapi:latest .
# Build with specific tag
docker build -t embapi:v0.1.0 .
# Build with no cache (clean build)
docker build --no-cache -t embapi:latest .The Dockerfile uses a multi-stage build:
- Builder stage: Compiles the Go application and generates sqlc code
- Runtime stage: Creates a minimal Alpine-based image with just the binary
# Start in background (detached mode)
docker-compose up -d
# Start with logs visible
docker-compose up
# Rebuild and start (after code changes)
docker-compose up -d --build# View all logs
docker-compose logs
# Follow logs in real-time
docker-compose logs -f
# View logs for specific service
docker-compose logs -f embapi
docker-compose logs -f postgres# Stop containers (keeps volumes)
docker-compose stop
# Stop and remove containers (keeps volumes)
docker-compose down
# Stop, remove containers, and remove volumes (deletes data!)
docker-compose down -v# Restart all services
docker-compose restart
# Restart specific service
docker-compose restart embapidocker run -d \
--name embapi \
-p 8880:8880 \
--env-file .env \
embapi:latestdocker run -d \
--name embapi \
-p 8880:8880 \
-e SERVICE_DEBUG=false \
-e SERVICE_HOST=0.0.0.0 \
-e SERVICE_PORT=8880 \
-e SERVICE_DBHOST=postgres-host \
-e SERVICE_DBPORT=5432 \
-e SERVICE_DBUSER=dbuser \
-e SERVICE_DBPASSWORD=dbpass \
-e SERVICE_DBNAME=embapi \
-e SERVICE_ADMINKEY=admin-key \
-e ENCRYPTION_KEY=encryption-key-32-chars-min \
embapi:latestdocker run -it --rm \
--name embapi \
-p 8880:8880 \
--env-file .env \
embapi:latestTo use an external PostgreSQL database with pgvector:
- PostgreSQL 11+ with pgvector extension installed
- Database and user created with appropriate permissions
- Network access from the container to the database
Connect to your PostgreSQL server and run:
-- Create database
CREATE DATABASE embapi;
-- Create user
CREATE USER embapi_user WITH PASSWORD 'secure_password';
-- Grant privileges
GRANT ALL PRIVILEGES ON DATABASE embapi TO embapi_user;
-- Connect to the database
\c embapi
-- Grant schema permissions
GRANT ALL ON SCHEMA public TO embapi_user;
-- Enable pgvector extension
CREATE EXTENSION IF NOT EXISTS vector;In your .env file:
SERVICE_DBHOST=your-database-host.example.com
SERVICE_DBPORT=5432
SERVICE_DBUSER=embapi_user
SERVICE_DBPASSWORD=secure_password
SERVICE_DBNAME=embapiFor docker-compose with external database, you can either:
-
Keep the postgres service commented out:
# services: # postgres: # ...
-
Or skip docker-compose and run just the embapi container with
docker run.
The docker-compose setup creates a named volume postgres_data that persists database data:
volumes:
postgres_data: # Named volume for databaseView volumes:
docker volume lsInspect volume:
docker volume inspect embapi_postgres_data# Backup
docker-compose exec postgres pg_dump -U postgres embapi > backup.sql
# Restore
docker-compose exec -T postgres psql -U postgres embapi < backup.sql- Use strong, randomly generated passwords and keys
- Never commit
.envfiles to version control - Use Docker secrets for sensitive values in production
- Run containers behind a reverse proxy (nginx, Traefik)
- Enable HTTPS/TLS for API endpoints
- Restrict database network access
- Keep Docker images updated
- Use specific image tags (not
latest) in production - Implement proper logging and monitoring
- Set resource limits for containers
# Generate admin key
openssl rand -base64 32
# Generate encryption key
openssl rand -hex 32For Docker Swarm:
services:
embapi:
secrets:
- admin_key
- encryption_key
environment:
SERVICE_ADMINKEY_FILE: /run/secrets/admin_key
ENCRYPTION_KEY_FILE: /run/secrets/encryption_key
secrets:
admin_key:
external: true
encryption_key:
external: trueCheck logs:
docker-compose logs embapi
docker logs embapiCommon issues:
- Missing required environment variables (
SERVICE_ADMINKEY,ENCRYPTION_KEY) - Database connection failure
- Port already in use
# Check if postgres is healthy
docker-compose ps
# Check database logs
docker-compose logs postgres
# Test database connection
docker-compose exec postgres psql -U postgres -d embapi -c "SELECT 1;"# Check if container is running
docker ps
# Check port mapping
docker port embapi
# Test from inside container
docker-compose exec embapi wget -O- http://localhost:8880/docs
# Test from host
curl http://localhost:8880/docsIf you see permission errors, check:
- Container runs as non-root user
appuser(UID 1000) - Volume permissions match container user
# Stop and remove everything (including data!)
docker-compose down -v
# Remove images
docker rmi embapi:latest
docker rmi pgvector/pgvector:0.7.4-pg16
# Start fresh
docker-compose up -d --build# Check health status
docker inspect --format='{{.State.Health.Status}}' embapi
# View health check logs
docker inspect --format='{{range .State.Health.Log}}{{.Output}}{{end}}' embapiIf you encounter errors like "TLS: unspecified error" or "Permission denied" when pulling Alpine packages:
# Try building with host network mode
docker build --network=host -t embapi:latest .
# Or use a different mirror
docker build --build-arg ALPINE_MIRROR=http://dl-2.alpinelinux.org/alpine/ -t embapi:latest .
# Or pull a pre-built image if available
docker pull <registry>/embapi:latestThese errors typically indicate network restrictions or firewall issues in the build environment. The Docker files are correct and will work in standard environments.
docker build \
--build-arg GO_VERSION=1.24 \
-t embapi:custom .Add to docker-compose.yml:
services:
embapi:
deploy:
resources:
limits:
cpus: '2'
memory: 2G
reservations:
cpus: '0.5'
memory: 512MConnect to existing network:
docker network create app-networkservices:
embapi:
networks:
- app-network
networks:
app-network:
external: trueAfter starting the services, verify everything is working correctly:
# Check if containers are running
docker-compose ps
# Expected output should show both services as "running" or "healthy"# Test if API is accessible
curl http://localhost:8880/docs
# Should return HTML documentation page
# Test health endpoint (if available)
curl http://localhost:8880/# Connect to PostgreSQL
docker-compose exec postgres psql -U postgres -d embapi
# Check pgvector extension
\dx
# Should show the vector extension
# Exit psql
\q# Use your admin key from .env file
curl -X POST http://localhost:8880/v1/users \
-H "Authorization: Bearer YOUR_ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"user_handle": "testuser",
"full_name": "Test User"
}'
# Should return a response with an API key for the new user- Container won't start: Check logs with
docker-compose logs embapi - Can't connect to database: Verify postgres is healthy with
docker-compose ps - API returns 401: Check that SERVICE_ADMINKEY is set correctly
- Port already in use: Change API_PORT or POSTGRES_PORT in .env file
- Check the main README for general usage
- Review API documentation once running
- Check container logs for errors
- Verify environment variables are set correctly