Skip to main content

Docker & Container Deployment

Deploying Lioran S3 with Docker Compose is the recommended production path. It packages the server alongside the Caddy reverse proxy for automated TLS certificate provisioning.


1. Production Docker Compose Configuration​

The following docker-compose.yml is the canonical production deployment template:

docker-compose.yml
services:
bastion:
image: liorans3/liorans3:pre-alpha
container_name: bastion-server
restart: unless-stopped
init: true
stop_grace_period: 30s
expose:
# Expose port only to internal Docker network; no public host port binding
- "27118"
environment:
# Runtime environment mode: production (default) or development
- BASTION_ENV=${BASTION_ENV:-production}
- BASTION_HOST=0.0.0.0
- BASTION_PORT=27118
- BASTION_DATA_DIR=/data

# Bootstrap Admin Credentials
- BASTION_ADMIN_USERNAME=${BASTION_ADMIN_USERNAME:-admin}
- BASTION_ADMIN_PASSWORD=${BASTION_ADMIN_PASSWORD}

# Domain & Security Configuration
- BASTION_PUBLIC_URL=${BASTION_PUBLIC_URL:-https://${BASTION_DOMAIN:-s3.example.com}}
- BASTION_CORS_ORIGINS=${BASTION_CORS_ORIGINS:-https://${BASTION_DOMAIN:-s3.example.com}}
- BASTION_SIGNING_SECRET=${BASTION_SIGNING_SECRET:-}
- BASTION_MAX_SIGNED_URL_TTL_SECS=${BASTION_MAX_SIGNED_URL_TTL_SECS:-604800}

# Storage & Safety Guardrails
- BASTION_MIN_FREE_SPACE_BYTES=${BASTION_MIN_FREE_SPACE_BYTES:-536870912}
- BASTION_STREAM_CHUNK_KIB=${BASTION_STREAM_CHUNK_KIB:-256}
- BASTION_DURABILITY=${BASTION_DURABILITY:-strict}
volumes:
- bastion-data:/data
networks:
- bastion-net
logging:
driver: "json-file"
options:
max-size: "20m"
max-file: "5"
healthcheck:
test: ["CMD", "curl", "-f", "http://127.0.0.1:27118/health"]
interval: 15s
timeout: 5s
retries: 3
start_period: 5s

caddy:
image: caddy:2-alpine
container_name: bastion-caddy
restart: unless-stopped
ports:
- "80:80"
- "443:443"
environment:
- BASTION_DOMAIN=${BASTION_DOMAIN:-s3.example.com}
- CADDY_ACME_EMAIL=${CADDY_ACME_EMAIL:-}
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy-data:/data
- caddy-config:/config
depends_on:
bastion:
condition: service_healthy
networks:
- bastion-net
logging:
driver: "json-file"
options:
max-size: "20m"
max-file: "5"

volumes:
bastion-data:
driver: local
caddy-data:
driver: local
caddy-config:
driver: local

networks:
bastion-net:
driver: bridge

2. Deployment Steps​

Step 1: Prepare Environment File​

Copy .env.production.example to .env:

cp .env.production.example .env

Generate a secure admin password and 64-hex signing secret:

# Generate admin password
openssl rand -base64 24 | tr -d '/+'

# Generate HMAC signing secret
openssl rand -hex 32

Populate .env:

.env
BASTION_DOMAIN=s3.yourdomain.com
BASTION_PUBLIC_URL=https://s3.yourdomain.com
BASTION_ENV=production
BASTION_ADMIN_USERNAME=admin
BASTION_ADMIN_PASSWORD=YourStrongPasswordHere123!
BASTION_SIGNING_SECRET=f4a7c8... # 64 hex characters
BASTION_CORS_ORIGINS=https://s3.yourdomain.com,https://app.yourdomain.com
BASTION_DURABILITY=strict

Step 2: Start the Stack​

docker compose up -d

Step 3: Verify Liveness​

# Verify container health
docker compose ps

# Check public endpoint
curl -f https://s3.yourdomain.com/health

Expected output:

{
"name": "Lioran Bastion",
"status": "ok",
"version": "0.1.0"
}

3. Container Lifecycle & Graceful Shutdown​

  • stop_grace_period: 30s: Allows in-flight multipart chunk writes and HTTP downloads to finish cleanly before signaling termination.
  • Signal Handling: The server captures SIGTERM / SIGINT signals, flushes active RocksDB handles, syncs open file descriptors, and terminates without data corruption.
  • Log Rotation: Logs use json-file with a 20MB per-file limit and 5-file retention ceiling to prevent filling host disks.