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
Backend Cookie Domain¶
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¶
- User accesses
https://qual.portugalodissey.pt - Traefik routes request to
public-fo-qualservice - Frontend detects domain via
window.location.hostname - Frontend constructs API URLs using
portugalodissey.ptdomain: https://api-qual.portugalodissey.pthttps://cms-qual.portugalodissey.pt- etc.
- Backend services detect domain from request headers
- Cookies are set with
.portugalodissey.ptdomain - All subsequent requests use
portugalodissey.ptdomain
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:
-
Check Traefik logs for ACME errors:
-
Verify router rules include both domains:
-
Check Let's Encrypt rate limits (see Let's Encrypt Rate Limit Guide)
Cookies Not Working¶
If cookies are not working across domains:
- Verify auth-service is detecting domain correctly:
- Check request headers include
X-Forwarded-HostorHost -
Verify cookie domain matches request domain
-
Check browser console for cookie errors:
- Cookies set for
.portugalodyssey.ptwon't work forportugalodissey.pt - Ensure cookies are set with correct domain
CORS Errors¶
If CORS errors occur:
- Verify domain is in CORS middleware:
- Check
infrastructure/traefik/dynamic.yml -
Ensure both domains are in
accessControlAllowOriginList -
Check request origin matches allowed origins
Keycloak Redirect Errors¶
If Keycloak redirects fail:
- Verify redirect URI is in Keycloak realm configuration:
- Check
infrastructure/keycloak/realm-export.json -
Ensure portugalodissey.pt URIs are included
-
Re-import realm if needed:
Testing¶
Verify Domain Detection¶
- Access
https://qual.portugalodyssey.pt - Open browser DevTools → Network tab
-
Verify API calls use
portugalodyssey.ptdomain -
Access
https://qual.portugalodissey.pt - Open browser DevTools → Network tab
- Verify API calls use
portugalodissey.ptdomain
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¶
- Access site via portugalodissey.pt
- Log in
- Check browser DevTools → Application → Cookies
- Verify cookie domain is
.portugalodissey.pt