For development and debugging integrations, you can run Stronghold locally in Docker. Use such an instance for development only: do not store real secrets in it.

Building the image

The image is built from the Stronghold binary with stronghold bootstrap docker:

stronghold bootstrap docker
docker load -i stronghold-v1.19.0.tar

By default, the image is tagged stronghold:<VERSION>, where <VERSION> is the Stronghold version, for example stronghold:1.19.0.

Development mode

The default container command is stronghold server -dev. In development mode, Stronghold:

  • keeps data in memory — everything is lost when the container stops;
  • initializes and unseals automatically;
  • prints the root token to the log;
  • runs without TLS.

Start the container. By default, development mode listens only on 127.0.0.1 inside the container, so the published port would not be reachable. Set the listen address explicitly:

docker run --rm --name stronghold-dev -p 8200:8200 stronghold:1.19.0 stronghold server -dev -dev-listen-address=0.0.0.0:8200

Find the root token in the container log (the Root Token line) and configure the client:

export STRONGHOLD_ADDR=http://127.0.0.1:8200
export STRONGHOLD_TOKEN=<ROOT_TOKEN>
d8 stronghold status

Replace <ROOT_TOKEN> with the root token from the container log.

For Vault client libraries, set the same values in VAULT_ADDR and VAULT_TOKEN. For details, see Application clients.

To set a predictable root token, add the -dev-root-token-id parameter:

docker run --rm --name stronghold-dev -p 8200:8200 stronghold:1.19.0 stronghold server -dev -dev-root-token-id=root -dev-listen-address=0.0.0.0:8200

Single-node Raft configuration in Docker Compose

If data must persist across restarts, run Stronghold with a configuration file and Raft storage.

  1. Create config/stronghold.hcl (the format is described in Configuration):

    ui            = true
    disable_mlock = true
    api_addr      = "http://127.0.0.1:8200"
    cluster_addr  = "http://127.0.0.1:8201"
    
    storage "raft" {
      path    = "/stronghold/data"
      node_id = "dev-node-1"
    }
    
    listener "tcp" {
      address     = "0.0.0.0:8200"
      tls_disable = true
    }

    tls_disable = true is acceptable only on a local developer machine.

  2. Create compose.yaml:

    services:
      stronghold:
        image: stronghold:1.19.0
        command: ["stronghold", "server", "-config=/stronghold/config/stronghold.hcl"]
        ports:
          - "8200:8200"
        volumes:
          - ./config:/stronghold/config:ro
          - stronghold-data:/stronghold/data
        restart: unless-stopped
    
    volumes:
      stronghold-data:

    The image runs as root (no user is set in the image), so no additional permissions on the /stronghold/data volume are needed. The image has no ENTRYPOINT: the full command is passed, as in the example.

  3. Start the container:

    docker compose up -d
  4. Initialize and unseal Stronghold. For local development, a single key is enough:

    export STRONGHOLD_ADDR=http://127.0.0.1:8200
    d8 stronghold operator init -key-shares=1 -key-threshold=1
    d8 stronghold operator unseal

    Save the unseal key and root token from the operator init output. After each container restart, run d8 stronghold operator unseal.

  5. Log in with the root token and enable the engines you need, for example KV version 2:

    export STRONGHOLD_TOKEN=<ROOT_TOKEN>
    d8 stronghold secrets enable -path=secret -version=2 kv
    d8 stronghold kv put -mount=secret myapp/db username=app password=S3cr3t

    Replace <ROOT_TOKEN> with the root token from the operator init output.

The web UI is available at http://127.0.0.1:8200/ui.

Running an application next to Stronghold

An application in the same compose.yaml reaches Stronghold by service name. Add the app service to the services section of the compose.yaml file from the previous section:

services:
  app:
    image: registry.example.com/myapp:1.0.0
    environment:
      VAULT_ADDR: http://stronghold:8200
      VAULT_TOKEN: <ROOT_TOKEN>
    depends_on:
      - stronghold

Replace <ROOT_TOKEN> with the root token from the operator init output. Stronghold with Raft storage does not create a root token with a predefined value, as -dev-root-token-id does in development mode.

A token in an environment variable is acceptable only for local development. In real environments, use the auth methods described in Delivering secrets to Kubernetes pods and Application clients.