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
-
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.
-
The IPC_LOCK capability was a red herring. Adding
cap_add: - IPC_LOCKfixed the IPC_LOCK warning but didn’t resolve the binding error. -
The vault.hcl syntax validation passed, with
cat -Aconfirming no trailing whitespace or hidden characters after fixing with:sudo sed -i 's/[[:space:]]*$//' vault.hcl -
Docker maintains its own port allocation state that persists even after containers stop and networks are pruned. The
docker.sockitself 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:
- Docker’s network driver caching old allocations
- A zombie container holding the namespace
- 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.