AI AdminPanel Documentation

Configuration

AI Admin Panel is configured through environment variables, Docker Compose files, and service-specific configuration. This page covers all configurable aspects of the system.

Environment Variables

The primary configuration file is /opt/aiadminpanel/.env. All variables are read at startup.

Core Settings

VariableDefaultDescription
PANEL_DOMAIN(required — auto-filled by the installer's temporary domain when you don't have one)Base domain for the panel
MANAGED_DOMAIN(unset)true on installs using a claimed temporary domain (written by the installer)
MANAGED_DNS_URLhttps://dns.aiadminpanel.comClaim service the temporary domain came from; the panel renews the lease against it
MANAGED_DOMAIN_TOKEN_FILE/run/secrets/managed_domain_tokenPath to the claim credential the panel reads to verify email and renew the lease
PANEL_PORT8080Internal HTTP port (Traefik proxies to this)
DATABASE_URL(auto-generated)PostgreSQL connection string
VALKEY_URLvalkey://valkey:6379Valkey connection string
LOG_LEVELinfoLog level: debug, info, warn, error
ENVIRONMENTproductionRuntime environment: production, development

MANAGED_DOMAIN_TOKEN_FILE points at a Docker Compose secret (managed_domain_token, mounted from /opt/aiadminpanel/secrets/managed_domain_token) rather than a plain env var, so the claim credential never lands in .env or docker inspect output. On a bring-your-own-domain install the installer still writes an empty, 0600 placeholder file so the compose mount never fails — the panel treats an empty token as "not managed" and skips all managed-domain behavior (no wizard step, no banner, no Settings card, no network calls to MANAGED_DNS_URL). On a claimed temporary domain, the panel — not the installer — owns verification and renewal from then on: see "Keeping your free domain" on the Installation page.

Authentication (Keycloak)

VariableDefaultDescription
OIDC_ISSUER_URLhttps://auth.{PANEL_DOMAIN}/realms/aiadminpanelKeycloak realm URL
OIDC_CLIENT_IDpanelOIDC client identifier
OIDC_CLIENT_SECRET(auto-generated)OIDC client secret
SESSION_SECRET(auto-generated)Cookie encryption key

Secrets Backend (OpenBao)

VariableDefaultDescription
SECRETS_BACKENDopenbaoopenbao (default) or filefile is the legacy escape hatch, disabling the secrets manager entirely
BAO_ADDRhttp://openbao:8200Internal address the panel uses to reach the bundled OpenBao service
OPENBAO_VERSION2.5.5Pinned OpenBao image tag for the openbao compose service

OpenBao stores AI provider API keys (platform and per-customer) in per-customer namespaces. See Secrets Manager for what it does and docs/runbooks/openbao.md in the repository for backup/restore/rotation procedures. All OpenBao failures are non-fatal to the panel: reads fall back to the legacy encrypted column, writes fail loudly with a localized error rather than silently succeeding.

SSL and Traefik

VariableDefaultDescription
ACME_EMAIL(required)Email for Let's Encrypt notifications
ACME_STORAGE/traefik/acme.jsonCertificate storage path
ACME_CA_SERVERhttps://acme-v02.api.letsencrypt.org/directoryACME CA server URL

Cloudflare DNS (Optional)

VariableDefaultDescription
CF_DNS_API_TOKEN(empty)Cloudflare API token with DNS edit permission
CF_ZONE_ID(empty)Cloudflare zone ID (auto-detected if token has zone read permission)
CF_PROXIEDfalseWhether to enable Cloudflare proxy on created DNS records

AI Provider (Optional)

VariableDefaultDescription
AI_PROVIDER(empty)AI provider: openai, litellm, ollama
AI_API_URL(empty)AI API endpoint URL
AI_API_KEY(empty)AI API key
AI_MODEL(empty)Model name for AI-powered deployments

