Quick Start
Get Porta running in 5 minutes with Docker.
Prerequisites
- Docker with Docker Compose v2+
Looking for other setup methods?
This guide uses Docker Hub images for the fastest setup. For cloning the repo or developing from source, see Setup Alternatives.
Automated Install
The installer writes docker-compose.yml and a .env with generated secrets, starts the stack, applies migrations, and optionally bootstraps the admin system:
curl -fsSL https://raw.githubusercontent.com/blendsdk/porta-identity/main/install-porta.sh | bashIt prompts for your public URL and SMTP relay, scans for a free host port to publish, and prints an nginx reverse-proxy example. For an unattended install, pass flags instead (run the script with --help for the full list):
curl -fsSL https://raw.githubusercontent.com/blendsdk/porta-identity/main/install-porta.sh \
| bash -s -- \
--issuer-url https://auth.example.com \
--smtp-host smtp.example.com --smtp-from noreply@example.comRe-running with --force reuses every saved answer and only asks for keys that are missing or empty. --check lists those values without changing anything, and --fresh ignores the saved file and starts over.
The manual steps below describe the same deployment file by file.
Step 1: Create a Project Directory
mkdir porta && cd portaStep 2: Generate Required Secrets
Required — Do Not Skip
Porta requires 3 cryptographic secrets to operate securely. These protect session cookies, 2FA secrets, and signing keys. You must generate unique values — do not use the defaults or placeholders.
Run these commands to generate all three secrets:
# 1. Cookie signing key (base64, at least 32 chars)
echo "COOKIE_KEYS=$(openssl rand -base64 32)"
# 2. Two-Factor encryption key (64 hex chars = 32 bytes, AES-256-GCM)
echo "TWO_FACTOR_ENCRYPTION_KEY=$(node -e "console.log(require('crypto').randomBytes(32).toString('hex'))")"
# 3. Signing key encryption key (64 hex chars = 32 bytes, AES-256-GCM)
echo "SIGNING_KEY_ENCRYPTION_KEY=$(node -e "console.log(require('crypto').randomBytes(32).toString('hex'))")"Save the output — you'll paste these into your .env file in Step 4.
| Secret | Purpose | Format |
|---|---|---|
COOKIE_KEYS | Signs OIDC session cookies | Base64 string, ≥32 chars |
TWO_FACTOR_ENCRYPTION_KEY | Encrypts TOTP authenticator secrets at rest | 64 hex characters (32 bytes) |
SIGNING_KEY_ENCRYPTION_KEY | Encrypts ES256 signing key private keys at rest | 64 hex characters (32 bytes) |
Step 3: SMTP — Email is Required
Porta requires a working SMTP server
Magic links, user invitations, password resets, and email-based 2FA all send emails. Without SMTP, these features will fail silently.
For local development, we include MailHog in the Docker Compose file below — it catches all outgoing emails and provides a web inbox at http://localhost:8025. No extra setup needed.
For production, configure a real SMTP server:
| Variable | Example | Description |
|---|---|---|
SMTP_HOST | smtp.sendgrid.net | SMTP server hostname |
SMTP_PORT | 587 | SMTP port (587 for STARTTLS, 465 for SSL) |
SMTP_USER | apikey | SMTP username |
SMTP_PASS | SG.xxxxx | SMTP password or API key |
SMTP_FROM | noreply@yourdomain.com | Sender email address |
Popular options: SendGrid, Amazon SES, Postmark, Mailgun, or any SMTP-compatible service.
Step 4: Create docker-compose.yml
Create a file called docker-compose.yml:
services:
# ── Porta OIDC Provider ─────────────────────
porta:
image: blendsdk/porta:latest
container_name: porta-app
restart: unless-stopped
ports:
- '${PORT:-3000}:3000'
env_file:
- .env
environment:
DATABASE_URL: postgresql://porta:${POSTGRES_PASSWORD:-porta_secret}@postgres:5432/porta
REDIS_URL: redis://redis:6379
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
healthcheck:
test: ['CMD', 'curl', '-f', 'http://localhost:3000/health']
interval: 30s
timeout: 5s
start_period: 30s
retries: 3
# ── PostgreSQL 16 ───────────────────────────
postgres:
image: postgres:16-alpine
container_name: porta-postgres
restart: unless-stopped
environment:
POSTGRES_DB: porta
POSTGRES_USER: porta
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-porta_secret}
volumes:
- porta_pgdata:/var/lib/postgresql/data
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U porta']
interval: 5s
timeout: 5s
retries: 5
# ── Redis 7 ─────────────────────────────────
redis:
image: redis:7-alpine
container_name: porta-redis
restart: unless-stopped
healthcheck:
test: ['CMD', 'redis-cli', 'ping']
interval: 5s
timeout: 5s
retries: 5
# ── MailHog (dev email testing) ─────────────
mailhog:
image: mailhog/mailhog
container_name: porta-mailhog
ports:
- '8025:8025' # Web UI
- '1025:1025' # SMTP
profiles:
- dev
volumes:
porta_pgdata:
driver: localMailHog for development
Start with docker compose --profile dev up -d to include MailHog. Then open http://localhost:8025 to see all emails Porta sends.
Step 5: Create .env
Create a .env file and paste in your generated secrets from Step 2:
# ── Server ────────────────────────────────────
NODE_ENV=production
PORT=3000
HOST=0.0.0.0
# ── Database ──────────────────────────────────
POSTGRES_PASSWORD=porta_secret
# ── OIDC ──────────────────────────────────────
ISSUER_BASE_URL=https://porta.local:3443
# ── Secrets (paste values from Step 2) ────────
COOKIE_KEYS=<paste-your-cookie-key-here>
TWO_FACTOR_ENCRYPTION_KEY=<paste-your-2fa-key-here>
SIGNING_KEY_ENCRYPTION_KEY=<paste-your-signing-key-here>
# ── Email (MailHog for dev, real SMTP for prod)
SMTP_HOST=mailhog
SMTP_PORT=1025
SMTP_USER=
SMTP_PASS=
SMTP_FROM=noreply@porta.local
# ── Logging ───────────────────────────────────
LOG_LEVEL=info
# ── Startup ───────────────────────────────────
PORTA_AUTO_MIGRATE=true
TRUST_PROXY=falseReplace the secret placeholders!
Replace <paste-your-cookie-key-here>, <paste-your-2fa-key-here>, and <paste-your-signing-key-here> with the values you generated in Step 2. Porta will refuse to start with placeholder values in production.
Step 6: Start Services
# For development (with MailHog email testing):
docker compose --profile dev up -d
# For production (without MailHog):
docker compose up -dWait a few seconds for PostgreSQL and Redis to become healthy, then verify:
curl https://porta.local:3443/healthYou should see {"status":"ok","database":"ok","redis":"ok"}.
Step 7: Bootstrap the Admin System
docker exec -it porta-app porta initThis interactive command creates:
- The super-admin organization (
porta-admin) - The admin application with 42 RBAC permissions
- A PKCE client for CLI authentication
- Your first admin user (you'll be prompted for email, name, and password)
You can also run it non-interactively:
docker exec porta-app porta init \
--email admin@example.com \
--given-name Admin \
--family-name User \
--password 'YourSecurePassword123!'Step 8: Install the Standalone CLI
The Porta Docker image includes infrastructure commands only (init, migrate, seed, health). For full admin management, install the standalone CLI on your workstation:
npm install -g @portaidentity/cliThen authenticate against your Porta server:
porta login --server https://porta.local:3443The CLI opens your browser for OIDC authentication. After logging in, you can manage everything:
porta whoami # Check current identity
porta org list # List organizations
porta version # Show CLI/SDK/server versionsDocker wrapper (infrastructure only)
For init/migrate commands inside the container, you can also download the wrapper script:
curl -fsSL https://raw.githubusercontent.com/blendsdk/porta-identity/main/docker/porta.sh \
-o porta && chmod +x porta
./porta init
./porta migrate statusStep 9: Configure Your Environment
Before you provision applications and clients
Applications, modules, roles, permissions, and claim definitions are deployment-global; your organization owns its clients, users, and assignments. Read the Core ownership model before you create them.
Open the interactive administration shell:
porta admin --server https://porta.local:3443Create the organization, applications, roles, permissions, users, and OIDC clients needed by your project. Existing command-line CRUD commands are also available when you prefer scripts.
Moving configuration from another Porta installation
Export a selective JSON manifest from the source and import it into this installation. Import always previews before it applies changes.
porta export manifest \
--organization my-company \
--category organizations \
--category applications_authorization \
--all-applications \
--output my-company-porta.json
porta import manifest my-company-porta.json --mode keep-existingRead Environment Portability for category selection, import modes, and credential handling.
Step 10: Verify Everything Works
# Check health
curl https://porta.local:3443/health
# List organizations with the standalone CLI
porta org list
# Open MailHog to see test emails (if using dev profile)
# http://localhost:8025Open https://porta.local:3443/health in your browser to confirm the server, database, and Redis are all connected.
Stopping & Cleanup
# Stop all services
docker compose down
# Stop and delete all data (fresh start)
docker compose down -vTroubleshooting
Container won't start
docker compose logs portaCommon causes:
- Missing or placeholder secrets — check your
.env(see Step 2) - PostgreSQL not ready yet — the entrypoint waits up to 60 seconds
- Port 3000 already in use — change
PORTin your.envfile
Emails not being sent
- Development: Make sure you started with
--profile devfor MailHog, and check http://localhost:8025 - Production: Verify your SMTP settings. Test with
telnet your-smtp-host 587. - Check Porta logs:
docker compose logs porta | grep -i smtp
Login page loads but authentication fails
Most likely missing TRUST_PROXY=true when running behind a TLS-terminating reverse proxy (nginx, Traefik, cloud load balancer). See Environment Variables → Reverse Proxy.
Health check failing
docker compose ps # All services should show "healthy"
docker compose logs postgres # Check databaseNext Steps
- 📖 Architecture Overview — How Porta is designed
- 🔁 Environment Portability — Selective manifest export and import
- 💻 CLI Reference — All CLI commands
- 📋 Admin API — REST API reference
- 🔑 OIDC & Authentication — How OIDC works in Porta
- 🏢 Multi-Tenancy — Organization-scoped tenancy model
- ⚙️ Environment Variables — Complete configuration reference
- 🚢 Deployment Guide — Production deployment guidance
- 🖥️ Setup Alternatives — Clone & Docker or source development setup