AI AdminPanel Documentation

Installation

AI Admin Panel installs on a fresh Linux server and sets up everything: Docker, PostgreSQL, Valkey, Traefik (auto-SSL), Keycloak (OIDC auth), OpenBao (secrets manager), and the panel itself.

Prerequisites

Server Requirements

RequirementMinimumRecommended
CPU2 cores4+ cores
RAM4 GB8+ GB
Disk20 GB SSD50+ GB SSD
OSAny certified Linux distro (see below)Ubuntu 24.04 LTS / Rocky Linux 9
Architecturex86_64 (amd64), aarch64 (arm64)x86_64

Supported Linux Distributions

The installer detects your distribution by package manager + version floor (not a fixed allowlist), so newer minor/point releases of a supported family work automatically. It requires systemd (Docker is managed via systemctl) and rootful Docker on a 64-bit host; on RHEL-family distros it installs Docker from Docker's official repository and handles SELinux (:z labels) and firewalld automatically.

TierDistributionsBehaviour
Certified — tested in CI on every releaseUbuntu 22.04 / 24.04 / 26.04 LTS · Debian 12 / 13 · Rocky Linux 9 / 10 · AlmaLinux 9 / 10 · RHEL 9 / 10 · CentOS Stream 9 / 10Fully supported
Best-effortFedora (current) · Oracle Linux 8 / 9 / 10 · Amazon Linux 2023Installs and runs; warns it isn't in the certified matrix
CommunityopenSUSE Leap / SLES · Arch LinuxDetected; best-effort (SUSE has no official Docker repo, so Docker may need installing first)
Not supportedAlpine / OpenRC (no systemd) · EOL releases (Ubuntu ≤ 20.04, Debian ≤ 11, CentOS Linux 7 / 8, Amazon Linux 2) · 32-bit · OpenVZ / unprivileged LXCInstaller stops with a clear message naming what is supported

DNS Requirements

No domain? You don't need one. Leave the installer's domain prompt empty (or run unattended without PANEL_DOMAIN) and it claims a free temporary domain for you — like aap-x7k2f9.aiadminpanel.host — points it at your server, and gives the panel, login, and every deployed service working HTTPS automatically. No DNS records to create, no terminal. Verify your email in the panel afterwards to keep it, or disable the whole path with MANAGED_DOMAIN=off. Full details in "No Domain? Get a Free Temporary One" below.

Bringing your own domain? Point it to the server before installing:

  1. A recordpanel.example.com → your server IP
  2. Wildcard A record*.panel.example.com → same server IP

The wildcard record is essential — every deployed service gets a subdomain like myapp.panel.example.com.

Tip: Cloudflare Users — Disable the orange proxy cloud during installation so Let's Encrypt can issue certificates via the HTTP challenge. Re-enable it after setup if desired. Alternatively, install with TLS_MODE=cloudflare + CF_DNS_API_TOKEN to use the DNS-01 challenge — that needs no inbound port 80, so you can leave the proxy on (see Configuration → DNS-01 Certificates).

Network Requirements

PortDirectionPurpose
80InboundHTTP → auto-redirects to HTTPS
443InboundHTTPS (Traefik terminates SSL)
22InboundSSH access

No other services should be running on ports 80/443.

Automated Install

curl -fsSL https://get.aiadminpanel.com -o install.sh && bash install.sh

The installer will ask for your domain, then handle everything else automatically. At the end it prints your admin URL, email, and password.

To skip the prompt (CI/automation), set environment variables:

PANEL_DOMAIN="panel.example.com" ACME_EMAIL="admin@example.com" \
  curl -fsSL https://get.aiadminpanel.com | bash

Installer Options

FlagDescription
--dry-runPreview all actions without executing
--verboseEnable debug output
--unattendedNon-interactive mode (claims a free temporary domain when PANEL_DOMAIN is unset; set MANAGED_DOMAIN=off to require PANEL_DOMAIN)

Environment Variables

