Self-Hosted Deployment
Deploy Aira on your own infrastructure with a single command.
Quick Start
curl -sSL https://get.airaproof.com/install.sh | bashThe installer prompts for your license key, registry token, domain, and AI provider keys. It generates all secrets, configures HTTPS, and starts everything automatically.
Contact support@airaproof.com to get your license key and registry token.
What gets installed
https://governance.acme.com
|
[Traefik] — automatic HTTPS (Let's Encrypt)
|
-----+-----
| |
/api/* /*
| |
[API] [Frontend]
|
[Worker] [PostgreSQL 17] [Redis 7]All services run as Docker containers on a single domain. Traefik routes /api/* to the backend and everything else to the dashboard.
| Service | Image | Purpose |
|---|---|---|
| Traefik v3.6 | traefik:v3.6 | Reverse proxy with automatic HTTPS |
| API | ghcr.io/aira-proof/backend | FastAPI — authorization, notarization, policies, chat |
| Frontend | ghcr.io/aira-proof/frontend | Next.js dashboard |
| Worker | ghcr.io/aira-proof/backend | Celery background tasks and webhooks |
| PostgreSQL 17 | postgres:17-alpine | Database |
| Redis 7 | redis:7-alpine | Cache and job queue |
Prerequisites
Server
| Requirement | Minimum | Recommended |
|---|---|---|
| OS | Ubuntu 22.04 / Debian 12 / RHEL 9 | Ubuntu 24.04 LTS |
| CPU | 4 vCPUs | 8 vCPUs |
| RAM | 8 GB | 16 GB |
| Disk | 40 GB SSD | 100 GB NVMe SSD |
| Network | 100 Mbps | 1 Gbps |
Software
- Docker 24+ with Docker Compose v2
openssl(for key generation)
Network
- Domain name (e.g.,
governance.acme.com) with a DNS A record pointing to the server IP - Ports 80 and 443 open in your firewall
- No other web server running on the same ports
Credentials
Contact support@airaproof.com to receive:
- License key — Ed25519-signed, validates at startup and per-request. Encodes your org name, tier, expiry, and domain.
- Registry token — grants access to pull Docker images from
ghcr.io/aira-proof/*
Installation
The installer handles everything:
- Authenticates with the container registry
- Generates all cryptographic keys (JWT secret, Ed25519 signing keys, database password)
- Writes
docker-compose.yml,.env, anddocker-compose.yml - Pulls Docker images
- Runs database migrations
- Starts all services with health checks
- Obtains a TLS certificate from Let's Encrypt
curl -sSL https://get.airaproof.com/install.sh | bashThe script prompts for:
| Input | Required | Description |
|---|---|---|
| License key | Yes | Provided by Aira team |
| Registry token | Yes | For pulling Docker images |
| Domain | Yes | Your deployment domain |
| OpenAI API key | No | Enables GPT models |
| Anthropic API key | No | Enables Claude models |
| Google API key | No | Enables Gemini models |
| Custom TLS certs | No | Default: automatic Let's Encrypt |
All config files are written to /opt/aira.
After installation
Open https://your-domain.com and register your admin account. Email verification is skipped in self-hosted mode — you can log in immediately.
Interactive API docs
Your instance includes Swagger UI and ReDoc:
- Swagger:
https://your-domain.com/docs - ReDoc:
https://your-domain.com/redoc
SDK configuration
Point your SDKs to your self-hosted domain:
from aira import Aira
aira = Aira(
api_key="aira_live_...",
base_url="https://governance.acme.com",
)import { Aira } from "aira-sdk";
const aira = new Aira({
apiKey: "aira_live_...",
baseUrl: "https://governance.acme.com",
});Note: the base_url is your domain root (not /api/v1). The SDK adds the API prefix automatically.
Manage
cd /opt/aira
# View API logs
docker compose logs -f api
# Upgrade to latest version
./upgrade.sh
# Backup database
./backup.sh
# Stop all services
docker compose down
# Restart
docker compose up -d
# Uninstall
./uninstall.shUpgrade
cd /opt/aira && ./upgrade.shThis backs up the database, pulls latest images, runs migrations, and rolls out services with zero downtime using docker-rollout. New containers start and pass health checks before old ones are removed — no request is dropped.
Backup
cd /opt/aira && ./backup.shCreates a compressed PostgreSQL dump in backups/. Keeps the 14 most recent backups automatically.
Configuration
All configuration is in /opt/aira/.env. After editing, restart affected services:
docker compose up -d --force-recreate api worker frontendAdding AI providers later
Edit .env:
OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=sk-ant-...
GOOGLE_API_KEY=AIza...
DEEPSEEK_API_KEY=sk-...
XAI_API_KEY=xai-...Then restart with zero downtime: docker rollout api && docker compose restart worker
You can also configure provider keys from the dashboard under Models > Providers using the BYOK API.
Environment variables
Required (generated by installer)
| Variable | Description |
|---|---|
AIRA_LICENSE_KEY | Ed25519-signed license key |
DOMAIN | Your deployment domain |
SECRET_KEY | JWT signing key (auto-generated) |
DB_PASS | PostgreSQL password (auto-generated) |
AUTH_SECRET | NextAuth session encryption (auto-generated) |
SIGNING_PRIVATE_KEY_HEX | Ed25519 receipt signing key (auto-generated) |
POLICY_EVALUATOR_PRIVATE_KEY_HEX | Ed25519 policy evaluator key (auto-generated) |
Optional
| Variable | Default | Description |
|---|---|---|
OPENAI_API_KEY | — | OpenAI provider key |
ANTHROPIC_API_KEY | — | Anthropic provider key |
GOOGLE_API_KEY | — | Google provider key |
SMTP_HOST/PORT/USER/PASSWORD | — | SMTP for email notifications |
AUTH_GOOGLE_ID/SECRET | — | Google OAuth (social login) |
AUTH_GITHUB_ID/SECRET | — | GitHub OAuth (social login) |
RATE_LIMIT_PER_MINUTE | 60 | Rate limit for authenticated requests |
Custom TLS certificates
If you can't use Let's Encrypt (internal network, air-gapped, custom CA):
- The installer will ask during setup, or
- Place your files manually:
cp your-cert.pem /opt/aira/certs/cert.pem
cp your-key.pem /opt/aira/certs/key.pemCreate /opt/aira/dynamic/certs.yml:
tls:
certificates:
- certFile: /certs/cert.pem
keyFile: /certs/key.pemRestart Traefik: docker compose restart traefik
SSO / Social Login
Self-hosted deployments support the same SSO options as cloud:
- SAML 2.0 — Okta, Azure AD, Google Workspace, OneLogin
- OpenID Connect — any OIDC-compliant provider
- Social logins — Google, GitHub, GitLab (optional)
For social login, create OAuth apps in your provider's console with this redirect URI:
https://governance.acme.com/api/auth/callback/{provider}Where {provider} is google, github, or gitlab.
For SAML/OIDC enterprise SSO, configure from Dashboard > Settings > Single Sign-On.
Social login and email are both optional. Email/password works without any additional configuration. Email verification is skipped in self-hosted mode.
Self-hosted vs Cloud
| Feature | Cloud | Self-hosted |
|---|---|---|
| AI provider keys | Aira-managed or BYOK | BYOK only |
| Billing | Stripe (metered) | Flat license fee |
| Usage limits | Plan-based | Unlimited |
| Email verification | Required | Skipped (auto-verified) |
| SSO / SAML / OIDC | All plans | Included |
| Data residency | EU (Frankfurt) | Your infrastructure |
| Updates | Automatic | ./upgrade.sh |
| License | Not required | Required |
| Domains | Single domain per service | Single domain (Traefik proxy) |
| HTTPS | Managed | Auto (Let's Encrypt) or custom certs |
Troubleshooting
License errors
"FATAL: Self-hosted deployment requires AIRA_LICENSE_KEY" — set AIRA_LICENSE_KEY in .env. Contact support@airaproof.com if you don't have one.
"FATAL: Invalid AIRA_LICENSE_KEY" — the key is malformed, expired, or tampered with. Check the full key was copied (long base64url string with two dots).
API returns 403 "License invalid" — the license expired at runtime. Renew and restart: docker rollout api
API won't start
docker compose logs api --tail 30Common causes:
- Missing/expired license key
- Database not ready — wait or
docker rollout api - Port conflict — ensure nothing else is on port 8000 internally
TLS certificate issues
docker compose logs traefik --tail 20- NXDOMAIN — DNS A record not set for your domain
- Rate limited — Let's Encrypt allows 5 duplicate certs per week. Wait or use custom certs.
- Port 80 blocked — Traefik needs port 80 for ACME HTTP-01 challenges
Can't pull images
docker pull ghcr.io/aira-proof/backend:latestIf this fails, re-authenticate: echo $TOKEN | docker login ghcr.io -u aira-customer --password-stdin
Database password mismatch
If you changed DB_PASS after initial setup:
docker compose exec db psql -U aira -c "ALTER USER aira PASSWORD 'new-password';"Or reset completely: docker compose down -v && docker compose up -d