HashiCorp Vault Failing to Bind Port 8200 in Docker Compose — Port Appears Free on Host

Environment

  • Docker: 29.5.2
  • Docker Compose: v5.1.4
  • OS: Ubuntu 26.04 LTS (ARM64)
  • Kernel: 7.0.0-15-generic
  • Vault Image: hashicorp/vault:1.15.0

The Problem

My Vault container starts but immediately exits with the following error:

Error initializing listener of type tcp: listen tcp4 0.0.0.0:8200: bind: address already in use

The puzzling part: nothing is actually using port 8200 on the host. I’ve verified this with:

sudo lsof -i :8200      # No output
sudo ss -tlnp | grep 8200 # No output
sudo netstat -tulpn | grep 8200 # No output

Yet Docker insists the port is occupied. This has persisted even after:

  • Stopping all containers
  • Restarting the Docker daemon
  • Clearing Docker networks and volumes
  • Changing to different ports (8201, 8202, etc.)
  • Removing orphaned containers
  • Restarting the entire system

What I’ve Tried

1. Basic Cleanup

docker container prune -f
docker network prune -f
sudo systemctl restart docker
docker system prune -a --volumes -f

2. Configuration Validation

vault.hcl

storage "file" {
  path = "/vault/data"
}

listener "tcp" {
  address         = "0.0.0.0:8200"
  tls_disable     = true
  tls_min_version = "tls12"
}

api_addr = "http://vault:8200"
cluster_addr = "http://vault:8201"

ui = true
disable_mlock = true

Docker Compose Service

services:
  vault:
    image: hashicorp/vault:1.15.0
    cap_add:
      - IPC_LOCK
    ports:
      - "8200:8200"
      - "8201:8201"
    environment:
      VAULT_ADDR: "http://127.0.0.1:8200"
      VAULT_API_ADDR: "http://127.0.0.1:8200"
    volumes:
      - ./vault-data:/vault/data
      - ./vault-config:/vault/config
      - ./vault-logs:/vault/logs
    command:
      - server
      - "-config=/vault/config/vault.hcl"
    healthcheck:
      test: ["CMD", "vault", "operator", "status"]
      interval: 10s
      timeout: 10s
      retries: 5
      start_period: 30s
    networks:
      - girl-network

3. Port Diagnostics

# Check for any process binding 8200
sudo lsof -i TCP:8200
sudo ss -ltnp '( sport = :8200 )'
sudo netstat -tlnp | grep :8200

# Force kill any process on 8200
sudo fuser -k 8200/tcp

# Flush ARP cache
sudo ip neigh flush all

All commands return empty or show nothing using the port.

4. YAML Command Structure

I changed from:

command: server -config=/vault/config/vault.hcl

To:

command:
  - server
  - "-config=/vault/config/vault.hcl"

The YAML string format passes the entire command as a single argument $1, which causes Vault’s entrypoint script to not recognize it as the server subcommand. The list format correctly splits the arguments.

The Actual Error in Logs

Error parsing listener configuration.
Error initializing listener of type tcp: listen tcp4 0.0.0.0:8200: bind: address already in use
2026-06-07T04:59:30.994Z [INFO] proxy environment: http_proxy="" https_proxy="" no_proxy=""

The Error parsing listener configuration appears before the bind error, suggesting something is wrong with how the listener is being read even before it attempts to bind.

What I’ve Learned

  1. Port binding error occurs inside the container, not on the host. Docker’s internal port allocation table can be out of sync with the OS network namespace.

  2. The IPC_LOCK capability was a red herring. Adding cap_add: - IPC_LOCK fixed the IPC_LOCK warning but didn’t resolve the binding error.

  3. The vault.hcl syntax validation passed, with cat -A confirming no trailing whitespace or hidden characters after fixing with:

    sudo sed -i 's/[[:space:]]*$//' vault.hcl
    
  4. Docker maintains its own port allocation state that persists even after containers stop and networks are pruned. The docker.sock itself can hold allocations.

Where I’m Stuck Now

The container still exits immediately on startup despite:

  • Port 8200 appearing completely free on the host
  • No process actually listening on that port
  • All cleanup commands showing nothing
  • Config files appearing valid
  • Command structure properly formatted as a list

The error message says the port is in use, but all system level tools confirm it’s free. This points to either:

  1. Docker’s network driver caching old allocations
  2. A zombie container holding the namespace
  3. An issue with how Vault is reading the config inside the container

My Goal

I’m trying to run HashiCorp Vault for secrets management to store API credentials (Twitch tokens, database credentials, etc.) for an Airflow based analytics pipeline. Once Vault is running, I need to execute an initialization script to set up policies and store secrets.

Any insight on why Docker would report a port as “already in use” when the entire system shows it’s free would be greatly appreciated. This has been driving me in circles for days.

Thanks in advance for any help. I’m happy to provide additional logs, configs, or debugging output.

Noticed you said you’re using 1.15. Do you get the same problem if you use a newer/supported version like 1.21?

What if you just run docker run and not from compose file?

   $ docker run \
         --name=learn-vault \
         --hostname=learn-vault \\
         --publish 8200:8200 \
         --env VAULT_ADDR="http://localhost:8200" \
         --env VAULT_CLUSTER_ADDR="http://learn-vault:8201" \
         --env VAULT_API_ADDR="http://learn-vault:8200" \
         --cap-add=IPC_LOCK \
         --detach \
         --rm \
         hashicorp/vault:1.21 vault server -dev -dev-listen-address 0.0.0.0:8200 -dev-root-token-id root

Can’t say i’ve run into this before but can try to replicate based on whether a newer version works and/or just docker run works.

1 Like