Getting Started
Installation

Installation

One-Line Installer (Recommended)

The interactive installer detects your OS, installs Docker if needed, generates secrets, configures TLS, and starts everything.

curl -fsSL https://vaultctl.vinelabs.de/install.sh | bash

What it does:

  1. Checks for Docker (installs if missing)
  2. Pulls the latest vaultctl + PostgreSQL images
  3. Generates cryptographic secrets (JWT, HMAC, encryption keys)
  4. Asks for your domain name
  5. Configures Caddy for automatic HTTPS via Let's Encrypt
  6. Starts all services
  7. Runs database migrations
  8. Prints your vault URL

The installer is fully interactive — it prompts before every action. You can review each step before proceeding.


Docker Images

Official multi-arch images (linux/amd64, linux/arm64) are published to both registries on every release. All images are signed with cosign (opens in a new tab) keyless signatures.

docker pull vineethnkrishnan/vaultctl:latest
 
# or pin to a specific version
docker pull vineethnkrishnan/vaultctl:1.1.3

Verify image signature

cosign verify vineethnkrishnan/vaultctl:latest \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  --certificate-identity-regexp 'github\.com/vineethkrishnan/vaultctl'

Run directly

docker run -d --name vaultctl \
  -p 8080:8080 \
  -e VAULTCTL_DATABASE_URL="postgres://user:pass@host:5432/vaultctl?sslmode=disable" \
  -e VAULTCTL_JWT_SECRET_CURRENT="$(openssl rand -base64 32)" \
  -e VAULTCTL_SERVER_PEPPER="$(openssl rand -base64 32)" \
  -e VAULTCTL_ENUMERATION_PEPPER="$(openssl rand -base64 32)" \
  -e VAULTCTL_DATA_ENCRYPTION_KEY="$(openssl rand -base64 32)" \
  vineethnkrishnan/vaultctl:latest
⚠️

Always put a TLS-terminating reverse proxy (Caddy, nginx, Traefik) in front. Never expose port 8080 directly to the internet.


Docker Compose

Two compose variants are provided in the repository.

Full Stack — Caddy + vaultctl + PostgreSQL

Includes Caddy for automatic HTTPS via Let's Encrypt.

Clone the repository

git clone https://github.com/vineethkrishnan/vaultctl.git
cd vaultctl

Configure environment

cp .env.example .env

Edit .env and set these required values:

VAULTCTL_ENV=production
VAULTCTL_BASE_URL=https://vault.yourdomain.com
VAULTCTL_DB_PASSWORD=<generate-a-strong-password>

# Generate each with: openssl rand -base64 32
VAULTCTL_JWT_SECRET_CURRENT=<generate>
VAULTCTL_SERVER_PEPPER=<generate>
VAULTCTL_ENUMERATION_PEPPER=<generate>
VAULTCTL_DATA_ENCRYPTION_KEY=<generate>

Generate secrets

for var in JWT_SECRET_CURRENT SERVER_PEPPER ENUMERATION_PEPPER DATA_ENCRYPTION_KEY; do
  echo "VAULTCTL_${var}=$(openssl rand -base64 32)"
done >> .env

Start services

docker compose up -d

Verify

curl https://vault.yourdomain.com/api/v1/health
# → {"status":"ok"}

Binary

Pre-built binaries are available on GitHub Releases (opens in a new tab) for all major platforms. Each release includes SHA-256 checksums signed with cosign and per-archive SBOMs.

# amd64
curl -L https://github.com/vineethkrishnan/vaultctl/releases/latest/download/vaultctl_linux_amd64.tar.gz | tar xz
 
# arm64
curl -L https://github.com/vineethkrishnan/vaultctl/releases/latest/download/vaultctl_linux_arm64.tar.gz | tar xz
 
sudo mv vaultctl /usr/local/bin/

Verify checksums

# Download checksums and signature
curl -LO https://github.com/vineethkrishnan/vaultctl/releases/latest/download/checksums.txt
curl -LO https://github.com/vineethkrishnan/vaultctl/releases/latest/download/checksums.txt.sig
curl -LO https://github.com/vineethkrishnan/vaultctl/releases/latest/download/checksums.txt.pem
 
# Verify signature
cosign verify-blob checksums.txt \
  --signature checksums.txt.sig \
  --certificate checksums.txt.pem \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  --certificate-identity-regexp 'github\.com/vineethkrishnan/vaultctl'
 
# Verify file integrity
sha256sum -c checksums.txt --ignore-missing

Prerequisites

  • PostgreSQL 16+ running and accessible
  • A reverse proxy (Caddy or nginx) for TLS termination

Run

# Run database migrations
vaultctl migrate up
 
# Start the server (listens on :8080)
vaultctl server

Kubernetes

A Helm chart is planned for a future release. For now, use the Docker image directly:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: vaultctl
spec:
  replicas: 1
  selector:
    matchLabels:
      app: vaultctl
  template:
    metadata:
      labels:
        app: vaultctl
    spec:
      containers:
        - name: vaultctl
          image: ghcr.io/vineethkrishnan/vaultctl:latest
          ports:
            - containerPort: 8080
          envFrom:
            - secretRef:
                name: vaultctl-secrets
          livenessProbe:
            httpGet:
              path: /api/v1/health
              port: 8080
            initialDelaySeconds: 5
          readinessProbe:
            httpGet:
              path: /api/v1/health
              port: 8080
            initialDelaySeconds: 3
---
apiVersion: v1
kind: Service
metadata:
  name: vaultctl
spec:
  selector:
    app: vaultctl
  ports:
    - port: 80
      targetPort: 8080

Create a Secret with all required environment variables. See the Configuration page for the complete list.

You can use either ghcr.io/vineethkrishnan/vaultctl or vineethnkrishnan/vaultctl (Docker Hub) — both are identical multi-arch images.


Post-Installation

After installation, open your browser and navigate to your server URL.

  1. Click Create Account
  2. Follow the Your First Account guide
  3. Install the Browser Extension
⚠️

Security reminder: Each cryptographic secret (JWT_SECRET, SERVER_PEPPER, ENUMERATION_PEPPER, DATA_ENCRYPTION_KEY) must be unique. Never reuse secrets across deployments. Store them separately from database backups.