Self-Host in 15 Minutes
Get a fully functional Tank registry running on your infrastructure with a single docker compose up.
Prerequisites
- Docker Engine 24+ and Docker Compose v2
- 4 GB RAM, 20 GB disk
- A domain pointing to your server (or use localhost for testing)
Quick Start
Minimal docker run (single Tank container)
If you already have a PostgreSQL database URL, you can preview Tank with a single tank-web container and local filesystem storage.
Trade-off: this is the smallest possible preview setup. For publishing scans and S3-compatible package storage, use the full compose file with RustFS + scanner.
docker run --rm -p 3000:3000 \
-e DATABASE_URL='postgresql://USER:PASSWORD@HOST:5432/DBNAME' \
-e BETTER_AUTH_SECRET='change-me' \
-e APP_URL='http://localhost:3000' \
-e STORAGE_BACKEND='filesystem' \
-e STORAGE_FS_PATH='/app/data/packages' \
-e TANK_MODE='selfhosted' \
-e AUTO_MIGRATE='true' \
-e AUTH_PROVIDERS='credentials' \
-v tank-data:/app/data \
ghcr.io/tankpkg/tank-web:latest
Use this when you want to try the UI and setup flow without running separate storage containers.
1. Create a directory and download the compose file
mkdir tank && cd tank
curl -fsSL https://raw.githubusercontent.com/tankpkg/tank/main/infra/docker-compose.production.yml -o docker-compose.yml
2. Create your environment file
cat > .env << 'EOF'
# Required — generate a unique secret
BETTER_AUTH_SECRET=$(openssl rand -base64 32)
# Database (uses bundled PostgreSQL)
DATABASE_URL=postgresql://tank:tank@postgres:5432/tank
# Your registry URL (change for production)
APP_URL=http://localhost:3000
# Scanner
PYTHON_API_URL=http://scanner:8000
# Headless admin bootstrap (optional — or use the web wizard)
# [email protected]
# FIRST_ADMIN_PASSWORD=changeme123
# Override default registry URL (for CLI pointing to this instance)
# TANK_REGISTRY_URL=http://localhost:3000
EOF
Tip: For automated deployments without the web wizard, uncomment
FIRST_ADMIN_EMAILandFIRST_ADMIN_PASSWORD.
3. Start everything
docker compose up -d
Image tags: The compose file builds from source by default (no internet needed). For pre-built images, edit
docker-compose.production.ymland use:latest(stable) or:nightly(bleeding edge).
This starts PostgreSQL, RustFS (storage), the security scanner, and the Tank web app. Database tables are created automatically on first boot.
Note on Images: By default,
docker compose upuses the:nightlyimage tags to ensure you have the latest features. For production environments, we strongly recommend pinning to a specific version tag (e.g.,:v0.8.1) or the:lateststable tag.
4. Open the Setup Wizard
Visit http://localhost:3000/setup in your browser. The wizard walks you through:
- Database — connection is pre-configured from your
.env - URL — confirm your registry's public URL
- Storage — choose RustFS (default), S3, or local filesystem
- Admin Account — create your first admin user
- Authentication — optionally configure GitHub OAuth or OIDC SSO
- Scanner — configure LLM for enhanced security analysis (optional)
- Complete — save configuration and start using Tank
5. Verify
# Health check
curl http://localhost:3000/api/health
# → {"status":"ok"}
# Point your CLI to your instance
tank login --registry http://localhost:3000
What's Next
- Add GitHub OAuth: Create a GitHub OAuth App with callback URL
https://your-domain/api/auth/callback/github - Add OIDC SSO: Configure your identity provider in the setup wizard or via env vars
- Production hardening: See the full Self-Hosting Guide for TLS, backups, monitoring, and Kubernetes deployment
- Local LLM: Add
--profile llm-localto use Ollama for security analysis without external API calls
Headless Mode (CI/CD)
For fully automated deployments without the wizard:
FIRST_ADMIN_EMAIL=[email protected] \
FIRST_ADMIN_PASSWORD=securepassword \
AUTO_MIGRATE=true \
docker compose up -d
This creates the admin user and skips the setup wizard entirely.