Platform
ScaiWave ScaiGrid ScaiCore ScaiBot ScaiDrive ScaiKey Models Tools & Services
Solutions
Organisations Developers Internet Service Providers Managed Service Providers AI-in-a-Box
Resources
Support Documentation Blog Downloads
Company
About Research Careers Investment Opportunities Contact
Log in

Deployment

Operational guide for deploying ScaiDNS. Covers required services, configuration, and the first-time setup flow.

Prerequisites#

  • PowerDNS. Authoritative server with the HTTP API enabled. Tested against PowerDNS 4.7+.
  • MariaDB or MySQL. For the application database. ScaiDNS uses mysql+asyncmy. A dedicated database is recommended; do not share with PowerDNS's backend.
  • Redis. For rate limiting and cache. Version 6+ with ACL auth.
  • ScaiKey instance. For identity. Can be shared with other ScaiLabs services or dedicated.

Configuration#

All configuration is via environment variables. See .env.example in the repository for the canonical reference.

Required#

Variable Notes
DATABASE_URL mysql+asyncmy://user:password@host:3306/scaidns
REDIS_URL redis://user:password@host:6379/0
PDNS_API_URL e.g., http://pdns.internal:8081
PDNS_API_KEY Shared secret for PowerDNS HTTP API
SCAIKEY_URL e.g., https://scaikey.scailabs.ai
SCAIKEY_CLIENT_ID OAuth client ID for ScaiDNS
SCAIKEY_CLIENT_SECRET OAuth client secret
SCAIKEY_APPLICATION_ID ScaiKey application ID for user assignment
SCAIKEY_WEBHOOK_SECRET HMAC secret for webhook signature verification
EXTERNAL_URL Public URL users hit (e.g., https://scaidns.example.com)
SESSION_SECRET Cryptographic secret for session management
API_KEY_PEPPER Secret added to API key hashes

Optional#

Variable Default Notes
DEBUG false Enable in dev; never in production
ENVIRONMENT production development, staging, production
LOG_LEVEL INFO DEBUG, INFO, WARNING, ERROR
LOG_FORMAT text text or json
DATABASE_POOL_SIZE 20 Connection pool size
REDIS_MAX_CONNECTIONS 20
ARQ_MAX_JOBS 10 Background worker concurrency
SCAIKEY_TOKEN_CACHE_TTL 60 JWT validation cache TTL (seconds)
SCAIKEY_JWKS_CACHE_TTL 3600 JWKS cache TTL (seconds)
VALIDATION_CHALLENGE_TTL 3600 Validation challenge expiry (seconds)
VALIDATION_EXPIRY_HOURS 72 Max age before a challenge is expired
VALIDATION_CHECK_INTERVAL_SECONDS 60 Background check cadence
RATE_LIMIT_USER_PER_MINUTE 1000 Default per-JWT rate limit
RATE_LIMIT_API_KEY_PER_MINUTE 100 Default per-API-key rate limit
DNSSEC_DEFAULT_ALGORITHM 13 ECDSA P-256
DNSSEC_KSK_LIFETIME_DAYS 365
DNSSEC_ZSK_LIFETIME_DAYS 30
CORS_ORIGINS [] JSON array of allowed origins

Services#

ScaiDNS runs three processes:

  1. API server. FastAPI + uvicorn, serves the HTTP API. Stateless, horizontally scalable.
  2. Worker. arq worker, runs background jobs (validation checks, DNSSEC rotation, sync retries).
  3. CLI. scaidns commands for setup and maintenance. Not a long-running process.

Typical systemd units:

ini
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# /etc/systemd/system/scaidns-api.service
[Unit]
Description=ScaiDNS API
After=network.target

[Service]
Type=exec
User=scaidns
WorkingDirectory=/usr/local/scaidns/backend
EnvironmentFile=/usr/local/scaidns/backend/.env
ExecStart=/usr/local/scaidns/backend/.venv/bin/uvicorn app.main:app \
          --host 0.0.0.0 --port 8000 --workers 4
Restart=always

[Install]
WantedBy=multi-user.target
ini
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# /etc/systemd/system/scaidns-worker.service
[Unit]
Description=ScaiDNS Worker
After=network.target

[Service]
Type=exec
User=scaidns
WorkingDirectory=/usr/local/scaidns/backend
EnvironmentFile=/usr/local/scaidns/backend/.env
ExecStart=/usr/local/scaidns/backend/.venv/bin/arq app.workers.WorkerSettings
Restart=always

[Install]
WantedBy=multi-user.target

First-time setup#

1. Database migrations#

bash
1
2
cd /usr/local/scaidns/backend
.venv/bin/alembic upgrade head

Creates the schema and seeds system roles, templates, and default configuration.

2. ScaiKey registration#

Register ScaiDNS as an OAuth application in ScaiKey:

  • Application name: ScaiDNS
  • Redirect URI: https://<your-external-url>/oauth/callback
  • Post-logout URI: https://<your-external-url>/
  • Scopes: openid, profile, email

Take the resulting client_id and client_secret and put them in .env.

Also in ScaiKey:

  • Generate a webhook signing secret. Put it in SCAIKEY_WEBHOOK_SECRET.
  • Configure the webhook URL: https://<your-external-url>/api/v1/webhooks/scaikey.
  • Assign users/groups to the ScaiDNS application so they receive user/group events.

There's a helper in the ScaiDNS CLI:

bash
1
scaidns register-scaikey --public-url https://<your-external-url>

3. First sync#

Pull the initial user and tenant data from ScaiKey:

bash
1
scaidns sync

Check the output for created/updated counts. If everything shows zeros, double-check SCAIKEY_APPLICATION_ID and that users are assigned to the application.

4. Initial platform admin#

Creating your first platform admin via the API requires already being one, so use the CLI:

bash
1
scaidns assign-admin --user-email your-email@example.com

Assigns platform_admin at platform scope. You can now log in via the web UI and manage further access.

5. Nameserver configuration#

Set the authoritative nameservers for ScaiDNS-hosted zones:

bash
1
2
3
4
curl -X PUT https://<your-external-url>/api/v1/admin/nameservers \
  -H "Authorization: Bearer $YOUR_JWT" \
  -H "Content-Type: application/json" \
  -d '{"nameservers": ["ns1.example.com.", "ns2.example.com."]}'

These become NS records in every zone.

PowerDNS configuration#

Recommended PowerDNS settings (in pdns.conf):

carbon
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
launch=gmysql
gmysql-host=...
gmysql-user=...
gmysql-password=...
gmysql-dbname=pdns

# HTTP API
api=yes
api-key=... # must match PDNS_API_KEY in .env
webserver=yes
webserver-address=0.0.0.0
webserver-port=8081
webserver-allow-from=...  # ScaiDNS host(s) only

# Enable DNSSEC
direct-dnskey=yes

# Recommended
default-soa-content=ns1.@ hostmaster.@ 0 3600 600 604800 600
default-ttl=3600

Important: Never point ScaiDNS and PowerDNS at the same database. PowerDNS owns its backend; ScaiDNS has its own schema. They communicate via the HTTP API.

Reverse proxy / TLS#

Run ScaiDNS behind a TLS-terminating reverse proxy (nginx, Caddy, HAProxy). An nginx config sketch:

nginx
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
server {
    listen 443 ssl http2;
    server_name scaidns.example.com;

    ssl_certificate     /etc/letsencrypt/live/scaidns.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/scaidns.example.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

Upgrades#

For minor version upgrades:

  1. Deploy new code.
  2. Run migrations: alembic upgrade head.
  3. Restart API and worker services.
  4. Smoke-test /api/v1/health/ready.

For major upgrades, check the release notes — schema migrations, config changes, or webhook signature format changes need explicit coordination.

What's next#

Updated 2026-05-17 02:38:19 View source (.md) rev 1