Your Ops-Center instance is now ready to support multi-tenant subdomain routing like:
acme.ops-center.com→ Acme Corp tenantcontoso.ops-center.com→ Contoso tenantapi.ops-center.com→ API endpointauth.ops-center.com→ Keycloak authentication
-
docs/DNS_SETUP_GUIDE.md (5,800 lines)
- Comprehensive DNS configuration guide
- Cloudflare, AWS Route53, DigitalOcean instructions
- SSL certificate setup (Let's Encrypt)
- Troubleshooting guide
-
setup-dns.sh (Executable)
- Interactive setup wizard
- Generates .env file with your domain
- Creates DNS record templates
- Outputs provider-specific commands
-
- Quick 5-minute setup guide
- Command reference
- Troubleshooting table
-
verify-dns.sh (Generated by setup-dns.sh)
- Tests DNS resolution
- Validates HTTPS connectivity
- Auto-created when you run setup-dns.sh
-
dns-records.json (Generated by setup-dns.sh)
- AWS Route53 configuration template
- Auto-created when you run setup-dns.sh
- docker-compose.direct.yml
- Added wildcard subdomain routing (Priority 50)
- Updated Keycloak to use
${APP_DOMAIN}variable - Updated backend environment to use
${APP_DOMAIN} - Configured TLS for wildcard certificates
cd /home/ubuntu/Ops-Center-OSS
./setup-dns.shYou'll be prompted for:
- Your domain (e.g.,
ops-center.com,yourdomain.com) - Server IP:
49.13.6.8(detected automatically) - Email for SSL certificates
The script will show you exactly which DNS records to add. Example output:
Type Name Value TTL
---- ---- ----- ---
A @ 49.13.6.8 300
A * 49.13.6.8 300
A api 49.13.6.8 300
A auth 49.13.6.8 300
Where to add these:
- Cloudflare: DNS tab → Add record
- AWS Route53: Use generated
dns-records.json - DigitalOcean: Use
doctlcommands (shown by script) - Other: Add in your DNS provider's control panel
# Usually 5-60 minutes
./verify-dns.sh yourdomain.comdocker-compose -f docker-compose.direct.yml restart# Main domain
curl https://yourdomain.com
# Wildcard subdomain
curl https://test.yourdomain.com
# API subdomain
curl https://api.yourdomain.com/api/v1/health- IPv4:
49.13.6.8 - IPv6:
2a01:4f8:c17:f246::1 - Current Domain:
kubeworkz.io(can be changed)
| Priority | Route | Matches |
|---|---|---|
| 100 | Admin/API paths | /admin, /api, /auth |
| 90 | API subdomain | api.yourdomain.com |
| 80 | Auth subdomain | auth.yourdomain.com |
| 50 | Wildcard tenants | *.yourdomain.com ← NEW |
| 1 | Root domain | yourdomain.com |
- Traefik will automatically request Let's Encrypt certificates
- Wildcard certificates require DNS-01 challenge (configured)
- Cloudflare users: Set SSL to "Full (strict)" mode
1. User visits: https://acme.yourdomain.com
↓
2. DNS resolves to: 49.13.6.8 (wildcard A record)
↓
3. Traefik matches: *.yourdomain.com (Priority 50)
↓
4. Forwards to: ops-center-direct:8084
↓
5. TenantIsolationMiddleware extracts: subdomain="acme"
↓
6. Queries DB: SELECT id FROM organizations WHERE subdomain='acme'
↓
7. Sets TenantContext: organization_id = <acme-org-id>
↓
8. All API calls auto-filter: WHERE organization_id = <acme-org-id>
# Get admin token first
TOKEN=$(curl -X POST https://yourdomain.com/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"admin@yourdomain.com","password":"your-password"}' \
| jq -r '.access_token')
# Create tenant with subdomain "demo"
curl -X POST https://yourdomain.com/api/v1/admin/tenants \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Demo Corporation",
"subdomain": "demo",
"tier": "professional",
"admin_email": "admin@demo.com",
"admin_name": "Demo Admin",
"admin_password": "SecureDemo123!"
}'# Login as tenant admin
curl -X POST https://demo.yourdomain.com/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"admin@demo.com","password":"SecureDemo123!"}'
# Access tenant-specific resources
curl https://demo.yourdomain.com/api/v1/dashboard \
-H "Authorization: Bearer $TENANT_TOKEN"# User from "demo" tenant tries to access "acme" resources
# Should return 403 Forbidden or 404 Not Found
curl https://acme.yourdomain.com/api/v1/devices \
-H "Authorization: Bearer $DEMO_TOKEN"Pros: Free, easy wildcard support, DDoS protection, CDN
# 1. Sign up: https://cloudflare.com
# 2. Add your domain
# 3. Add 4 A records (shown by setup-dns.sh)
# 4. Set SSL to "Full (strict)"
# 5. Enable "Always Use HTTPS"Wildcard SSL: Automatic with DNS-01 challenge
# Use generated dns-records.json
aws route53 change-resource-record-sets \
--hosted-zone-id YOUR_ZONE_ID \
--change-batch file://dns-records.json# Commands shown by setup-dns.sh
doctl compute domain create yourdomain.com
doctl compute domain records create yourdomain.com \
--record-type A --record-name "*" --record-data 49.13.6.8Add these records manually in your control panel:
A @ 49.13.6.8A * 49.13.6.8A api 49.13.6.8A auth 49.13.6.8
After running setup-dns.sh, your .env will contain:
# Domain Configuration
APP_DOMAIN=yourdomain.com
BASE_DOMAIN=yourdomain.com
# SSL/TLS
ACME_EMAIL=admin@yourdomain.com
# Database (auto-generated secure passwords)
POSTGRES_USER=unicorn
POSTGRES_PASSWORD=<random-32-char>
POSTGRES_DB=unicorn_db
# Keycloak (auto-generated secure password)
KEYCLOAK_ADMIN=admin
KEYCLOAK_ADMIN_PASSWORD=<random-32-char>
# Optional: Cloudflare credentials (for wildcard SSL)
# CF_API_EMAIL=you@example.com
# CF_API_KEY=your-api-key
# Optional: AWS credentials (for wildcard SSL)
# AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
# AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
# AWS_REGION=us-east-1# Check DNS propagation
dig yourdomain.com +short
dig test.yourdomain.com +short
# Both should return: 49.13.6.8
# If not, wait longer (up to 24-48 hours max)# Check Traefik logs
docker logs ops-center-traefik 2>&1 | grep -i error
# Common issues:
# 1. Port 80/443 not open
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# 2. Let's Encrypt rate limit (50 certs/week)
# Wait or use staging environment
# 3. DNS-01 challenge not configured
# Add Cloudflare/Route53 credentials to .env# Check Traefik routing
docker logs ops-center-direct 2>&1 | grep -i "tenant\|subdomain"
# Verify priority in docker-compose.direct.yml
# Wildcard should be priority 50 (lower than api/auth)# Check database
docker exec -it ops-center-postgresql psql -U unicorn -d unicorn_db
SELECT id, name, subdomain FROM organizations;
# Should show:
# id | name | subdomain
# -----+--------+-----------
# ... | Acme | acme
# ... | Demo | demo- Row-level tenant isolation (WHERE organization_id = ...)
- Middleware tenant context enforcement
- Quota limits by tier
- Soft/hard delete options
- SSL/TLS encryption
- Subdomain validation: Only allow
[a-z0-9-](already enforced) - DNS verification: Verify custom domain ownership before activation
- Rate limiting: Configure per-tenant rate limits (Epic 11 candidate)
- Audit logging: Track all tenant creation/modification
- Backup strategy: Per-tenant backup and restore
CREATE INDEX idx_org_subdomain ON organizations(subdomain);
CREATE INDEX idx_org_custom_domain ON organizations(custom_domain);
CREATE INDEX idx_org_is_active ON organizations(is_active);- AsyncPG pool already configured (50 connections)
- One pool shared across all tenants
- Consider caching subdomain → org_id mapping (5-minute TTL)
- Reduces DB queries on every request
Your infrastructure is now ready for multi-tenant subdomains!
- ✅ Run
./setup-dns.sh - ✅ Add DNS records
- ✅ Verify with
./verify-dns.sh - ✅ Create test tenant
- ✅ Test tenant isolation
- Per-tenant rate limiting
- Custom domain verification workflow
- Tenant onboarding emails
- CLI commands:
ops-center tenants create/list/delete - Tenant-specific analytics dashboards
| Document | Purpose |
|---|---|
| DNS_SETUP_GUIDE.md | Comprehensive DNS configuration guide (5,800 lines) |
| DNS_QUICK_REFERENCE.md | Quick command reference |
| EPIC_10_MULTITENANT_COMPLETE.md | Full Epic 10 documentation |
setup-dns.sh |
Interactive setup wizard |
verify-dns.sh |
DNS verification tool |
dns-records.json |
AWS Route53 template |
🎉 DNS configuration is production-ready!
Run ./setup-dns.sh to get started.
Questions? Check docs/DNS_SETUP_GUIDE.md or open an issue.