VariableRequiredDescription
PANEL_DOMAINNoBase domain (e.g., panel.example.com). Leave unset to claim a free temporary domain like aap-x7k2f9.aiadminpanel.host
MANAGED_DOMAINNoSet to off to disable the temporary-domain claim path (installs then require PANEL_DOMAIN)
MANAGED_DNS_URLNoClaim service base URL (default https://dns.aiadminpanel.com)
ACME_EMAILNoEmail for Let's Encrypt (default: admin@example.com)
CF_DNS_API_TOKENNoCloudflare API token for wildcard certs and auto-DNS
PANEL_VERSIONNoVersion to install (default: latest)
GOMEMLIMITNoGo memory limit (default: 0 = unlimited)
TLS_MODENoletsencrypt (default) or cloudflare (DNS-01; skips the public A-record pre-flight check)
AAP_FIX_ROUTINGNoSet to 1 to auto-fix a detected dual-default-route hazard on multi-homed VPSes (OVH/Hetzner). netplan hosts only; otherwise the installer just warns
ADMIN_PASSWORDNoOverride the auto-generated admin password
LICENSE_KEYNoLicense key for activation (omit for a 14-day trial)
OPENBAO_VERSIONNoPinned OpenBao secrets-manager image tag (default: 2.5.5)
SECRETS_BACKENDNoopenbao (default) or filefile disables the secrets manager entirely and falls back to the legacy encrypted-column storage
BAO_ADDRNoInternal address the panel uses to reach OpenBao (default: http://openbao:8200) — only needed for non-standard topologies
LITELLM_MASTER_KEYNoMaster key for the bundled LiteLLM AI gateway. The installer auto-generates a random per-install key — you don't normally set this. There is no shared default: a manual/advanced install that runs docker compose directly must provide it (the panel + gateway containers fail to start with a clear error otherwise)

No Domain? Get a Free Temporary One

If you don't have a domain yet, just leave the domain prompt empty (or run unattended without PANEL_DOMAIN): the installer claims a free temporary domain like aap-x7k2f9.aiadminpanel.host, points it at your server, and the panel, login, and every deployed service get working HTTPS under it automatically.

Temporary domains start with a 7-day provisional lease — verify your email in the panel to keep the domain (it then renews automatically while your panel is running). The claim credential is stored at /opt/aiadminpanel/secrets/managed_domain_token (root-only); don't delete it. Temporary domains are IPv4-only, limited to 3 claims per IP per day, and can be disabled entirely with MANAGED_DOMAIN=off.

Keeping your free domain

Once the install finishes, the panel itself takes over the domain's lifecycle — no terminal needed. Verify your email in either of two places:

  • The setup wizard's "Keep your free domain" step (second-to-last step, and skippable if you'd rather decide later).
  • Settings → DNS & Domains, in the "Your free domain" card: shows the domain, a verified/unverified badge, the lease expiry, the last renewal result, and a send/resend-verification-email form. A Renew now button is always available there too.

Click the link in the verification email and you're taken straight back into your panel's Settings → DNS & Domains page (a short "email confirmed" message appears and the "Your free domain" card flips to verified) — the lease stops being provisional and becomes a 60-day rolling lease that renews itself automatically. A background job checks the lease daily, renews it on a weekly cadence while things are healthy, and retries daily if a renewal attempt fails.

If you haven't verified yet, a banner appears at the top of the panel and escalates as the 7-day grace period runs out: a routine reminder to verify, then an urgent one once you're down to the final 2 days. After you've verified, the same banner reappears only if auto-renewal starts failing and the lease drops under 14 days, and it flags the domain outright if the lease ever lapses. No banner at all means everything is healthy.

If the lease lapses — verification was skipped past the deadline, or renewal kept failing until the claim expired — the panel keeps running (you don't lose access or data), but the temporary domain stops resolving, so the panel, login, and any services published on that domain become unreachable at that address. A lapsed claim doesn't renew itself again; add a domain you own under Settings → DNS & Domains to recover.

Bring-your-own-domain installs never see any of this — no wizard step, no banner, no Settings card, and no extra network calls.

What the Installer Creates

/opt/aiadminpanel/
├── .env                          # Environment configuration
├── docker-compose.yml            # Production compose file
├── keycloak-realm-export.json    # Keycloak realm with panel clients
├── litellm-config.yaml           # LiteLLM AI gateway config
├── secrets/                      # Secret files — persistent, survive reboot
│   ├── master_key                # Panel encryption key
│   ├── db_password               # PostgreSQL password
│   ├── keycloak_admin_password   # Keycloak admin password
│   ├── openbao_unseal_key        # OpenBao secrets-manager auto-unseal key
│   └── admin_password            # Panel admin password
└── letsencrypt/
    ├── acme.json                 # Let's Encrypt certificates
    └── acme-dns.json             # Wildcard certificates (if Cloudflare)

/etc/aiadminpanel/
└── config.yaml                   # Panel configuration

/var/log/aiadminpanel/
└── install.log                   # Installation log

Secret files are mounted into the containers at /run/secrets/<name> by Docker, but their source of truth lives in /opt/aiadminpanel/secrets/ so they survive a host reboot.

What Gets Deployed

The install creates these Docker containers:

ContainerImagePurpose
aiadminpanel_traefiktraefik:v3Reverse proxy, auto-SSL
aiadminpanel_postgresqlpostgres:16-alpinePrimary database
aiadminpanel_valkeyvalkey/valkey:8-alpineCache and pub/sub
aiadminpanel_keycloakkeycloak:26.0OIDC identity provider
aiadminpanel_openbaoopenbao/openbao:2.5.5Secrets manager (AI provider keys) — internal only, no exposed port
aiadminpanel_panelghcr.io/aiadminpanel/ai-admin-panelThe panel itself
aiadminpanel_ollamaollama/ollamaLocal LLM inference
aiadminpanel_litellmghcr.io/berriai/litellmAI gateway

GPU Support (NVIDIA)

If the server has an NVIDIA GPU, the installer detects it during setup and automatically installs and configures the NVIDIA Container Toolkit plus Docker's nvidia runtime — no terminal steps. Once that's done, AI services you deploy with GPU access use the card, and Hardware → GPUs in the panel shows the model, VRAM, driver, and live utilization.

The bundled Local AI (Ollama) is GPU-accelerated automatically too. On a GPU host the installer reserves the card for the bundled Ollama, so Local AI uses the GPU out of the box and the AI Models page shows a ⚡ GPU badge for it — no deploy step or terminal needed. On a CPU-only host Ollama stays on the CPU and nothing changes. Already running on a GPU box? Just re-run the installer and the bundled Ollama picks up the GPU.

This runs on the apt (Ubuntu/Debian), dnf (RHEL/Rocky/AlmaLinux/Fedora), and zypper (SUSE) families. It's idempotent — re-running the installer just re-asserts the configuration — and a complete no-op on CPU-only hosts.

GPU driver is a prerequisite. The installer sets up the container plumbing, but the NVIDIA kernel driver must already be present. Many bare cloud GPU images ship without one. If the installer warns that a GPU is present but no driver is loaded, install it and reboot:

  • Ubuntu/Debian: sudo ubuntu-drivers install (or sudo apt install -y nvidia-driver-<version>)
  • RHEL/Rocky/AlmaLinux: enable EPEL + NVIDIA's CUDA repo, then sudo dnf install -y nvidia-driver

Verify with nvidia-smi, then re-run the panel installer to finish the toolkit configuration.

AMD/ROCm GPUs are not yet auto-configured by the installer.

Post-Install Verification

# Check panel health
curl -s https://panel.example.com/healthz | jq .

# Check Keycloak is accessible
curl -s -o /dev/null -w "%{http_code}" https://auth.panel.example.com

# Check template catalog loaded
curl -s https://panel.example.com/api/v1/templates/catalog | jq '.templates | length'
# Expected: 45

# Check all containers running
docker compose -f /opt/aiadminpanel/docker-compose.yml ps

Then open https://panel.example.com and log in with the admin email and password the installer printed at the end (the password is also saved on the server at /opt/aiadminpanel/secrets/admin_password).

Default Credentials

ServiceURLUsernamePassword
Keycloak Adminhttps://auth.{domain}/admin/adminContents of /opt/aiadminpanel/secrets/keycloak_admin_password
Panelhttps://{domain}Created via Keycloak

Troubleshooting

Port 80/443 already in use

Stop any existing web server:

systemctl stop nginx apache2 2>/dev/null
systemctl disable nginx apache2 2>/dev/null

Panel unreachable in a browser, but SSH works (multi-homed VPS)

On OVH and Hetzner Cloud with a private network, the private interface can install a default route at the same priority as the public one. Host traffic (SSH, curl) still works, but Docker container replies exit the private interface and are dropped — so the panel times out in a browser and containers can't reach the internet. This is not a firewall issue. See Multi-Homed VPS Routing for the one-file fix, or re-run the installer with AAP_FIX_ROUTING=1 to apply it automatically.

DNS not resolving

dig +short panel.example.com
dig +short test.panel.example.com

Both should return your server IP. If not, wait for DNS propagation (up to 48 hours for some providers).

Let's Encrypt rate limits

For testing, use the staging CA:

# In docker-compose.yml, change the ACME server to:
# --certificatesresolvers.letsencrypt.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory

Production rate limit: 50 certificates per registered domain per week.

Keycloak not starting

Keycloak needs its own database. If it fails to start:

# Check logs
docker logs aiadminpanel_keycloak

# Common fix: create the database
docker exec aiadminpanel_postgresql psql -U aiadminpanel -c "CREATE DATABASE keycloak;"
docker compose restart keycloak

Checking logs

docker logs --tail 100 aiadminpanel_panel       # Panel
docker logs --tail 100 aiadminpanel_traefik     # Traefik
docker logs --tail 100 aiadminpanel_keycloak    # Keycloak
docker logs --tail 100 aiadminpanel_postgresql  # PostgreSQL

Dry run

Test the installer without making changes:

bash install.sh --dry-run --verbose