# Docker Configuration

Advanced Docker setup and configuration options.

## Basic Setup

```bash
git clone https://github.com/chriswritescode-dev/opencode-manager.git
cd opencode-manager

# Copy and configure environment
cp .env.example .env

# Generate a secure AUTH_SECRET
openssl rand -base64 32
# Add the output to AUTH_SECRET in .env

# Start the container
docker-compose up -d
```

!!! warning "AUTH_SECRET Required"
    The container will not start without `AUTH_SECRET` set in your `.env` file. Generate one with:
    ```bash
    openssl rand -base64 32
    ```

## docker-compose.yml

Default configuration:

```yaml
services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: opencode-manager
    ports:
      - "5003:5003"
      - "5100:5100"
      - "5101:5101"
      - "5102:5102"
      - "5103:5103"
    environment:
      - NODE_ENV=${NODE_ENV:-production}
      - HOST=0.0.0.0
      - PORT=5003
      - OPENCODE_SERVER_PORT=5551
      - OPENCODE_HOST=127.0.0.1
      - DATABASE_PATH=/app/data/opencode.db
      - WORKSPACE_PATH=/workspace
      - PROCESS_START_WAIT_MS=2000
      - PROCESS_VERIFY_WAIT_MS=1000
      - HEALTH_CHECK_INTERVAL_MS=5000
      - HEALTH_CHECK_TIMEOUT_MS=30000
      - MAX_FILE_SIZE_MB=50
      - MAX_UPLOAD_SIZE_MB=50
      - DEBUG=false
      - AUTH_SECRET=${AUTH_SECRET}
      - AUTH_TRUSTED_ORIGINS=${AUTH_TRUSTED_ORIGINS:-http://localhost:5003}
      - ADMIN_EMAIL=${ADMIN_EMAIL:-}
      - ADMIN_PASSWORD=${ADMIN_PASSWORD:-}
      - ADMIN_PASSWORD_RESET=${ADMIN_PASSWORD_RESET:-false}
      - GITHUB_CLIENT_ID=${GITHUB_CLIENT_ID:-}
      - GITHUB_CLIENT_SECRET=${GITHUB_CLIENT_SECRET:-}
      - GOOGLE_CLIENT_ID=${GOOGLE_CLIENT_ID:-}
      - GOOGLE_CLIENT_SECRET=${GOOGLE_CLIENT_SECRET:-}
      - DISCORD_CLIENT_ID=${DISCORD_CLIENT_ID:-}
      - DISCORD_CLIENT_SECRET=${DISCORD_CLIENT_SECRET:-}
      - AUTH_SECURE_COOKIES=${AUTH_SECURE_COOKIES:-false}
      - PASSKEY_RP_ID=${PASSKEY_RP_ID:-localhost}
      - PASSKEY_RP_NAME=${PASSKEY_RP_NAME:-OpenCode Manager}
      - PASSKEY_ORIGIN=${PASSKEY_ORIGIN:-http://localhost:5003}
      - VAPID_PUBLIC_KEY=${VAPID_PUBLIC_KEY:-}
      - VAPID_PRIVATE_KEY=${VAPID_PRIVATE_KEY:-}
      - VAPID_SUBJECT=${VAPID_SUBJECT:-}
    volumes:
      - opencode-workspace:/workspace
      - opencode-data:/app/data
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:5003/api/health"]
      interval: 30s
      timeout: 3s
      retries: 3
      start_period: 40s

volumes:
  opencode-workspace:
    driver: local
  opencode-data:
    driver: local
```

## Environment Variables

Create a `.env` file in the project root. The docker-compose.yml automatically reads variables from `.env`:

```bash
# Required
AUTH_SECRET=generate-with-openssl-rand-base64-32

# Optional - pre-configured admin
ADMIN_EMAIL=admin@example.com
ADMIN_PASSWORD=your-secure-password

# Optional - OAuth providers
GITHUB_CLIENT_ID=your-client-id
GITHUB_CLIENT_SECRET=your-client-secret

# Optional - passkeys
PASSKEY_RP_ID=localhost
PASSKEY_ORIGIN=http://localhost:5003

# Optional - push notifications
VAPID_PUBLIC_KEY=BMx-1234567890abcdefghijklmnopqrstuv...
VAPID_PRIVATE_KEY=abcd1234567890abcdef...
VAPID_SUBJECT=mailto:you@example.com
```

## Entrypoint Behavior

The container entrypoint (`scripts/docker-entrypoint.sh`) automatically:

1. **Verifies Bun** is installed (installed at build time, fallback install if missing)
2. **Verifies OpenCode** is installed (installed at build time, fallback install if missing)
3. **Upgrades OpenCode** if below minimum version (1.0.137)
4. **Validates AUTH_SECRET** is set (required for startup)

## Port Configuration

### Main Application

The application runs on port 5003 by default:

```yaml
ports:
  - "5003:5003"
```

Change the host port if needed:

```yaml
ports:
  - "8080:5003"  # Access at localhost:8080
```

### Dev Server Ports

Ports 5100-5103 are exposed for running dev servers inside repositories:

```yaml
ports:
  - "5100:5100"
  - "5101:5101"
  - "5102:5102"
  - "5103:5103"
```

Configure your dev server to use one of these ports:

=== "Vite"

    ```typescript
    // vite.config.ts
    export default {
      server: {
        port: 5100,
        host: '0.0.0.0'
      }
    }
    ```

=== "Next.js"

    ```bash
    next dev -p 5100 -H 0.0.0.0
    ```

=== "Express"

    ```javascript
    app.listen(5100, '0.0.0.0')
    ```

## Volume Mounts

### Workspace

Repository storage:

```yaml
volumes:
  - opencode-workspace:/workspace
```