In the setup wizard and in Settings → AI Providers, the model field is a curated dropdown of recent models for the selected provider (Anthropic / OpenAI / OpenRouter) — so you don't have to remember exact model ids. Pick one from the list, or choose Enter a custom model to type any other model name. The lists are refreshed each release.

Bundled Provider AI (Optional)

A hosting provider can pre-inject a central, OpenAI-compatible inference endpoint at install time so AI apps your customers deploy have a working upstream on first boot — with no key pasting. When AAP_PROVIDER_AI_API_KEY is present at install, the panel seeds a Provider AI source on first boot (encrypting the key into its own database — the key is never logged). It is always editable later in Settings → AI Providers, and the panel never overwrites an operator-edited value on a later reboot. Leave these unset to stay sovereign by default (no Provider AI configured).

VariableDefaultDescription
AAP_PROVIDER_AI_API_KEY(empty)Bundles a central Provider AI source when set. Read once at first boot, encrypted into the panel DB.
AAP_PROVIDER_AI_BASE_URL(empty)OpenAI-compatible base URL (e.g. https://inference.example.com/v1).
AAP_PROVIDER_AI_MODEL(empty)Default model id for the bundled Provider AI.
AAP_PROVIDER_AI_PROVIDER_TYPEopenaiopenai (default) · openrouter · anthropic · ollama.

Notifications (Optional)

VariableDefaultDescription
SMTP_HOST(empty)SMTP server hostname
SMTP_PORT587SMTP server port
SMTP_USER(empty)SMTP username
SMTP_PASS(empty)SMTP password
SMTP_FROMnoreply@{PANEL_DOMAIN}From address for email notifications

Docker Compose Structure

The production deployment uses two compose files:

docker-compose.infra.yml — Infrastructure Services

Manages the foundational services that the panel depends on:

services:
  postgresql:
    image: postgres:16
    volumes:
      - pgdata:/var/lib/postgresql/data
    networks:
      - aiadminpanel

  valkey:
    image: valkey/valkey:8
    networks:
      - aiadminpanel

  traefik:
    image: traefik:v3.0
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./traefik:/traefik
    networks:
      - aiadminpanel

  keycloak:
    image: quay.io/keycloak/keycloak:26.0
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.keycloak.rule=Host(`auth.${PANEL_DOMAIN}`)"
    networks:
      - aiadminpanel

  openbao:
    image: openbao/openbao:${OPENBAO_VERSION:-2.5.5}
    volumes:
      - openbao_data:/openbao/file
    networks:
      - aiadminpanel
    # No Traefik labels — internal-only, no exposed route.

docker-compose.yml — Panel Application

Manages the panel itself:

services:
  panel:
    image: ghcr.io/aiadminpanel/panel:latest
    env_file: .env
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.panel.rule=Host(`${PANEL_DOMAIN}`)"
      - "traefik.http.routers.panel.tls.certresolver=${CERT_RESOLVER:-letsencrypt}"
    networks:
      - aiadminpanel

Keycloak Configuration

Keycloak serves as the sole identity provider. The installer creates:

  • Realm: aiadminpanel
  • Client: panel (confidential, authorization code flow)
  • Admin user: created with the email and password from install

Keycloak Admin Console

Access at https://auth.{PANEL_DOMAIN}/admin/ with the Keycloak admin credentials.

Custom Branding

The panel applies dark branding to the Keycloak login page automatically. To customize further, modify the theme in the Keycloak admin console under Realm Settings > Themes.

Adding Users

Users can be created through:

  1. The panel's customer management UI (creates Keycloak user automatically)
  2. The Keycloak admin console directly
  3. The Keycloak user self-registration flow (if enabled)

Roles

RolePermissions
adminFull access to all resources and settings
operatorManage services, deploy, view all customers
viewerRead-only access to assigned resources

Navigation adapts to your persona

The setup wizard asks how you'll use the panel (Just for me · For my clients · As a hosting business). On the Free and Power User editions your choice sets how much of the sidebar appears by default:

PersonaSidebar shows
Just for meServices, Projects, Templates, AI Models, Insights, Settings
For my clientsthe above + Customers, Plans, Roles, Audit Log

On the Web Host edition the full reseller sidebar — the above + Resellers — is always shown, whatever persona you picked: activating the reseller tier reveals its features. (An edition upgrade to Web Host surfaces the reseller and customer views immediately; you don't need to change your persona.) On a lesser edition the hosting view isn't available — it falls back to the For my clients view.

The persona only sets the default depth on Free / Power User. To reveal everything your edition allows regardless of persona, switch on Advanced view from the user menu (top-right). Advanced view never locks anything away.

Switching context and finding your way

Once you manage customers, two extras keep you oriented:

  • Context switcher — an Operator dropdown in the top toolbar. Use it to jump straight to a customer's page, or View as customer to open their portal in a new tab via single sign-on (no separate login). It appears only on the For my clients and As a hosting business views once you have at least one customer — a Just for me install never shows it.
  • Breadcrumbs — a trail under the header (e.g. Operator › Customers › Acme Ltd) so you always know where you are and can click back up a level. It stays hidden on the dashboard and appears as you move into a section.

Traefik SSL Setup

Traefik handles all SSL termination via Let's Encrypt. The static configuration at /opt/aiadminpanel/traefik/traefik.yml:

entryPoints:
  web:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: websecure
          scheme: https
  websecure:
    address: ":443"

certificatesResolvers:
  letsencrypt:
    acme:
      email: "${ACME_EMAIL}"
      storage: /traefik/acme.json
      httpChallenge:
        entryPoint: web

providers:
  docker:
    exposedByDefault: false
    network: aiadminpanel

Services get SSL automatically when deployed — no manual certificate management required.

DNS-01 Certificates (Cloudflare)

For hosts with a closed inbound port 80 or a domain behind a proxy: by default the panel issues certificates with the HTTP-01 challenge, which needs inbound port 80 to be publicly reachable. On a host where port 80 is firewalled or the domain sits behind a proxy, use the DNS-01 challenge via Cloudflare instead — it proves domain ownership through a DNS record, so port 80 never has to be open (and it can issue wildcard *.panel.example.com certs).

Enabling it requires both of these in /opt/aiadminpanel/.env:

TLS_MODE=cloudflare              # points the routers at the DNS-01 resolver
CF_DNS_API_TOKEN=your-cf-token   # Cloudflare token with Zone:DNS:Edit permission

TLS_MODE=cloudflare is the switch. Setting only CF_DNS_API_TOKEN is not enough — without TLS_MODE=cloudflare the panel and Keycloak routers keep using HTTP-01 and the DNS-01 resolver is never used. The installer writes CERT_RESOLVER=letsencrypt-dns in cloudflare mode; a plain install leaves it unset, so the routers fall back to letsencrypt (HTTP-01) — unchanged.

Traefik already defines the DNS-01 resolver the routers switch to:

certificatesResolvers:
  letsencrypt-dns:
    acme:
      dnsChallenge:
        provider: cloudflare
        resolvers:
          - "1.1.1.1:53"
          - "8.8.8.8:53"

Cloudflare DNS Integration

When configured, the panel automatically creates DNS records for deployed services:

  1. Service deploys to myapp.panel.example.com
  2. Panel calls Cloudflare API to create an A record
  3. Traefik picks up the route and provisions SSL
  4. Service is accessible within seconds

Setting Up Cloudflare

  1. Go to your Cloudflare dashboard
  2. Create an API token with Zone:DNS:Edit permission for your domain
  3. Set CF_DNS_API_TOKEN in /opt/aiadminpanel/.env
  4. Restart the panel: docker compose restart panel

Without Cloudflare

If not using Cloudflare, you need a wildcard DNS record (*.panel.example.com) pointing to your server. Services will be accessible immediately after deploy since the wildcard catches all subdomains.