# Docker Deployment

## Docker Deploy

The Docker container provides a streamlined way to deploy Keeper Commander Service Mode with automatic device registration and persistent login setup.

### Quick Setup Command

If you have KeeperPAM or Keeper Secrets Manager (KSM) activated on your account, you can use the Keeper Commander `service-docker-setup` command to automate the entire Docker deployment setup process. This command handles device registration, vault configuration, KSM integration and docker compose file generation in a single interactive workflow.

{% hint style="info" %}
Use `service-docker-setup` for a streamlined setup experience. If you prefer manual configuration or don't have KSM activated, follow the Authentication Methods section below.
{% endhint %}

#### **Prerequisites**

* Install [Docker](https://www.docker.com/)
* Pull the Docker image: `docker pull keeper/commander:latest`
* Keeper Secrets Manager (KSM) enabled on your account
* [Keeper Commander](https://docs.keeper.io/keeperpam/commander-cli) installed locally

#### **What It Does**

The `service-docker-setup` command performs these steps automatically:

1. Device Setup
   * Registers your device with Keeper
   * Enables persistent login
   * Sets logout timeout to 30 days
2. Vault Configuration
   * Creates a shared folder (`Commander Service Mode - Docker`)
   * Creates a configuration record (`Commander Service Mode - Docker Config`)
   * Uploads minimized `config.json` as an attachment
3. KSM Integration
   * Creates a KSM application (`Commander Service Mode - Docker App`)
   * Shares the folder with the KSM app (with edit permissions)
   * Creates a client device and generates KSM configuration
4. Docker Compose Generation
   * Prompts for service configuration (port, commands, queue mode, tunneling, TLS)
   * Generates a ready-to-use `docker-compose.yml` file

#### **Usage**

Run the command from within the Keeper Commander shell:

```
service-docker-setup
```

#### **Optional Parameters**

<table><thead><tr><th width="184.6484375">Parameter</th><th width="228.69140625">Description</th><th>Default</th></tr></thead><tbody><tr><td><code>--folder-name</code></td><td>Name for the shared folder</td><td><code>Commander Service Mode - Docker</code></td></tr><tr><td><code>--app-name</code></td><td>Name for the KSM application</td><td><code>Commander Service Mode - Docker App</code></td></tr><tr><td><code>--record-name</code></td><td>Name for the config record</td><td><code>Commander Service Mode - Docker Config</code></td></tr><tr><td><code>--config-path</code></td><td>Path to config.json file</td><td><code>~/.keeper/config.json</code></td></tr><tr><td><code>--timeout</code></td><td>Device timeout setting</td><td><code>30d</code></td></tr><tr><td><code>--skip-device-setup</code></td><td>Skip device registration if already configured</td><td><code>false</code></td></tr></tbody></table>

#### **Interactive Configuration**

The command will guide you through the following configuration options:

Service Configuration:

* Port: The port on which Commander Service will listen (default: 8900)
* Commands: Comma-separated list of allowed commands or aliases (default: tree,ls)
* Queue Mode: Enable async API (v2) for better performance (default: Yes)

{% hint style="info" %}
The `-ur` flag automatically stores the generated API key and service URL in the config record for safe retrieval.
{% endhint %}

Tunnelling Options (optional):

* Ngrok: Generate public URL using ngrok
  * Ngrok auth token
  * Ngrok custom domain (optional)
* Cloudflare: Generate public URL using Cloudflare (if ngrok disabled)
  * Cloudflare tunnel token
  * Cloudflare custom domain

**Output**

After successful completion, the command displays:

Resources Create&#x64;**:**

* Shared Folder UID
* KSM App UID
* Config Record UID
* KSM Base64 Config (for Docker environment variable)

Generated File&#x73;**:**

* `docker-compose.yml` - Ready-to-deploy Docker Compose configuration

***

Example `docker-compose.yml` outpu&#x74;**:**

```yaml
services:
  commander:
    container_name: keeper-service
    image: keeper/commander:latest
    environment:
      KSM_CONFIG: <base64-encoded-ksm-config>
      COMMANDER_RECORD: <config-record-uid>
    ports:
      - "8900:8900"
    command: service-create -p 8900 -c 'tree,ls' -f json -q y -ur $COMMANDER_RECORD \
    --ksm-config $KSM_CONFIG --record $COMMANDER_RECORD
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8900/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s
    restart: unless-stopped
```

#### **Deploy the Service**

Once the command completes successfully, it is recommended to follow the below steps:

1. Quit the Commander session: `quit`
2. Delete local config file to prevent conflicts: `rm ~/.keeper/config.json`
3. Start the services on the remote server where docker is running:\
   `docker compose up -d`
4. Verify deployment:

   `docker ps` , `docker logs keeper-service` , `curl http://localhost:8900/health`

#### **Re-running the Command**

If you run service-docker-setup multiple times:

* Existing vault resources (folder, app, record) will be reused
* The config.json attachment will be updated
* A new KSM client device will be created
* The `docker-compose.yml` file will be regenerated

***

### Manual Docker Setup

If you prefer manual configuration or don't have KSM activated, the Docker container supports four authentication methods described below.

#### **Method 1: Using KSM Config File**

Use a Keeper Secrets Manager (KSM) config file to download the `config.json` configuration from a Keeper record. The container will:

* Download the `config.json` attachment from the specified record using the mounted KSM config file
* Use the downloaded config for authentication

**Two approaches available:**

* **Approach A - KSM Config Base64**: Pass the KSM config base64-encoded string
* **Approach B - KSM Config File mounting**: Mount the `ksm-config.json` file to the container

#### **Method 2: Using KSM Token**

Use a KSM one-time access token to download the `config.json` configuration from a Keeper record. The container will:

* Download the `config.json` attachment from the specified record using the provided KSM token
* Use the downloaded config for authentication

#### **Method 3: Using Credentials**

Pass credentials directly via command line arguments. The container will automatically:

* Register the device with Keeper
* Enable persistent login
* Start the service

#### **Method 4: Using Config File**

Mount an existing Keeper configuration file to the container.

### Common Setup Steps for Config File Preparation

For authentication methods that require uploading a `config.json` file to your vault (KSM Config File, KSM Token, and Config File authentication), follow these steps on your host machine to generate this file:

1. **Login to Keeper on your host machine:**

   ```bash
   keeper shell
   # Then login with your credentials
   login user@example.com
   ```
2. **Register device:**

   ```bash
   this-device register
   ```
3. **Enable persistent login:**

   ```bash
   this-device persistent-login on
   ```
4. **Set timeout:**

   ```bash
   this-device timeout 43200
   ```
5. **Upload config file:** Once configured, locate the `config.json` file in the `.keeper` directory on your host machine. Upload this file as an attachment to a record within a shared folder in your vault.
6. **Remove the original config file:** After uploading, delete the `config.json` file from the `.keeper` directory on your host machine to prevent duplicate configurations with the same device token/clone code.

#### Important Note

**Do not use the same Keeper account in other Commander sessions or environments after uploading `config.json`**.\
Using the same Keeper account will regenerate the clone code, which can disrupt authentication flows in containerized or automated environments.

### Run Docker Container

**With KSM Config File Authentication**

#### **Approach A: Using Base64-Encoded KSM Config**

For environments where mounting files is not practical (e.g., container orchestration platforms), you can pass the KSM configuration as a base64-encoded string:

**Prerequisites:**

Before using KSM config file authentication, you must:

1. **Create a KSM Application** in your Keeper vault
2. **Generate a KSM config base64 value**
3. **Create a Keeper record** containing your service `config.json` as an attachment
4. **Share the record** with your KSM application

**Setup Steps:**

1. Complete the [Common Setup Steps for Config File Preparation](#common-setup-steps-for-config-file-preparation)
2. Create KSM Configuration File:
   * Go to Vault → Secrets Manager → My Applications.
   * Create new application and provide access to your shared folder.
   * Select your application, go to `Devices`, and click on `Add Device`.
   * Use `Configuration File` method and select `Base64` as configuration type.
   * Copy the KSM config base64-encoded string and keep it stored securely for future use.

**Docker Compose File:**

```yml
services:
    commander:
        ports:
            - <port>:<port>
        image: keeper/commander:latest
        command: service-create -p <port> -c '<commands>' -f <json-or-yaml> 
            --ksm-config <BASE64_ENCODED_CONFIG> 
            --record <RECORD_UID_OR_TITLE>
```

**Docker Run:**

```bash
docker run -d -p <port>:<port> \
  keeper/commander:latest \
  service-create -p <port> -c '<commands>' -f <json-or-yaml> \
  --ksm-config <BASE64_ENCODED_CONFIG> \
  --record <RECORD_UID_OR_TITLE>
```

**Example:**

```bash
docker run -d -p 9007:9007 \
  keeper/commander:latest \
  service-create -p 9007 -c 'ls,tree' -f json \
  --ksm-config eyJhcHBsaWNhdGlvbiI6ZXN0LWNsaWVudC1pZCJ9 \
  --record ABC123-DEF456-GHI789
```

{% hint style="info" %}
The `--record` parameter supports both **record UID** and **record title**. If multiple records exist with the same title, you must use the specific UID instead.
{% endhint %}

#### **Approach B: Mounting KSM Config File inside the container**

**Prerequisites:**

Before using KSM config file authentication, you must:

1. **Create a KSM Application** in your Keeper vault
2. **Generate a KSM config file** (`ksm-config.json`)
3. **Create a Keeper record** containing your service `config.json` as an attachment
4. **Share the record** with your KSM application

**Setup Steps:**

1. Complete the [Common Setup Steps for Config File Preparation](#common-setup-steps-for-config-file-preparation)
2. Create KSM Configuration Fil&#x65;**:**
   * Go to Vault → Secrets Manager → My Applications.
   * Create new application and provide access to your shared folder.
   * Select your application, go to `Devices`, and click on `Add Device`.
   * Use `Configuration File` method and download the JSON file.
   * Rename the downloaded file to `ksm-config.json` to avoid any conflict with `.keeper/config.json`.

**Docker Compose File:**

```yml
services:
    commander:
        ports:
            - <port>:<port>
        volumes:
            - /path/to/local/ksm-config.json:/home/commander/ksm-config.json
        image: keeper/commander:latest
        command: service-create -p <port> -c '<commands>' -f <json-or-yaml> 
            --ksm-config /home/commander/ksm-config.json 
            --record <RECORD_UID_OR_TITLE>
```

**Docker Run:**

```bash
docker run -d -p <port>:<port> \
  -v /path/to/local/ksm-config.json:/home/commander/ksm-config.json \
  keeper/commander:latest \
  service-create -p <port> -c '<commands>' -f <json-or-yaml> \
  --ksm-config /home/commander/ksm-config.json \
  --record <RECORD_UID_OR_TITLE>
```

**Example:**

```bash
docker run -d -p 9007:9007 \
  -v /path/to/local/ksm-config.json:/home/commander/ksm-config.json \
  keeper/commander:latest \
  service-create -p 9007 -c 'ls,tree' -f json \
  --ksm-config /home/commander/ksm-config.json \
  --record ABC123-DEF456-GHI789
```

{% hint style="info" %}
The `--record` parameter supports both **record UID** and **record title**. If multiple records exist with the same title, you must use the specific UID instead.
{% endhint %}

#### **With KSM Token Authentication**

**Prerequisites:**

Before using KSM Token authentication, you must:

1. **Create a KSM Application** in your Keeper vault
2. **Store the generated access token securely**
3. **Create a Keeper record** containing your `config.json` as an attachment
4. **Share the record** with your KSM application

**Setup Steps:**

1. Complete the [Common Setup Steps for Config File Preparation](#common-setup-steps-for-config-file-preparation)
2. Create KSM Access Token:
   * Go to Vault → Secrets Manager → My Applications
   * Create new application and provide access to your shared folder
   * Grant "Can Edit" permission and generate the access token
   * Store the generated access token securely

**Docker Compose File:**

```yml
services:
    commander:
        ports:
            - <port>:<port>
        image: keeper/commander:latest
        command: service-create -p <port> -c '<commands>' -f <json-or-yaml> 
            --ksm-token <KSM_TOKEN> 
            --record <RECORD_UID_OR_TITLE>
```

**Docker Run:**

```bash
docker run -d -p <port>:<port> \
  keeper/commander:latest \
  service-create -p <port> -c '<commands>' -f <json-or-yaml> \
  --ksm-token <KSM_TOKEN> \
  --record <RECORD_UID_OR_TITLE>
```

**Example:**

```bash
docker run -d -p 9007:9007 \
  keeper/commander:latest \
  service-create -p 9007 -c 'ls,tree' -f json \
  --ksm-token US:odncsdcindsijiojijj32i3ij2iknm23 \
  --record ABC123-DEF456-GHI789
```

{% hint style="info" %}
The `--record` parameter supports both **record UID** and **record title**. If multiple records exist with the same title, you must use the specific UID instead.
{% endhint %}

#### **With User/Password Authentication**

**Parameters:**

* `-p, --port`: Port number for the service
* `-c, --commands`: Comma-separated list of allowed commands
* `-f, --fileformat`: Configuration file format (json/yaml)
* `--user`: Keeper username for authentication
* `--password`: Keeper password for authentication
* `--server`: Keeper server (optional, defaults to `keepersecurity.com`)

**Docker Compose File:**

```yml
services:
    commander:
        ports:
            - <port>:<port>
        image: keeper/commander:latest
        command: service-create -p <port> -c '<commands>' -f <json-or-yaml> 
            --user <keeper-username> 
            --password <keeper-password>
            --server <keeper-server>
```

**Docker Run:**

```
docker run -d -p <port>:<port> keeper/commander:latest \
  service-create \
  -p <port> \
  -c '<comma-separated-commands>' \
  -f <json-or-yaml> \
  --user <keeper-username> \
  --password <keeper-password> \
  --server <keeper-server>
```

**Example:**

```bash
docker run -d -p 9009:9009 keeper/commander:latest \
  service-create \
  -p 9009 \
  -c 'tree,ls' \
  -f json \
  --user myuser@company.com \
  --password mypassword
```

#### **With Config File Authentication**

**Prerequisites:**

Before using config file authentication, you must first create a properly configured `config.json` file on your host machine.

**Setup Steps:**

1. Follow steps 1-4 from the [Common Setup Steps for Config File Preparation](#common-setup-steps-for-config-file-preparation)
2. **Copy config file:** Once configured, locate the `config.json` file in the `.keeper` directory on your host machine and copy the contents of the `config.json` file to your desired path (e.g., `/path/to/local/config.json`) for Docker mounting.
3. **Remove the original config file:** After copying, delete the `config.json` file from the `.keeper` directory on your host machine to prevent duplicate configurations with the same device token/clone code.

Mount your existing Keeper config file:

**Docker Compose File:**

```yml
services:
    commander:
        ports:
            - <port>:<port>
        volumes:
            - /path/to/local/config.json:/home/commander/.keeper/config.json
        image: keeper/commander:latest
        command: service-create -p <port> -c '<commands>' -f <json-or-yaml>
```

**Docker Run:**

```bash
docker run -d -p <port>:<port> \
  -v /path/to/local/config.json:/home/commander/.keeper/config.json \
  keeper/commander:latest \
  service-create -p <port> -c '<commands>' -f <json-or-yaml>
```

### Verify Deployment

#### **Check container status:**

```
docker ps
```

#### **View container logs:**

```
docker logs <container-name-or-id>
```

#### Retrieve API Key

The API key is stored securely in your Keeper vault. In Docker logs, the key is redacted for security:

```
Generated API key: ****nQ= (stored in vault record: <CONFIG_RECORD_UID>)
```

To retrieve the full API key:

1. Open Keeper Vault
2. Navigate to the "Commander Service Mode - Slack App" folder
3. Open the "Commander Service Mode Slack App Config" record
4. Find the api-key field

#### **Follow logs in real-time:**

```
docker logs -f <container-name-or-id>
```

#### Container Architecture

* **Base Image**: `python:3.11-slim`
* **Working Directory**: `/commander`
* **Config Directory**: `/home/commander/.keeper/`
* **Entrypoint**: `docker-entrypoint.sh` with automatic authentication setup

### Execute Command Endpoint

```bash
# Queue enabled (v2 - async)
curl --location 'http://localhost:<port>/api/v2/executecommand-async' \
--header 'Content-Type: application/json' \
--header 'api-key: <your-api-key>' \
--data '{
   "command": "<command>"
}'

# Queue disabled (v1 - direct)  
curl --location 'http://localhost:<port>/api/v1/executecommand' \
--header 'Content-Type: application/json' \
--header 'api-key: <your-api-key>' \
--data '{
   "command": "<command>"
}'
```

### Persistent Login Mode

Keeper Commander supports persistent login mode (e.g. "Stay Logged In"), which keeps the session active for a specific amount of time. To activate persistent login mode on an account, type the following:

```
this-device persistent-login on
this-device register
this-device timeout 43200
```

If persistent login is enabled with the above timeout settings, you won't be prompted to authenticate in Commander for next 30 days (43,200 minutes). Persistent login is required to ensure uninterrupted background execution of the Service Mode APIs, allowing seamless authentication without repeated login prompts.

Learn more about [persistent login sessions](https://docs.keeper.io/en/keeperpam/commander-installation-setup/logging-in#persistent-login-sessions-stay-logged-in).

### Logging

The service includes a comprehensive logging system that tracks:

* Service startup/shutdown events
* Configuration changes
* API execution
* Security events
* Error conditions

**Configuration**:

Once service mode started the `logging_config.yaml` is generated at default path (\~.keeper) with default level `INFO`. You can disable logging by setting `enabled: false` or can change log level (INFO, DEBUG, ERROR) by setting level value.

```yaml
   logging:
     enabled: true
     level: INFO
```

**Background Process Logging**

When running in **background mode**, service logs are stored in:

* **Location**: `keepercommander/service/core/logs/service_subprocess.log`
* **Content**: Subprocess output, errors, and service events
* **Auto-created**: Log directory is automatically created when service starts in background

**Ngrok Logging**

When ngrok tunneling is enabled, additional logs are maintained:

* **Location**: `keepercommander/service/core/logs/ngrok_subprocess.log`
* **Content**: Ngrok tunnel startup, connection events, public URL generation, and tunnel errors
* **Includes**: Tunnel establishment, reconnection attempts, and ngrok-specific error messages
* **Auto-created**: Created automatically when ngrok tunneling is configured and service starts

**Cloudflare Logging**

When Cloudflare tunneling is enabled, additional logs are maintained:

* **Location**: `keepercommander/service/core/logs/cloudflare_tunnel_subprocess.log`
* **Content**: Cloudflare tunnel startup, connection events, public URL generation, and tunnel errors
* **Includes**: Tunnel establishment, reconnection attempts, and Cloudflare-specific error messages
* **Auto-created**: Created automatically when Cloudflare tunneling is configured and service starts