All cloned repositories are stored here. Uses a named volume for data persistence across container recreations.

### Data

Database and configuration:

```yaml
volumes:
  - opencode-data:/app/data
```

Contains:
- SQLite database
- User settings
- Session data

Uses a named volume for data persistence.

### Import Existing OpenCode Chats From Your Host

If you already use standalone OpenCode on your machine and want Dockerized OpenCode Manager to show those chats on first setup, bind your host OpenCode config/state into the container and bind your repo root to the same absolute path that standalone OpenCode used.

Add to `.env`:

```bash
OCM_REPOS_HOST_PATH=/Users/you/Development
OCM_OPENCODE_CONFIG_HOST_PATH=/Users/you/.config/opencode
OCM_OPENCODE_STATE_HOST_PATH=/Users/you/.local/share/opencode
```

Then add a compose override:

```yaml
services:
  app:
    environment:
      - OPENCODE_IMPORT_CONFIG_PATH=/import/opencode-config/opencode.json
      - OPENCODE_IMPORT_STATE_PATH=/import/opencode-state
    volumes:
      - ${OCM_REPOS_HOST_PATH}:${OCM_REPOS_HOST_PATH}:ro
      - ${OCM_OPENCODE_CONFIG_HOST_PATH}:/import/opencode-config:ro
      - ${OCM_OPENCODE_STATE_HOST_PATH}:/import/opencode-state:ro
```

Why the repo mount uses the host path as the container path:

- standalone OpenCode stores chats against absolute directory paths
- mounting `${OCM_REPOS_HOST_PATH}` to the same path inside the container preserves those paths exactly
- OpenCode Manager can then discover that folder and create its normal workspace links under `/workspace/repos`

With a fresh Docker volume, first startup imports the host OpenCode config and state, and after you add `${OCM_REPOS_HOST_PATH}` in the Manager UI, previously existing chats appear under the discovered repositories.

## Health Checks

The container includes health checks:

```yaml
healthcheck:
  test: ["CMD", "curl", "-f", "http://localhost:5003/api/health"]
  interval: 30s
  timeout: 3s
  retries: 3
  start_period: 40s
```

Check health status:

```bash
docker inspect --format='{{.State.Health.Status}}' opencode-manager
```

## Resource Limits

Limit container resources:

```yaml
services:
  opencode-manager:
    # ... other config
    deploy:
      resources:
        limits:
          cpus: '2'
          memory: 4G
        reservations:
          cpus: '0.5'
          memory: 1G
```

## Networking

### Custom Network

Create an isolated network:

```yaml
services:
  opencode-manager:
    networks:
      - opencode-net

networks:
  opencode-net:
    driver: bridge
```

### Host Network

Use host networking (Linux only):

```yaml
services:
  opencode-manager:
    network_mode: host
```

## Commands

### Basic Operations

```bash
# Start
docker-compose up -d

# Stop
docker-compose down

# Restart
docker-compose restart

# View logs
docker-compose logs -f

# View logs (last 100 lines)
docker-compose logs --tail 100
```

### Maintenance

```bash
# Rebuild image
docker-compose build

# Rebuild without cache
docker-compose build --no-cache

# Update and restart (uses upgrade script)
docker-compose down
git pull
docker-compose build --no-cache
docker-compose up -d
```

### Debugging

```bash
# Access shell
docker exec -it opencode-manager sh

# View running processes
docker exec opencode-manager ps aux

# Check disk usage
docker exec opencode-manager df -h

# View environment
docker exec opencode-manager env
```

## Global Agent Instructions

The container creates a default `AGENTS.md` file at `/workspace/.config/opencode/AGENTS.md`.

### Default Content

Instructions for AI agents working in the container:
- Reserved ports information
- Available dev server ports
- Docker-specific guidelines

### Editing

**Via UI:** Settings > OpenCode > Global Agent Instructions

**Via File:**
```bash
docker exec -it opencode-manager vi /workspace/.config/opencode/AGENTS.md
```

### Precedence

Global instructions merge with repository-specific `AGENTS.md` files. Repository instructions take precedence.

## Exposing the OpenCode Server (Advanced)

By default, the OpenCode server binds to `127.0.0.1` inside the container and is **not reachable from outside the container**. This is the correct and safe default for nearly all users.

### When to Expose Externally

You only need to expose the OpenCode server on an external interface if you have a specific use case that requires other services or machines to connect directly to it.

### How to Expose Safely

To expose the OpenCode server on the host network:

1. **Set `OPENCODE_HOST=0.0.0.0`** in your environment
2. **Add port `5551:5551`** to the compose ports
3. **Set `OPENCODE_SERVER_PASSWORD`** — this is **required**; the managed OpenCode server will refuse to start without it

Example compose override:

```yaml
services:
  app:
    ports:
      - "5551:5551"
    environment:
      - OPENCODE_HOST=0.0.0.0
      - OPENCODE_SERVER_PASSWORD=${OPENCODE_SERVER_PASSWORD:?Set OPENCODE_SERVER_PASSWORD before exposing OpenCode on port 5551}
```

### Password Configuration

The password can be configured in two ways:

1. **Environment variable:** Set `OPENCODE_SERVER_PASSWORD` in your `.env` file or compose environment
2. **Via UI:** Use Settings → OpenCode → Server Auth to set a password at runtime

**DB-stored passwords take precedence over the environment variable.** If you set a password via the UI, it will override the env var.

### Startup Guard

If you set `OPENCODE_HOST=0.0.0.0` (or any non-localhost host) without configuring a password (either via env var or UI), the managed OpenCode server will refuse to start with an error message explaining how to fix it. The OpenCode Manager UI/API may remain available so you can configure a password and restart the managed server.
