Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Docker Deployment

BWS provides official Docker images for easy deployment.

Quick Start

Run with Default Configuration

# Run BWS on port 8080
docker run -p 8080:8080 ghcr.io/benliao/bws:latest

Run with Custom Configuration

# Run with custom config and static files
docker run -d \
  --name bws \
  -p 8080:8080 \
  -v $(pwd)/config.toml:/app/config.toml:ro \
  -v $(pwd)/static:/app/static:ro \
  ghcr.io/benliao/bws:latest

Available Images

Docker Hub Tags

  • latest - Latest stable release
  • v0.3.5 - Specific version (recommended for production)
  • main - Latest development build

Multi-Architecture Support

Images support multiple architectures:

  • linux/amd64 (x86_64)
  • linux/arm64 (ARM64/Apple Silicon)

Configuration Examples

Single Static Site

# Create content
mkdir static
echo "<h1>Hello from Docker!</h1>" > static/index.html

# Run container
docker run -d \
  --name bws-static \
  -p 8080:8080 \
  -v $(pwd)/static:/app/static:ro \
  ghcr.io/benliao/bws:latest \
  bws /app/static --port 8080

Multi-Site with SSL

# Create configuration
cat > config.toml << 'EOF'
[server]
name = "Docker Multi-Site"

[[sites]]
name = "main"
hostname = "localhost"
port = 8080
static_dir = "/app/static"
default = true

[[sites]]
name = "secure"
hostname = "secure.localhost"
port = 8443
static_dir = "/app/static"

[sites.ssl]
enabled = true
auto_cert = true
domains = ["secure.localhost"]

[sites.ssl.acme]
enabled = true
email = "admin@example.com"
challenge_dir = "/app/acme-challenges"
EOF

# Create directories
mkdir -p static acme-challenges

# Run container
docker run -d \
  --name bws-multisite \
  -p 8080:8080 \
  -p 8443:8443 \
  -v $(pwd)/config.toml:/app/config.toml:ro \
  -v $(pwd)/static:/app/static:ro \
  -v $(pwd)/acme-challenges:/app/acme-challenges \
  ghcr.io/benliao/bws:latest

Docker Compose

Basic Setup

# docker-compose.yml
version: '3.8'

services:
  bws:
    image: ghcr.io/benliao/bws:latest
    container_name: bws
    ports:
      - "8080:8080"
      - "8443:8443"
    volumes:
      - ./config.toml:/app/config.toml:ro
      - ./static:/app/static:ro
      - ./acme-challenges:/app/acme-challenges
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/api/health"]
      interval: 30s
      timeout: 10s
      retries: 3

Production Setup with Reverse Proxy

version: '3.8'

services:
  bws:
    image: ghcr.io/benliao/bws:v0.3.5
    container_name: bws
    expose:
      - "8080"
    volumes:
      - ./config.toml:/app/config.toml:ro
      - ./static:/app/static:ro
      - ./acme-challenges:/app/acme-challenges
    restart: unless-stopped
    networks:
      - bws-network

  nginx:
    image: nginx:alpine
    container_name: nginx-proxy
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
      - ./ssl-certs:/etc/ssl/certs:ro
    depends_on:
      - bws
    restart: unless-stopped
    networks:
      - bws-network

networks:
  bws-network:
    driver: bridge

Start with compose:

docker-compose up -d

Build Custom Image

Dockerfile

FROM ghcr.io/benliao/bws:latest

# Copy custom configuration
COPY config.toml /app/config.toml
COPY static/ /app/static/

# Expose ports
EXPOSE 8080 8443

# Run BWS
CMD ["bws", "--config", "/app/config.toml"]

Build and Run

# Build custom image
docker build -t my-bws .

# Run custom image
docker run -d --name my-bws-container -p 8080:8080 my-bws

Volume Mounts

Important Directories

  • /app/config.toml - Configuration file
  • /app/static/ - Static content directory
  • /app/acme-challenges/ - ACME challenge directory
  • /app/certs/ - Manual SSL certificates

Example with All Mounts

docker run -d \
  --name bws-full \
  -p 80:80 \
  -p 443:443 \
  -v $(pwd)/config.toml:/app/config.toml:ro \
  -v $(pwd)/static:/app/static:ro \
  -v $(pwd)/certs:/app/certs:ro \
  -v $(pwd)/acme-challenges:/app/acme-challenges \
  -v $(pwd)/logs:/app/logs \
  ghcr.io/benliao/bws:latest

Environment Variables

# Override config with environment variables
docker run -d \
  --name bws-env \
  -p 8080:8080 \
  -e BWS_LOG_LEVEL=debug \
  -e BWS_WORKERS=4 \
  -v $(pwd)/static:/app/static:ro \
  ghcr.io/benliao/bws:latest \
  bws /app/static --port 8080

Health Checks

Docker Health Check

# Run with health check
docker run -d \
  --name bws-health \
  -p 8080:8080 \
  --health-cmd="curl -f http://localhost:8080/api/health || exit 1" \
  --health-interval=30s \
  --health-timeout=10s \
  --health-retries=3 \
  ghcr.io/benliao/bws:latest

Check Container Health

# Check health status
docker ps
docker inspect bws-health | grep -A 10 '"Health"'

Troubleshooting

Common Issues

Container Won't Start:

# Check logs
docker logs bws

# Validate configuration
docker run --rm \
  -v $(pwd)/config.toml:/app/config.toml:ro \
  ghcr.io/benliao/bws:latest \
  bws --config /app/config.toml --dry-run

Permission Issues:

# Fix volume permissions
sudo chown -R 1000:1000 static/ acme-challenges/

Port Conflicts:

# Check port usage
docker ps -a
netstat -tulpn | grep :8080

Debug Commands

# Run interactive shell
docker run -it --entrypoint /bin/sh ghcr.io/benliao/bws:latest

# Exec into running container
docker exec -it bws /bin/sh

# View container logs
docker logs -f bws

Security

Best Practices

  • Use specific version tags (not latest) in production
  • Mount configuration as read-only (:ro)
  • Run as non-root user (default in BWS image)
  • Use Docker secrets for sensitive data

Non-Root User

# BWS image runs as user 1000 by default
docker run -d \
  --name bws-secure \
  --user 1000:1000 \
  -p 8080:8080 \
  ghcr.io/benliao/bws:latest