Installing XiansAi Server¶
This guide walks you through installing and running the XiansAi Server — the core platform API and orchestration engine — using the official Docker images published to DockerHub. It covers the external services you need, every environment variable (app setting) the server understands, and how to run the container for staging and production.
Where the Server fits
The XiansAi Server is the heart of the platform. Agents (built with the SDK) and Agent Studio both connect to it. Bring the Server up first, bootstrap it to mint your first API key, then point Agent Studio and your agents at it.
The official Docker image¶
The platform team publishes multi-platform images to DockerHub as 99xio/xiansai-server.
| Detail | Value |
|---|---|
| Image | 99xio/xiansai-server |
| Platforms | linux/amd64, linux/arm64 (Apple Silicon) |
| Container port | 8080 (HTTP only) |
| Health endpoint | GET /health |
Available tags follow semantic versioning. For a release v2.0.0 you can pull 2.0.0, 2.0, 2, or latest. Pre-releases (e.g. 2.0.0-beta) are published too, but never update the latest tag.
Pin a version in production
Prefer an explicit tag such as 99xio/xiansai-server:2.0.0 over latest so deployments are reproducible.
Prerequisites¶
The Server is stateless itself, but it depends on two external services. Provision these before starting the container.
| Dependency | Purpose |
|---|---|
| MongoDB (replica set) | Primary data store. A replica set is required because the server uses transactions. |
| Temporal | Workflow orchestration engine that runs agent workflows. |
| Docker Engine | 20.10+ (and optionally Docker Compose 2.0+). |
Redis (distributed cache) and Azure Communication Services (outbound email) can be added later — see optional settings.
Configuration: environment variables¶
All settings are supplied as environment variables using the standard .NET convention where : in a configuration path becomes __ (double underscore). For example, the setting MongoDB:ConnectionString is provided as MongoDB__ConnectionString.
The recommended approach is to keep these in an .env file and pass it to the container with --env-file.
Minimal .env to get started¶
Only the variables below are mandatory — everything else has sensible defaults. Copy this template, fill in the values (the sections that follow explain how to obtain each one), and you can start the server.
# MongoDB (must be a replica set)
MongoDB__ConnectionString=mongodb://user:password@mongodb:27017/xians?replicaSet=rs0&authSource=xians
MongoDB__DatabaseName=xians
# Temporal
Temporal__FlowServerUrl=temporal:7233
Temporal__FlowServerNamespace=default
# Encryption keys — generate each with: openssl rand -base64 32
EncryptionKeys__BaseSecret=<random-base64>
EncryptionKeys__UniqueSecrets__ConversationMessageKey=<random-base64>
EncryptionKeys__UniqueSecrets__TenantOidcSecretKey=<random-base64>
EncryptionKeys__UniqueSecrets__SecretVaultKey=<random-base64>
# Root CA certificate — see "Certificates" below for generation steps
Certificates__AppServerPfxBase64=<base64-encoded-pfx>
Certificates__AppServerCertPassword=<pfx-password>
General¶
| Variable | Default | Description |
|---|---|---|
ASPNETCORE_ENVIRONMENT | Production | Development, Staging, or Production. |
ASPNETCORE_URLS | http://+:8080 | Bind address. Keep HTTP-only in Docker; terminate TLS at your load balancer. |
SERVICE_TYPE | --all | Which service(s) to run: --all, --web, --lib, or --user. See running as microservices. |
CONFIG_NAME | — | A label for the active configuration (useful for diagnostics). |
Database (MongoDB) — required¶
MongoDB__ConnectionString=mongodb://user:password@mongodb:27017/xians?replicaSet=rs0&authSource=xians
MongoDB__DatabaseName=xians
Connection pool tuning is optional (defaults shown):
Replica set required
The connection string must point at a MongoDB replica set (replicaSet=...). The server relies on multi-document transactions, which standalone MongoDB does not support.
Where to get the connection string:
- MongoDB Atlas (managed): create a cluster, then copy the connection string from Connect → Drivers. Atlas clusters are always replica sets, so no extra configuration is needed.
- Self-hosted: start
mongodwith--replSet rs0and initialize it once withrs.initiate()frommongosh. Then usemongodb://<user>:<password>@<host>:27017/xians?replicaSet=rs0&authSource=<auth-db>.
Temporal workflow engine — required¶
Optionally, if agents connect from outside your Docker network via a different hostname:
Where to get these values:
FlowServerUrlis thehost:portof the Temporal frontend service as reachable from inside the server container. A self-hosted Temporal (e.g. via temporal docker-compose) listens on port7233by default.FlowServerNamespaceis the Temporal namespace to run workflows in. Self-hosted setups ship withdefault; for Temporal Cloud use your namespace (e.g.my-namespace.a1b2c) and the endpoint shown in the Temporal Cloud console.FlowServerUrlExternalis the endpoint handed to agents; it defaults toFlowServerUrlwhen omitted.
Encryption keys — required¶
The server encrypts sensitive data at rest (chat messages, tenant OIDC secrets, and the secret vault). Generate each key with openssl rand -base64 32 and use different values per environment.
# Foundational secret (min 32 chars)
EncryptionKeys__BaseSecret=<random-base64>
# Per-purpose unique secrets
EncryptionKeys__UniqueSecrets__ConversationMessageKey=<random-base64>
EncryptionKeys__UniqueSecrets__TenantOidcSecretKey=<random-base64>
EncryptionKeys__UniqueSecrets__SecretVaultKey=<random-base64>
Keep keys stable and safe
Store these in your secret manager. If they change or are lost, previously encrypted data can no longer be decrypted. See Chat Message Encryption for details.
Certificates — required¶
The server acts as its own certificate authority: it uses a root CA certificate to sign the client certificates that agents authenticate with. Supply that root CA as a password-protected, base64-encoded PFX (PKCS#12) bundle containing both the certificate and its private key.
Certificates__AppServerPfxBase64=<base64-encoded-pfx>
Certificates__AppServerCertPassword=<pfx-password>
Generating the root certificate with openssl:
# 1. Generate a private key for the CA
openssl genrsa -out ca.key 4096
# 2. Create a self-signed root CA certificate (valid 10 years).
# The CA basic constraint is required — the server looks for it when loading the bundle.
openssl req -x509 -new -nodes -key ca.key -sha256 -days 3650 \
-subj "/O=YourOrganization/CN=XiansAi Root CA" \
-addext "basicConstraints=critical,CA:true" \
-addext "keyUsage=critical,digitalSignature,keyCertSign,cRLSign" \
-out ca.crt
# 3. Bundle the certificate and key into a password-protected PFX
openssl pkcs12 -export -out ca.pfx -inkey ca.key -in ca.crt \
-passout pass:<pfx-password>
# 4. Base64-encode the PFX as a single line (portable across macOS/Linux)
openssl base64 -A -in ca.pfx -out ca.pfx.base64
Set Certificates__AppServerPfxBase64 to the contents of ca.pfx.base64 and Certificates__AppServerCertPassword to the password you chose in step 3. Alternatively, the server repository ships a ready-made script that does all of the above: infra/root-cert-gen.sh (run it as ./root-cert-gen.sh -p <pfx-password>).
Protect the CA key
Anyone holding this PFX and password can mint valid agent certificates for your platform. Store both in your secret manager, never commit them, and use a different certificate per environment. Rotating the certificate invalidates all previously issued agent certificates.
CORS — optional¶
Only needed when browser-based clients (e.g. custom apps calling the UserAPI) call the server directly. Set the origins they are served from; array entries use index notation. Defaults to no allowed origins.
Cors__AllowedOrigins__0=https://custom-ui.your-domain.com
Cors__AllowedOrigins__1=https://app.your-domain.com
Optional settings¶
None of these are needed to get started — the defaults work out of the box.
# Caching: "memory" (default) or "redis".
# Use Redis when running multiple server replicas so they share cache state.
Cache__Provider=memory
Cache__Redis__ConnectionString=
# Email: "console" (default, prints to logs) or "azure" (Azure Communication Services).
# Used for tenant user-invitation emails.
Email__Provider=console
Email__Azure__ConnectionString=
Email__Azure__SenderEmail=
# WebSockets
WebSockets__Enabled=true
# Logging
Logging__LogLevel__Default=Information
Logging__LogLevel__Microsoft.AspNetCore=Warning
# Data Protection keys directory (see "Persisting Data Protection keys")
DataProtection__KeysDirectory=/app/keys
Running the Server¶
1. Create your environment file¶
Create an .env file with your real values — start from the minimal template above and add optional settings as needed.
For the certificate PFX, follow the steps in Certificates — required.
2. Run the container¶
docker run -d \
--name xiansai-server \
--env-file .env \
-p 5001:8080 \
--restart unless-stopped \
99xio/xiansai-server:latest
| Parameter | Description |
|---|---|
-d | Run detached (in the background). |
--name xiansai-server | Name the container. |
--env-file .env | Load all app settings from your env file. |
-p 5001:8080 | Map host port 5001 to the container's HTTP port 8080. |
--restart unless-stopped | Restart automatically unless you stop it. |
3. Verify¶
4. Bootstrap the platform¶
A fresh server has no users or tenants. Initialize it and obtain your first API key:
See Platform Bootstrapping for the full flow, then point Agent Studio at the server using the returned key.
Running with Docker Compose¶
For a self-contained deployment you can define the server alongside its dependencies. The snippet below shows the server service; add your own MongoDB (as a replica set) and Temporal services, or point at managed instances.
services:
xiansai-server:
image: 99xio/xiansai-server:latest
ports:
- "5001:8080"
env_file:
- .env
restart: unless-stopped
volumes:
- xiansai-keys:/app/keys
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 5s
volumes:
xiansai-keys:
One-command local platform
To spin up the Server together with MongoDB, Temporal, Keycloak, and Agent Studio for evaluation, use the Community Edition repository, which wires everything together with Docker Compose.
Persisting Data Protection keys¶
ASP.NET Core Data Protection keys are used to protect tokens and cookies. In production the container writes them to /app/keys, which is exposed as a Docker volume. Mount a persistent (and, for multiple replicas, shared) volume there so keys survive restarts and are consistent across instances.
docker run -d \
--name xiansai-server \
--env-file .env \
-p 5001:8080 \
-v xiansai-keys:/app/keys \
99xio/xiansai-server:latest
Override the location with DataProtection__KeysDirectory if needed. If keys are not persisted, users may be logged out and encrypted cookies invalidated on every restart.
Running as separate microservices¶
The server can run as one combined process (default) or as independent, separately scalable services via SERVICE_TYPE:
SERVICE_TYPE | Service | Responsibility |
|---|---|---|
--all | All (default) | Everything in one process. |
--web | WebApi | Client-facing endpoints (api/client/*). |
--lib | LibApi | Server-to-server / agent endpoints (api/server/*). |
--user | UserApi | User-facing endpoints, webhooks, and websockets. |
Run each as its own container with the appropriate SERVICE_TYPE to scale them independently. See Scaling for guidance.
Updating¶
# Docker Compose
docker compose pull && docker compose up -d
# Plain docker run
docker pull 99xio/xiansai-server:latest
docker rm -f xiansai-server
docker run -d --name xiansai-server \
--env-file .env -p 5001:8080 -v xiansai-keys:/app/keys \
--restart unless-stopped 99xio/xiansai-server:latest
Troubleshooting¶
| Symptom | Likely cause / fix |
|---|---|
| Container exits immediately | Inspect docker logs xiansai-server. Usually a missing required variable or an unreachable dependency. |
Unable to configure HTTPS endpoint | The app tried to bind HTTPS. Keep ASPNETCORE_URLS=http://+:8080 and terminate TLS at your load balancer. |
| Cannot connect to MongoDB / transaction errors | Ensure the connection string targets a replica set and credentials/authSource are correct. |
| Cannot connect to Temporal | Verify Temporal__FlowServerUrl is reachable from inside the container. |
409 Conflict on bootstrap | The platform already has users; bootstrapping only works on an empty database. See Bootstrapping. |
| Users logged out after restart | Data Protection keys aren't persisted — mount a volume at /app/keys. |
| Health check failing | Confirm the app is listening on 8080, dependencies are reachable, and required env vars are set. |
| Port already in use | Change the host mapping, e.g. -p 5002:8080. |
What's next?¶
- Platform Bootstrapping — initialize a fresh server and mint your first API key.
- Installing Agent Studio — stand up the web console against this server.
- Scaling — run and scale the server and agents.
- Chat Message Encryption — how encryption keys protect data at rest.