Multi-Server Deployment¶
This guide covers deploying ubTrace services across different servers or network configurations.
Architecture Overview¶
ubTrace consists of the following services that need to communicate:
API server (NestJS backend) – serves the REST API
Frontend (Next.js) – serves the web application
Keycloak – handles authentication (OIDC)
PostgreSQL – application database
Elasticsearch – search and analytics indexing
Redis – caching and session management
In the default Docker Compose setup, all services run on the same host and communicate via the internal Docker network. For multi-server deployments, the key challenge is configuring the public-facing URLs correctly.
URL Configuration¶
Three sets of URLs must be configured:
Keycloak URLs – the OIDC issuer must be reachable from both the user’s browser and the API server.
API server URL – the frontend needs to reach the API, and Keycloak needs to send backchannel logout requests to it.
Frontend URL – used for post-login redirects.
# .env -- adjust to your actual hostnames/IPs
# Keycloak (must be reachable from browser AND ubtrace-api)
KC_HOSTNAME=https://auth.yourdomain.com
OIDC_ISSUER=https://auth.yourdomain.com/realms/ubtrace
# API server (must be reachable from browser AND keycloak)
API_SERVER_PUBLIC_URL=https://api.yourdomain.com
# Frontend (used for redirects after login)
FRONTEND_PUBLIC_URL=https://ubtrace.yourdomain.com
FRONTEND_UBT_URL=https://ubtrace.yourdomain.com
Deployment Scenarios¶
Single Host (Docker Compose)¶
The default docker-compose-prod.yml runs all services on one machine.
No special URL configuration is needed beyond setting passwords.
docker compose -f docker-compose-prod.yml up -d
Split Services (Multiple Hosts)¶
When services run on different machines (e.g., database on a dedicated server):
Remove the service from your local
docker-compose-prod.ymlPoint the relevant environment variables to the remote host
Example – external PostgreSQL:
# .env
DATABASE_URL=postgresql://ubtrace:password@db-server.internal:5432/ubtrace
Example – external Elasticsearch:
# In the ubtrace-api environment section of docker-compose-prod.yml
ELASTICSEARCH_NODE: 'http://es-server.internal:9200'
A remote Elasticsearch is reached over a slower path than a co-located one – more so when the traffic passes through a tunnel, a proxy hop or a managed Elasticsearch-compatible service. If administrative calls fail or indexing a large project’s documents does not complete, raise the per-request timeout (default 5000 ms) on both the API and the worker:
# .env
ELASTICSEARCH_REQUEST_TIMEOUT_MS=30000
Accepted range: 1–600000 ms. The readiness health check keeps its own, separate timeout, so raising this value does not delay ubTrace noticing that Elasticsearch is unreachable.
Warning
On the worker, raise WORKER_VISIBILITY_TIMEOUT_MS (default 600000 ms)
along with this value. A load task must finish all of its Elasticsearch work
inside that window; document indexing issues many sequential bulk requests,
so a slow path multiplies. A task that overruns the window is treated as
abandoned – it is re-enqueued alongside the copy still running, and after
repeated overruns the version is dead-lettered.
Note
On Kubernetes, set api.config.elasticsearchRequestTimeoutMs and
worker.elasticsearchRequestTimeoutMs in the Helm values instead –
per component, so the worker can carry a higher value than the API. The
companion worker.visibilityTimeoutMs is the Helm equivalent of
WORKER_VISIBILITY_TIMEOUT_MS in the warning above.
Reverse Proxy¶
For production, place a reverse proxy (nginx, Traefik, Caddy) in front of the services to handle TLS termination:
Browser --> Reverse Proxy (TLS) --> Frontend (:7155)
--> API Server (:7150)
--> Keycloak (:7181)
Ensure that the KC_HOSTNAME, API_SERVER_PUBLIC_URL, and FRONTEND_PUBLIC_URL
variables use the external HTTPS URLs that the browser will access.
Troubleshooting¶
- OIDC errors after login
Verify
OIDC_ISSUERis reachable from both the user’s browser and the API server containerInside the Docker network, the API server uses
OIDC_BASE_URL(http://ubtrace-keycloak:8080/...) for server-to-server communication
- Frontend cannot reach API
Check that
UBTRACE_API_URLin the frontend environment points to the correct API server URLIf behind a reverse proxy, ensure the
/apipath is forwarded correctly
- Services not starting
Check service logs:
docker compose logs <service-name>Verify all dependent services are healthy:
docker compose psCheck firewall rules and network connectivity between servers