O.0 prep from OPERATOR-PLAN.md. Mechanical refactor before adding partner management and operator-specific endpoints. The service now owns more than just provisioning orchestration (it'll soon own partners, tenant lifecycle actions, multi-audience JWT validation), so the name 'platform-api' reflects its scope better. What changed: - Directory: services/provisioning/ -> services/platform-api/ - Package: @dezky/provisioning -> @dezky/platform-api - Docker: container_name dezky-provisioning -> dezky-platform-api; compose service key 'provisioning' -> 'platform-api'; volume provisioning_node_modules -> platform_api_node_modules - Portal: PROVISIONING_INTERNAL_URL env var -> PLATFORM_API_INTERNAL_URL, default URL http://provisioning:3001 -> http://platform-api:3001 in all three proxy routes (me.get.ts, tenants/index.post.ts, tenants/[slug]/ reconcile.post.ts), plus NUXT_API_BASE updated - Health endpoint service identifier and main.ts log lines updated to 'dezky-platform-api' - Docs swept: README, CLAUDE.md, SERVICES.md, AUTHENTIK-SETUP.md, NEXT-STEPS.md, TROUBLESHOOTING.md, OPERATOR-PLAN.md, traefik/dynamic.yml What deliberately stays: - Internal module names ProvisioningService / ProvisioningModule (those describe an orchestration sub-concern, not the service's purpose) - Tenant.provisioningStatus / provisioningErrors field names (state per integration, not service name) - File services/platform-api/src/tenants/provisioning.service.ts - 'Hetzner provisioning' references in production-prep docs (infrastructure provisioning, unrelated) Verified end-to-end after rename: /api/me returns 200 with profile + 2 tenants + subscription, /api/tenants/dezky/reconcile returns 200 with Authentik integration still ok. OPERATOR-PLAN.md O.0 checkboxes ticked.
6.6 KiB
Troubleshooting
Common issues and fixes when running the Dezky local development stack.
TLS / Certificate issues
Browser shows "Not Secure" or certificate warning
mkcert root CA isn't trusted in your browser yet.
mkcert -install
Then fully restart your browser (quit, not just close window).
Certificate not loading in Traefik
Verify the cert files exist:
ls -la infrastructure/docker-compose/certs/
# Should show:
# dezky.local.pem
# dezky.local-key.pem
If they're named differently (e.g. _wildcard.dezky.local+1.pem), rename them:
cd infrastructure/docker-compose/certs/
mv _wildcard.dezky.local+*.pem dezky.local.pem
mv _wildcard.dezky.local+*-key.pem dezky.local-key.pem
Then restart Traefik:
docker compose restart traefik
Service-to-service TLS errors
Inside Docker, services talk via internal hostnames (e.g. authentik-server:9000), not auth.dezky.local. Internal traffic uses HTTP, not HTTPS. Only Traefik handles TLS termination.
If a service config has https://authentik-server, change it to http://authentik-server.
Container startup issues
Authentik fails to start
Most common cause: PostgreSQL not ready yet, or password mismatch.
# Check postgres is healthy
docker compose ps postgres
# Should show "healthy" in STATUS
# Check Authentik DB user exists
docker compose exec postgres psql -U postgres -c "\du"
# Should list "authentik" as a user
# Check Authentik logs
docker compose logs authentik-server | tail -50
If password is wrong, reset and re-bootstrap:
./scripts/reset.sh
./scripts/bootstrap.sh
Port 25 conflict (Stalwart fails to bind)
macOS often has Postfix running by default:
sudo launchctl unload /System/Library/LaunchDaemons/org.postfix.master.plist 2>/dev/null || true
sudo launchctl stop org.postfix.master 2>/dev/null || true
Or just disable the SMTP port mapping in docker-compose.yml for local dev:
stalwart:
# ports:
# - "25:25" # comment out if conflicting
Port 80/443 conflict (Traefik fails to bind)
Another service is using those ports.
# Find what's using port 80
sudo lsof -nP -i:80 -sTCP:LISTEN
Common culprits: nginx, apache, Caddy, other Docker stacks. Stop them or change Traefik to use 8080/8443.
OCIS crashes on first start
OCIS needs to initialize before running. The compose file does this via:
command: ["-c", "ocis init --insecure true || true && ocis server"]
If init fails:
# Manually init
docker compose run --rm ocis ocis init --insecure true
# Then start
docker compose up -d ocis
DNS / hostname issues
app.dezky.local doesn't resolve
Check /etc/hosts:
grep dezky.local /etc/hosts
Should see entries pointing 127.0.0.1 to all hostnames. If missing, run:
./scripts/bootstrap.sh # Will offer to add them
Or manually:
echo "127.0.0.1 dezky.local app.dezky.local auth.dezky.local mail.dezky.local files.dezky.local office.dezky.local meet.dezky.local chat.dezky.local traefik.dezky.local" | sudo tee -a /etc/hosts
Browser DNS cache holding old entry
Clear browser cache, or test from terminal:
ping app.dezky.local
# Should return 127.0.0.1
If terminal resolves but browser doesn't:
- Chrome: chrome://net-internals/#dns → Clear host cache
- Firefox: about:networking#dns → Clear DNS cache
Authentik OIDC integration issues
"Invalid issuer URL"
The iss claim in the JWT must match exactly what the consuming service expects.
# In docker-compose.yml for OCIS:
OCIS_OIDC_ISSUER: https://auth.dezky.local/application/o/ocis/
The trailing slash matters. Authentik issues with trailing slash by default.
Verify the actual issuer:
curl -s https://auth.dezky.local/application/o/ocis/.well-known/openid-configuration | jq .issuer
"redirect_uri not allowed"
The OAuth provider in Authentik must list every redirect URI the client might use.
For OCIS:
https://files.dezky.local/
https://files.dezky.local/oidc-callback
Add both. Patterns matter — exact match.
Login loop (redirects forever)
Usually caused by:
- Time mismatch between container and host. Check
docker compose exec ocis datematches host clock. - Cookie domain mismatch. Cookies set for
.dezky.localshould work across subdomains.
Hot reload not working
Nuxt portal doesn't rebuild on file changes
The volume mount works on macOS but file watching needs explicit polling:
Add to apps/portal/nuxt.config.ts:
export default defineNuxtConfig({
vite: {
server: {
watch: {
usePolling: true,
interval: 1000,
},
},
},
})
NestJS platform-api doesn't restart
Same issue. The start:dev command uses nodemon under the hood. Make sure your package.json has:
{
"scripts": {
"start:dev": "nest start --watch"
}
}
Data and reset issues
Want to keep data but restart services
docker compose restart [service-name]
Want to reset just one service
docker compose stop authentik-server authentik-worker
docker volume rm dezky_authentik_media dezky_authentik_certs
docker compose up -d authentik-server authentik-worker
Full reset (nuclear option)
./scripts/reset.sh
./scripts/bootstrap.sh
Performance issues
Stack is using too much RAM
Check usage:
docker stats --no-stream
Top RAM consumers are usually:
- Zulip (4-6 GB) — disabled in main compose
- Jitsi (2-4 GB) — disabled in main compose
- Authentik server + worker (~1 GB each)
- OCIS (~1 GB)
- Collabora (1-2 GB if active document open)
For low-memory machines, disable services you're not using:
docker compose stop collabora # Save ~1 GB
docker compose stop ocis # Save ~1 GB if not testing files
macOS Docker is slow
OrbStack is significantly faster than Docker Desktop on macOS:
brew install --cask orbstack
Or in Docker Desktop, enable VirtioFS for bind mount performance.
Logs and debugging
See logs from one service
docker compose logs -f authentik-server
See logs from multiple services
docker compose logs -f authentik-server authentik-worker postgres
Inspect a container
docker compose exec authentik-server sh
# or
docker compose exec postgres psql -U postgres
See what's running
docker compose ps
Network debugging — can services reach each other?
docker compose exec ocis ping -c 3 authentik-server
docker compose exec ocis curl -v http://authentik-server:9000/-/health/ready/