Skip to content

Dual Domain Support

Overview

The platform supports two primary domains simultaneously: - portugalodyssey.pt (primary domain) - portugalodissey.pt (secondary domain)

Both domains work identically, with services automatically detecting which domain was used in the original request and using the appropriate domain for API calls and external URLs.

Architecture

Domain Detection

Frontend (Browser): - Uses window.location.hostname to detect the current domain - Dynamically constructs service URLs based on detected domain - Falls back to environment variables if domain detection fails

Backend Services: - Detect domain from request headers (X-Forwarded-Host or Host) - Set cookies dynamically based on request origin - Use appropriate domain for external URLs and callbacks

Traefik Routing

Traefik routes both domains to the same services: - Router rules include both domains using || operator - Example: Host(\qual.portugalodyssey.pt`) || Host(`qual.portugalodissey.pt`)` - Certificates are automatically requested for both domains via Let's Encrypt

Certificate Management

  • Traefik automatically requests certificates for both domains
  • Separate certificates are issued for each domain and subdomain
  • Certificates are managed via ACME HTTP challenge
  • Note: Be aware of Let's Encrypt rate limits when requesting certificates

Configuration

Traefik Router Rules

All services exposed via Traefik include both domains in their router rules:

labels:
  - "traefik.http.routers.service-name.rule=Host(`service.portugalodyssey.pt`) || Host(`service.portugalodissey.pt`)"

CORS Configuration

Both domains are included in CORS middleware (infrastructure/traefik/dynamic.yml): - default-headers middleware includes all portugalodissey.pt variants - secure-headers middleware includes production portugalodissey.pt domains

Frontend Domain Detection

The frontend uses the domain-detector utility (frontends/public-fo/src/utils/domain-detector.ts):

import { getCmsUrl, getApiBaseUrl } from '../utils/domain-detector';

// Automatically detects domain and constructs URLs
const cmsUrl = getCmsUrl(); // Returns https://cms-qual.portugalodissey.pt if accessed via portugalodissey.pt

The auth-service detects the domain from request headers and sets cookies accordingly:

// In auth-service
const cookieDomain = this.getCookieDomain(req); // Returns .portugalodissey.pt or .portugalodyssey.pt
res.cookie("po_rt", token, { domain: cookieDomain });

Keycloak Configuration

Keycloak redirect URIs include both domains: - public-app: Includes portugalodissey.pt redirect URIs - admin-app: Includes admin.portugalodissey.pt redirect URIs - partner-console: Includes console.portugalodissey.pt redirect URIs - auth-service: Includes auth.portugalodissey.pt redirect URIs

Keycloak uses --hostname-strict=false to accept requests from any hostname, with routing handled by Traefik.

Supported Domains

Qualification Environment

Service portugalodyssey.pt portugalodissey.pt
Public FO qual.portugalodyssey.pt qual.portugalodissey.pt
API Gateway api-qual.portugalodyssey.pt api-qual.portugalodissey.pt
CMS cms-qual.portugalodyssey.pt cms-qual.portugalodissey.pt
Auth Service auth-qual.portugalodyssey.pt auth-qual.portugalodissey.pt
Payment Service payment-qual.portugalodyssey.pt payment-qual.portugalodissey.pt
Notification Service notification-qual.portugalodyssey.pt notification-qual.portugalodissey.pt
File Service files-qual.portugalodyssey.pt files-qual.portugalodissey.pt
Keycloak sso-qual.portugalodyssey.pt sso-qual.portugalodissey.pt

Production Environment

Service portugalodyssey.pt portugalodissey.pt
Public FO portugalodyssey.pt, www.portugalodyssey.pt portugalodissey.pt, www.portugalodissey.pt
API Gateway api.portugalodyssey.pt api.portugalodissey.pt
CMS cms.portugalodyssey.pt cms.portugalodissey.pt
Auth Service auth.portugalodyssey.pt auth.portugalodissey.pt
Payment Service payment.portugalodyssey.pt payment.portugalodissey.pt
Notification Service notification.portugalodyssey.pt notification.portugalodissey.pt
File Service files.portugalodyssey.pt files.portugalodissey.pt
Keycloak sso.portugalodyssey.pt sso.portugalodissey.pt

How It Works

User Flow

  1. User accesses https://qual.portugalodissey.pt
  2. Traefik routes request to public-fo-qual service
  3. Frontend detects domain via window.location.hostname
  4. Frontend constructs API URLs using portugalodissey.pt domain:
  5. https://api-qual.portugalodissey.pt
  6. https://cms-qual.portugalodissey.pt
  7. etc.
  8. Backend services detect domain from request headers
  9. Cookies are set with .portugalodissey.pt domain
  10. All subsequent requests use portugalodissey.pt domain

Service-to-Service Communication

Internal service-to-service communication continues to use internal HTTP URLs: - http://payment-service-qual:3000 - http://user-management-qual:3000 - etc.

This ensures efficient internal communication without going through Traefik.

Troubleshooting

Certificates Not Issued

If certificates are not being issued for portugalodissey.pt domains:

  1. Check Traefik logs for ACME errors:

    docker logs po-traefik 2>&1 | grep -i "acme\|certificate\|portugalodissey"
    

  2. Verify router rules include both domains:

    docker inspect po-public-fo-qual | grep -i "rule"
    

  3. Check Let's Encrypt rate limits (see Let's Encrypt Rate Limit Guide)

Cookies Not Working

If cookies are not working across domains:

  1. Verify auth-service is detecting domain correctly:
  2. Check request headers include X-Forwarded-Host or Host
  3. Verify cookie domain matches request domain

  4. Check browser console for cookie errors:

  5. Cookies set for .portugalodyssey.pt won't work for portugalodissey.pt
  6. Ensure cookies are set with correct domain

CORS Errors

If CORS errors occur:

  1. Verify domain is in CORS middleware:
  2. Check infrastructure/traefik/dynamic.yml
  3. Ensure both domains are in accessControlAllowOriginList

  4. Check request origin matches allowed origins

Keycloak Redirect Errors

If Keycloak redirects fail:

  1. Verify redirect URI is in Keycloak realm configuration:
  2. Check infrastructure/keycloak/realm-export.json
  3. Ensure portugalodissey.pt URIs are included

  4. Re-import realm if needed:

    docker restart po-keycloak-qual
    

Testing

Verify Domain Detection

  1. Access https://qual.portugalodyssey.pt
  2. Open browser DevTools → Network tab
  3. Verify API calls use portugalodyssey.pt domain

  4. Access https://qual.portugalodissey.pt

  5. Open browser DevTools → Network tab
  6. Verify API calls use portugalodissey.pt domain

Verify Certificates

# Check certificate for portugalodissey.pt
curl -I https://qual.portugalodissey.pt

# Check certificate details
openssl s_client -connect qual.portugalodissey.pt:443 -servername qual.portugalodissey.pt

Verify Cookies

  1. Access site via portugalodissey.pt
  2. Log in
  3. Check browser DevTools → Application → Cookies
  4. Verify cookie domain is .portugalodissey.pt