Skip to main content

Docker Deployment

Deploy Cargoman using Docker and Docker Compose.

Quick Start

Create a docker-compose.yml:

version: '3.8'

services:
cargoman:
image: ghcr.io/byte8/cargoman:latest
ports:
- "8080:8080"
environment:
DATABASE_URL: postgresql://cargoman:cargoman@db:5432/cargoman
ADMIN_TOKEN: ${ADMIN_TOKEN:-change-me-in-production}
BASE_URL: ${BASE_URL:-http://localhost:8080}
STORAGE_BACKEND: filesystem
STORAGE_PATH: /data/packages
RUST_LOG: info
volumes:
- packages:/data/packages
depends_on:
db:
condition: service_healthy
restart: unless-stopped

db:
image: postgres:16-alpine
environment:
POSTGRES_USER: cargoman
POSTGRES_PASSWORD: cargoman
POSTGRES_DB: cargoman
volumes:
- postgres:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U cargoman"]
interval: 5s
timeout: 5s
retries: 5
restart: unless-stopped

volumes:
packages:
postgres:

Start the services:

export ADMIN_TOKEN=$(openssl rand -hex 32)
docker compose up -d

Environment Variables

Create a .env file:

# Required
ADMIN_TOKEN=your-secure-admin-token
BASE_URL=https://packages.example.com

# Database (if using external)
DATABASE_URL=postgresql://user:pass@host:5432/cargoman

# Storage
STORAGE_BACKEND=filesystem
STORAGE_PATH=/data/packages

# Logging
RUST_LOG=info,cargoman=debug

With Cloud Storage

For production with Cloudflare R2:

services:
cargoman:
image: ghcr.io/byte8/cargoman:latest
environment:
DATABASE_URL: postgresql://cargoman:cargoman@db:5432/cargoman
ADMIN_TOKEN: ${ADMIN_TOKEN}
BASE_URL: https://packages.example.com
STORAGE_BACKEND: r2
R2_ACCOUNT_ID: ${R2_ACCOUNT_ID}
R2_ACCESS_KEY_ID: ${R2_ACCESS_KEY_ID}
R2_SECRET_ACCESS_KEY: ${R2_SECRET_ACCESS_KEY}
R2_BUCKET: cargoman-packages
# No volume needed for cloud storage

With Redis Cache

Add Redis for improved performance:

services:
cargoman:
environment:
REDIS_URL: redis://redis:6379
depends_on:
- redis

redis:
image: redis:7-alpine
volumes:
- redis:/data
restart: unless-stopped

volumes:
redis:

With Nginx

Full production setup with TLS:

services:
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./certs:/etc/nginx/certs:ro
depends_on:
- cargoman

cargoman:
# ... (as above, but remove ports)

Example nginx.conf:

events {}

http {
upstream cargoman {
server cargoman:8080;
}

server {
listen 80;
server_name packages.example.com;
return 301 https://$server_name$request_uri;
}

server {
listen 443 ssl http2;
server_name packages.example.com;

ssl_certificate /etc/nginx/certs/fullchain.pem;
ssl_certificate_key /etc/nginx/certs/privkey.pem;

location / {
proxy_pass http://cargoman;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}

Health Checks

The container includes health checks:

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

# Response
{"status": "healthy", "version": "0.1.0"}

Updating

# Pull latest image
docker compose pull

# Restart with new image
docker compose up -d

# Check logs
docker compose logs -f cargoman

Backup

# Backup database
docker compose exec db pg_dump -U cargoman cargoman > backup.sql

# Backup packages (if using filesystem)
docker compose exec cargoman tar -czf /tmp/packages.tar.gz /data/packages
docker cp cargoman:/tmp/packages.tar.gz ./packages.tar.gz

Next Steps