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:

  1. Keycloak URLs – the OIDC issuer must be reachable from both the user’s browser and the API server.

  2. API server URL – the frontend needs to reach the API, and Keycloak needs to send backchannel logout requests to it.

  3. 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):

  1. Remove the service from your local docker-compose-prod.yml

  2. Point 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'

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_ISSUER is reachable from both the user’s browser and the API server container

  • Inside 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_URL in the frontend environment points to the correct API server URL

  • If behind a reverse proxy, ensure the /api path is forwarded correctly

Services not starting
  • Check service logs: docker compose logs <service-name>

  • Verify all dependent services are healthy: docker compose ps

  • Check firewall rules and network connectivity between servers