diff --git a/.gitignore b/.gitignore index 107208d..0ecc9a2 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,7 @@ # Node.js node_modules/ -**/node_modules/ \ No newline at end of file +**/node_modules/ + +# Local SSL certificates (generated by npm run createCA) +ca/ \ No newline at end of file diff --git a/README.md b/README.md index dfec8c8..34600a0 100644 --- a/README.md +++ b/README.md @@ -1,108 +1,104 @@ # UID2 Integration Examples -The [UID2 framework](https://unifiedid.com/docs/intro) enables publishers to integrate in either of the following ways: +Sample sites demonstrating UID2/EUID integration patterns. -- Via the standard integration workflow, using the [UID2 SDK for JavaScript](https://unifiedid.com/docs/sdks/client-side-identity) (also known as the UID2 SDK). -- Via the server-only (custom) integration workflow, by building a direct integration without using the UID2 SDK. +## Prerequisites -If you are a content publisher interested in generating UID2 tokens for the real-time bidding (RTB) bid stream and want to see how you can use the UID2 services and which integration fits your needs best, you can build and run an example application for each integration. +### 1. Set Up Environment Variables -The following table summarizes both examples and provides links to the example applications, their documentation, and the respective step-by-step integration guides. +Copy one of the sample environment files: -| Environment | Documentation | Description | Primary Audience | Integration Guide | -|-------------|----------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| Node.js | [UID2 SDK Integration Example](./publisher/standard/README.md) | Demonstrates how to use the UID2 services with the [UID2 client SDK](https://unifiedid.com/docs/sdks/client-side-identity) to implement the standard UID2 integration workflow. | Publishers with web assets | [Client SDK Integration Guide](https://unifiedid.com/docs/guides/publisher-client-side) | -| Node.js | [Server-Only UID2 Integration Example](https://github.com/UnifiedID2/uid2-examples/tree/main/publisher/server_only) | Demonstrates how to use the UID2 services to implement a custom (server-only) UID2 integration workflow without relying on an SDK for establishing client UID2 identity and retrieving advertising tokens. | App developers and CTV broadcasters | [Server-Only UID2 Integration Guide](https://unifiedid.com/docs/guides/custom-publisher-integration) | -| Java | [Java SDK Integration Example](./publisher/uid2-java-test-site/README.md) | Demonstrates use of the [UID2 Java SDK](https://github.com/IABTechLab/uid2-client-java) for both a server-only UID2 integration, and a standard (client SDK and server SDK) integration. | Publishers with web assets, app developers, CTV broadcasters | [Server-Only](https://unifiedid.com/docs/guides/custom-publisher-integration); [Client SDK](https://unifiedid.com/docs/guides/publisher-client-side) | +```bash +# For UID2 +cp .env.sample.uid2 .env -The example applications illustrate the basic steps that you need to consider for your integration. For example, you need to decide how to do the following: -- Implement user login and logout. -- Manage UID2 identity information and use it for targeted advertising. -- Refresh tokens. -- Deal with missing identities. -- Handle user opt-outs. +# For EUID +cp .env.sample.euid .env +``` -## Docker Compose Setup +Edit `.env` and add your credentials: +- `UID_API_KEY` - Your API key +- `UID_CLIENT_SECRET` - Your client secret +- `UID_CSTG_SERVER_PUBLIC_KEY` - Your CSTG public key +- `UID_CSTG_SUBSCRIPTION_ID` - Your CSTG subscription ID -This repository includes Docker Compose configuration for easy development and testing of multiple UID2 integration examples. +### 2. Run a Local Operator (Required) -### Quick Start +These sample sites require a local UID2 operator instance. -**Start all services:** -```bash -docker-compose up -d -``` +1. Clone the operator repo: + ```bash + git clone https://github.com/IABTechLab/uid2-operator.git + ``` -**Start a single service:** -```bash -# Start only the Prebid.js client-side integration -docker-compose up -d prebid-client +2. Follow the setup instructions in the [uid2-operator README](https://github.com/IABTechLab/uid2-operator#readme) -# Start with live logs (foreground) -docker-compose up prebid-client -``` +3. Ensure the operator is running on `http://localhost:8080` + +--- + +## Running the Sample Sites + +### Start All Services -**Stop services:** ```bash +# Start all sample sites +docker-compose up -d + # Stop all services docker-compose down +``` + +### Start a Single Service + +```bash +# Start only prebid-client +docker-compose up -d prebid-client # Stop a single service docker-compose stop prebid-client ``` -**View logs:** -```bash -# View all logs -docker-compose logs -f -# View logs for a specific service -docker-compose logs -f prebid-client -``` +### Rebuild After Code Changes -**Rebuild and restart:** ```bash -# Rebuild and restart all services +# Rebuild all docker-compose up -d --build -# Rebuild and restart a single service +# Rebuild a single service docker-compose up -d --build prebid-client ``` +See the list below for the name of all individual services. -### Available Services - -- **`prebid-client`** - Prebid.js client-side integration (Port: 3031) -- **`javascript-sdk-client`** - JavaScript SDK client-server integration (Port: 3051) -- *More services will be added as they are containerized* +--- -### Environment Configuration +## Available Sample Sites -This repository includes sample environment files for both UID2 and EUID configurations: +| Service Name | Description | Port | URL | +|--------------|-------------|------|-----| +| `javascript-sdk-client-side` | JavaScript SDK Client Side | 3031 | http://localhost:3031 | +| `javascript-sdk-client-server` | JavaScript SDK Client Server | 3032 | http://localhost:3032 | +| `server-side` | Server Side Integration | 3033 | http://localhost:3033 | +| `javascript-sdk-react-client-side` | JavaScript SDK React | 3034 | http://localhost:3034 | +| `google-secure-signals-client-server` | Google Secure Signals Client Server | 3041 | http://localhost:3041 | +| `google-secure-signals-client-side` | Google Secure Signals Client Side | 3042 | http://localhost:3042 | +| `google-secure-signals-server-side` | Google Secure Signals Server Side | 3043 | http://localhost:3043 | +| `google-secure-signals-react-client-side` | Google Secure Signals React | 3044 | http://localhost:3044 | +| `prebid-client` | Prebid Client Side | 3051 | http://localhost:3051 | +| `prebid-client-server` | Prebid Client Server | 3052 | http://localhost:3052 | +| `prebid-client-side-deferred` | Prebid Client Side Deferred | 3053 | http://localhost:3053 | +| `prebid-secure-signals-client-side` | Prebid Secure Signals | 3061 | http://localhost:3061 | -- **`.env.sample.uid2`** - UID2 configuration template -- **`.env.sample.euid`** - EUID configuration template +--- -**To get started:** - -1. Copy the appropriate sample file to `.env`: - ```bash - # For UID2 - cp .env.sample.uid2 .env - - # For EUID - cp .env.sample.euid .env - ``` +## Run Without Local Operator (Using Integ Environment) -2. Update the `.env` file with your credentials: - - Replace `your-api-key` with your actual API key - - Replace `your-client-secret` with your actual client secret - - Update other placeholder values as needed +If you don't want to run a local operator, you can use HTTPS with custom domains to hit the integration environment operator instead. -The sample files include all necessary environment variables for running the examples, including configuration for: -- Core API endpoints -- JavaScript SDK settings -- Google Secure Signals integration -- Prebid integration -- React client examples -- UI/Display preferences +This setup: +- Uses `https://` with subdomains (e.g., `https://prebid-client.sample-dev.com`) +- Connects to the UID2 integration operator (no local operator required) +- Requires certificate setup and hosts file configuration +See [tools/reverse-proxy/README.md](tools/reverse-proxy/README.md) for setup instructions. diff --git a/createCA.ts b/createCA.ts new file mode 100644 index 0000000..cf4afaa --- /dev/null +++ b/createCA.ts @@ -0,0 +1,67 @@ +import { createCA, createCert } from 'mkcert'; +import { allDomains } from './siteDetails'; +import fs from 'node:fs/promises'; + +const domains = allDomains; + +const caFolder = './ca/'; +const caFile = `${caFolder}ca.crt`; +const caKey = `${caFolder}ca.key`; +const certFile = `${caFolder}cert.crt`; +const certKey = `${caFolder}cert.key`; + +const overwriteFileOptions = { + flag: 'w', +}; +const failIfExistsFileOptions = { + flag: 'wx', +}; + +const fileExists = async (path: string) => !!(await fs.stat(path).catch((e) => false)); + +const getOrCreateCA = async () => { + if (await fileExists(caFile)) { + console.log('Found existing CA, loading...'); + return { + cert: await fs.readFile(caFile, { encoding: 'utf8' }), + key: await fs.readFile(caKey, { encoding: 'utf8' }), + }; + } else { + console.log('Creating new CA...'); + const ca = await createCA({ + organization: 'UID2 Examples local dev CA', + countryCode: 'AU', + state: 'NSW', + locality: 'Sydney', + validity: 3650, + }); + await fs.mkdir(caFolder, { recursive: true }); + await fs.writeFile(caFile, ca.cert, failIfExistsFileOptions); + await fs.writeFile(caKey, ca.key, failIfExistsFileOptions); + return ca; + } +}; + +async function createCerts() { + const ca = await getOrCreateCA(); + console.log(`Creating a certificate for ${domains.join(', ')}`); + const cert = await createCert({ + ca: { key: ca.key, cert: ca.cert }, + domains, + validity: 3650, + }); + console.log('Certificate created.'); + + await fs.writeFile(certFile, `${cert.cert}${ca.cert}`, overwriteFileOptions); + await fs.writeFile(certKey, cert.key, overwriteFileOptions); + + console.log('Certificate saved to ./ca/ folder.'); + console.log(''); + console.log('Next steps:'); + console.log('1. Trust the CA certificate (ca.crt) in your system/browser'); + console.log('2. Add the domains to your hosts file (see README.md)'); + console.log('3. Run: docker-compose up'); +} + +createCerts(); + diff --git a/docker-compose.yml b/docker-compose.yml index 5cb29ab..fd1525d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,6 +6,9 @@ services: dockerfile: Dockerfile ports: - "80:80" + - "443:443" + volumes: + - ./ca:/etc/nginx/certs:ro container_name: reverse-proxy environment: - DOMAIN=${DOMAIN:-sample-dev.com} @@ -115,6 +118,16 @@ services: env_file: - .env + prebid-client-side-deferred: + build: + context: web-integrations/prebid-integrations + dockerfile: client-side-deferred/Dockerfile + ports: + - "3053:3053" + container_name: prebid-client-side-deferred + env_file: + - .env + # prebid + secure signals integrations prebid-secure-signals-client-side: build: diff --git a/package-lock.json b/package-lock.json index b51c040..90aa74b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,7 +7,14 @@ "": { "name": "uid2-examples", "version": "0.2.71", - "license": "BSD-2-Clause" + "license": "BSD-2-Clause", + "devDependencies": { + "mkcert": "^3.2.0", + "tsx": "^4.19.1" + }, + "engines": { + "node": ">=18" + } } } } diff --git a/package.json b/package.json index 9ef89e0..8a5ab40 100644 --- a/package.json +++ b/package.json @@ -3,5 +3,15 @@ "version": "0.2.71", "private": true, "description": "UID2 Integration Examples", - "license": "BSD-2-Clause" + "license": "BSD-2-Clause", + "engines": { + "node": ">=18" + }, + "scripts": { + "createCA": "tsx createCA.ts" + }, + "devDependencies": { + "mkcert": "^3.2.0", + "tsx": "^4.19.1" + } } diff --git a/siteDetails.js b/siteDetails.js new file mode 100644 index 0000000..720d2e0 --- /dev/null +++ b/siteDetails.js @@ -0,0 +1,105 @@ +/** + * Site details configuration for UID2 example sites. + * These domains are used for local development with HTTPS. + */ + +const sites = [ + // JavaScript SDK integrations + { + name: 'js-client-side', + domain: 'js-client-side.sample-dev.com', + port: 3031, + description: 'JavaScript SDK Client Side', + }, + { + name: 'js-client-server', + domain: 'js-client-server.sample-dev.com', + port: 3032, + description: 'JavaScript SDK Client Server', + }, + { + name: 'js-react', + domain: 'js-react.sample-dev.com', + port: 3034, + description: 'JavaScript SDK React Client Side', + }, + + // Server-side integration + { + name: 'server-side', + domain: 'server-side.sample-dev.com', + port: 3033, + description: 'Server Side Integration', + }, + + // Google Secure Signals integrations + { + name: 'secure-signals-client-server', + domain: 'secure-signals-client-server.sample-dev.com', + port: 3041, + description: 'Google Secure Signals Client Server', + }, + { + name: 'secure-signals-client-side', + domain: 'secure-signals-client-side.sample-dev.com', + port: 3042, + description: 'Google Secure Signals Client Side', + }, + { + name: 'secure-signals-server-side', + domain: 'secure-signals-server-side.sample-dev.com', + port: 3043, + description: 'Google Secure Signals Server Side', + }, + { + name: 'secure-signals-react', + domain: 'secure-signals-react.sample-dev.com', + port: 3044, + description: 'Google Secure Signals React Client Side', + }, + + // Prebid integrations + { + name: 'prebid-client', + domain: 'prebid-client.sample-dev.com', + port: 3051, + description: 'Prebid Client Side', + }, + { + name: 'prebid-client-server', + domain: 'prebid-client-server.sample-dev.com', + port: 3052, + description: 'Prebid Client Server', + }, + { + name: 'prebid-deferred', + domain: 'prebid-deferred.sample-dev.com', + port: 3053, + description: 'Prebid Client Side Deferred (mergeConfig)', + }, + + // Prebid + Secure Signals integrations + { + name: 'prebid-secure-signals', + domain: 'prebid-secure-signals.sample-dev.com', + port: 3061, + description: 'Prebid Secure Signals Client Side', + }, +]; + +// Export for CommonJS (used by createCA.ts) +export const port = 443; + +export const urlPortSuffix = port === 443 ? '' : `:${port}`; + +export const devSites = sites.map((s) => ({ ...s, url: `https://${s.domain}${urlPortSuffix}/` })); + +export const devDomains = Object.values(devSites).map((s) => s.domain); + +export const devSiteMap = Object.fromEntries(devSites.map((s) => [s.name, s])); + +export const topLevelDomain = 'sample-dev.com'; + +// Also include the root domain for certificate (index page) +export const allDomains = [topLevelDomain, ...devDomains]; + diff --git a/tools/reverse-proxy/Dockerfile b/tools/reverse-proxy/Dockerfile index 1aff542..e8b9836 100644 --- a/tools/reverse-proxy/Dockerfile +++ b/tools/reverse-proxy/Dockerfile @@ -1,11 +1,14 @@ FROM nginx:alpine -# Install wget for healthcheck and gettext for envsubst -RUN apk add --no-cache wget gettext +# Install wget for healthcheck, gettext for envsubst, and openssl for fallback cert generation +RUN apk add --no-cache wget gettext openssl # Create templates directory RUN mkdir -p /etc/nginx/templates +# Create directory for SSL certificates +RUN mkdir -p /etc/nginx/certs + # Copy custom nginx.conf with increased server_names_hash_bucket_size COPY nginx.conf /etc/nginx/nginx.conf @@ -19,7 +22,8 @@ RUN chmod +x /docker-entrypoint.sh # Create directory for static files (optional) RUN mkdir -p /usr/share/nginx/html -EXPOSE 80 +# Expose both HTTP and HTTPS ports +EXPOSE 80 443 ENTRYPOINT ["/docker-entrypoint.sh"] CMD ["nginx", "-g", "daemon off;"] diff --git a/tools/reverse-proxy/README.md b/tools/reverse-proxy/README.md index e86559a..77e8053 100644 --- a/tools/reverse-proxy/README.md +++ b/tools/reverse-proxy/README.md @@ -1,174 +1,161 @@ # Nginx Reverse Proxy -A nginx reverse proxy configuration that routes requests to different backend services based on subdomain. +Routes HTTPS requests to UID sample sites based on subdomain. -## Configuration +## Prerequisites: Environment Variables -This reverse proxy is configured to forward requests to different ports based on subdomain. Each subdomain maps to a specific service defined in `docker-compose.yml`. +Before running the sample sites, create a `.env` file in the project root (`uid2-examples/`) with your API credentials. -### Environment Variables +1. Copy one of the sample files: + ```bash + # For UID2 + cp .env.sample.uid2 .env -The domain used for subdomain routing can be configured using the `DOMAIN` environment variable. This allows you to use different domains for different environments (dev, test, prod). + # For EUID + cp .env.sample.euid .env + ``` -**Default:** `sample-dev.com` (if `DOMAIN` is not set) +2. Edit `.env` and add your credentials: + - `UID_API_KEY` - Your API key + - `UID_CLIENT_SECRET` - Your client secret + - `UID_CSTG_SERVER_PUBLIC_KEY` - Your CSTG public key + - `UID_CSTG_SUBSCRIPTION_ID` - Your CSTG subscription ID -**Examples:** -- Development: `DOMAIN=sample-dev.com` -- Test: `DOMAIN=sample-test.com` -- Production: `DOMAIN=sample-prod.com` +See the sample files for all available configuration options. -### Subdomain Routing +--- -The following subdomains are configured (using `${DOMAIN}` as the base domain): +## Quick Start -- `js-client-side.${DOMAIN}` → JavaScript SDK Client Side (port 3031) -- `js-client-server.${DOMAIN}` → JavaScript SDK Client Server (port 3032) -- `js-react.${DOMAIN}` → JavaScript SDK React Client Side (port 3034) -- `server-side.${DOMAIN}` → Server Side Integration (port 3033) -- `secure-signals-client-server.${DOMAIN}` → Google Secure Signals Client Server (port 3041) -- `secure-signals-client-side.${DOMAIN}` → Google Secure Signals Client Side (port 3042) -- `secure-signals-server-side.${DOMAIN}` → Google Secure Signals Server Side (port 3043) -- `secure-signals-react.${DOMAIN}` → Google Secure Signals React Client Side (port 3044) -- `prebid-client.${DOMAIN}` → Prebid Client Side (port 3051) -- `prebid-client-server.${DOMAIN}` → Prebid Client Server (port 3052) -- `prebid-secure-signals.${DOMAIN}` → Prebid Secure Signals Client Side (port 3061) +### 1. Install Dependencies & Generate Certificates -**Example with default domain (`sample-dev.com`):** -- `js-client-side.sample-dev.com` → JavaScript SDK Client Side (port 3031) -- `js-client-server.sample-dev.com` → JavaScript SDK Client Server (port 3032) -- etc. +```bash +cd /path/to/uid2-examples +npm install +npm run createCA +``` -## Required Hosts File Configuration +### 2. Trust the CA Certificate (macOS) -To use the subdomain-based routing, you must add entries to your hosts file so that these subdomains resolve to localhost. +```bash +sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain ./ca/ca.crt +``` -**Note:** Replace `sample-dev.com` with your configured `DOMAIN` value in the examples below. +Enter your password when prompted. -### Windows +
+Windows instructions -1. Open Notepad (or your preferred text editor) **as Administrator** - - Right-click Notepad → "Run as administrator" - - Or use PowerShell as Administrator +1. Double-click `ca/ca.crt` +2. Click `Install Certificate...` → `Current User` → `Next` +3. Select `Place all certificates in the following store` → `Browse...` +4. Choose `Trusted Root Certification Authorities` → `OK` → `Next` → `Finish` -2. Open the hosts file: - ``` - C:\Windows\System32\drivers\etc\hosts - ``` +
-3. Add the following entries at the end of the file: - ``` - 127.0.0.1 js-client-side.sample-dev.com - 127.0.0.1 js-client-server.sample-dev.com - 127.0.0.1 js-react.sample-dev.com - 127.0.0.1 server-side.sample-dev.com - 127.0.0.1 secure-signals-client-server.sample-dev.com - 127.0.0.1 secure-signals-client-side.sample-dev.com - 127.0.0.1 secure-signals-server-side.sample-dev.com - 127.0.0.1 secure-signals-react.sample-dev.com - 127.0.0.1 prebid-client.sample-dev.com - 127.0.0.1 prebid-client-server.sample-dev.com - 127.0.0.1 prebid-secure-signals.sample-dev.com - ``` +### 3. Add Hosts File Entries -4. Save the file +Open your hosts file: +```bash +# macOS/Linux +sudo nano /etc/hosts -5. Flush DNS cache (run in PowerShell as Administrator): - ```powershell - ipconfig /flushdns - ``` +# Windows (run Notepad as Administrator) +# Open: C:\Windows\System32\drivers\etc\hosts +``` -### macOS / Linux +Add these entries: -1. Open the hosts file with sudo: - ```bash - sudo nano /etc/hosts - ``` - (or use `vim`, `vi`, or your preferred editor) +``` +127.0.0.1 sample-dev.com +127.0.0.1 js-client-side.sample-dev.com +127.0.0.1 js-client-server.sample-dev.com +127.0.0.1 js-react.sample-dev.com +127.0.0.1 server-side.sample-dev.com +127.0.0.1 secure-signals-client-server.sample-dev.com +127.0.0.1 secure-signals-client-side.sample-dev.com +127.0.0.1 secure-signals-server-side.sample-dev.com +127.0.0.1 secure-signals-react.sample-dev.com +127.0.0.1 prebid-client.sample-dev.com +127.0.0.1 prebid-client-server.sample-dev.com +127.0.0.1 prebid-deferred.sample-dev.com +127.0.0.1 prebid-secure-signals.sample-dev.com +``` -2. Add the following entries: - ``` - 127.0.0.1 js-client-side.sample-dev.com - 127.0.0.1 js-client-server.sample-dev.com - 127.0.0.1 js-react.sample-dev.com - 127.0.0.1 server-side.sample-dev.com - 127.0.0.1 secure-signals-client-server.sample-dev.com - 127.0.0.1 secure-signals-client-side.sample-dev.com - 127.0.0.1 secure-signals-server-side.sample-dev.com - 127.0.0.1 secure-signals-react.sample-dev.com - 127.0.0.1 prebid-client.sample-dev.com - 127.0.0.1 prebid-client-server.sample-dev.com - 127.0.0.1 prebid-secure-signals.sample-dev.com - ``` +Flush DNS cache after saving: +```bash +# macOS +sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder +``` -3. Save and exit +### 4. Start All Services -4. Flush DNS cache (if needed): - ```bash - # macOS - sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder - - # Linux (systemd-resolved) - sudo systemd-resolve --flush-caches - ``` +```bash +docker-compose up -d +``` -## Usage +> **Important:** This starts ALL containers (reverse-proxy + all sample sites). The reverse-proxy only routes traffic—it doesn't contain the sites themselves. -### Using Docker Compose (Recommended) +### 5. Access the Sites -When using `docker-compose.yml` from the project root, the reverse proxy will automatically connect to other services on the same Docker network: +Go to **https://sample-dev.com** — this index page has clickable links to all sample sites. -**Default domain (sample-dev.com):** -```bash -docker-compose up reverse-proxy -``` +--- -**Custom domain:** -```bash -DOMAIN=sample-test.com docker-compose up reverse-proxy -``` +## Available Sites -**Or set in your `.env` file:** -```bash -DOMAIN=sample-prod.com -``` +| URL | Description | Port | +|-----|-------------|------| +| `https://sample-dev.com` | Index page (links to all sites) | — | +| `https://js-client-side.sample-dev.com` | JavaScript SDK Client Side | 3031 | +| `https://js-client-server.sample-dev.com` | JavaScript SDK Client Server | 3032 | +| `https://server-side.sample-dev.com` | Server Side Integration | 3033 | +| `https://js-react.sample-dev.com` | JavaScript SDK React | 3034 | +| `https://secure-signals-client-server.sample-dev.com` | Google Secure Signals Client Server | 3041 | +| `https://secure-signals-client-side.sample-dev.com` | Google Secure Signals Client Side | 3042 | +| `https://secure-signals-server-side.sample-dev.com` | Google Secure Signals Server Side | 3043 | +| `https://secure-signals-react.sample-dev.com` | Google Secure Signals React | 3044 | +| `https://prebid-client.sample-dev.com` | Prebid Client Side | 3051 | +| `https://prebid-client-server.sample-dev.com` | Prebid Client Server | 3052 | +| `https://prebid-deferred.sample-dev.com` | Prebid Client Side Deferred | 3053 | +| `https://prebid-secure-signals.sample-dev.com` | Prebid Secure Signals | 3061 | -Then run: -```bash -docker-compose up reverse-proxy -``` +--- -### Standalone Build and Run +## Troubleshooting -#### Build the image -```bash -docker build -t nginx-reverse-proxy . -``` +### Browser shows "Not Secure" warning +1. Make sure you trusted the CA certificate (step 2) +2. **Fully quit Chrome** (Cmd+Q) and reopen it +3. Verify trust worked: `security dump-trust-settings -d | grep -A2 "UID2 Examples"` -#### Run the container +### 502 Bad Gateway +The backend service isn't running. Make sure you ran `docker-compose up -d` (not just the reverse-proxy). -**Default domain:** -```bash -docker run -d -p 80:80 --name nginx-proxy nginx-reverse-proxy -``` +### Site not loading at all +- Check hosts file entries are correct +- Flush DNS cache +- Make sure you're using `https://` not `http://` -**Custom domain:** +### Re-generating certificates +If you add new domains or delete the `ca/` folder: ```bash -docker run -d -p 80:80 -e DOMAIN=sample-test.com --name nginx-proxy nginx-reverse-proxy +npm run createCA +# Then re-trust the CA certificate (step 2) ``` -**Note:** When running standalone, you'll need to ensure the backend services are accessible. You may need to modify the `proxy_pass` directives in `default.conf.template` to use `host.docker.internal` or the appropriate Docker network hostname. +--- -## Customization +## Alternative: Direct Access (No Certificates) -Edit `default.conf.template` to customize the nginx configuration: -- Add or remove server blocks for different subdomains -- Modify subdomain names in the `server_name` directives (use `${DOMAIN}` for the domain variable) -- Adjust proxy headers as needed -- Add additional location blocks for specific routes +You can skip all certificate setup and access services directly via localhost: -**Important:** After modifying `default.conf.template`, rebuild the Docker image: -```bash -docker-compose build reverse-proxy -docker-compose up -d reverse-proxy -``` +| URL | Service | +|-----|---------| +| `http://localhost:3051` | Prebid Client Side | +| `http://localhost:3052` | Prebid Client Server | +| `http://localhost:3053` | Prebid Client Side Deferred | +| `http://localhost:3031` | JavaScript SDK Client Side | +| *(etc.)* | +This bypasses the reverse-proxy entirely—no HTTPS, no subdomains needed. diff --git a/tools/reverse-proxy/default.conf.template b/tools/reverse-proxy/default.conf.template index 50c9276..1aa35ea 100644 --- a/tools/reverse-proxy/default.conf.template +++ b/tools/reverse-proxy/default.conf.template @@ -2,7 +2,13 @@ # Matches localhost (for local dev) and root domain (for production) server { listen 80; - server_name localhost 127.0.0.1 ${DOMAIN} www.${DOMAIN}; + listen 443 ssl; + server_name localhost 127.0.0.1 ${DOMAIN}; + + ssl_certificate /etc/nginx/certs/cert.crt; + ssl_certificate_key /etc/nginx/certs/cert.key; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers HIGH:!aNULL:!MD5; # Exact match for /ops/healthcheck (highest priority) location = /ops/healthcheck { @@ -14,15 +20,21 @@ server { location / { add_header Content-Type text/html; # Use protocol-relative URLs (//) so they work with both http and https - return 200 "UID2 Sample Pages

UID2 Sample Pages

Access services using the following subdomains:

js-client-side.${DOMAIN}js-client-server.${DOMAIN}js-react.${DOMAIN}server-side.${DOMAIN}secure-signals-client-server.${DOMAIN}secure-signals-client-side.${DOMAIN}secure-signals-server-side.${DOMAIN}secure-signals-react.${DOMAIN}prebid-client.${DOMAIN}prebid-client-server.${DOMAIN}prebid-secure-signals.${DOMAIN}
Note: For local development, add ${DOMAIN} and all subdomains to your hosts file (127.0.0.1) to use them. Example: 127.0.0.1 ${DOMAIN} js-client-side.${DOMAIN} ...
"; + return 200 "UID2 Sample Pages

UID2 Sample Pages

Access services using the following subdomains:

js-client-side.${DOMAIN}js-client-server.${DOMAIN}js-react.${DOMAIN}server-side.${DOMAIN}secure-signals-client-server.${DOMAIN}secure-signals-client-side.${DOMAIN}secure-signals-server-side.${DOMAIN}secure-signals-react.${DOMAIN}prebid-client.${DOMAIN}prebid-client-server.${DOMAIN}prebid-deferred.${DOMAIN} (mergeConfig example)prebid-secure-signals.${DOMAIN}
Note: For local development, add ${DOMAIN} and all subdomains to your hosts file (127.0.0.1) to use them. Example: 127.0.0.1 ${DOMAIN} js-client-side.${DOMAIN} ...
"; } } # Default server block - catch-all for unmatched subdomains server { listen 80 default_server; + listen 443 ssl default_server; server_name _; + ssl_certificate /etc/nginx/certs/cert.crt; + ssl_certificate_key /etc/nginx/certs/cert.key; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers HIGH:!aNULL:!MD5; + # Exact match for /ops/healthcheck (highest priority) location = /ops/healthcheck { access_log off; @@ -39,8 +51,14 @@ server { # JavaScript SDK - Client Side (port 3031) server { listen 80; + listen 443 ssl; server_name js-client-side.${DOMAIN} *.js-client-side.${DOMAIN}; + ssl_certificate /etc/nginx/certs/cert.crt; + ssl_certificate_key /etc/nginx/certs/cert.key; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers HIGH:!aNULL:!MD5; + location / { proxy_pass http://${JS_CLIENT_SIDE_BACKEND}:3031; proxy_redirect off; @@ -57,8 +75,14 @@ server { # JavaScript SDK - Client Server (port 3032) server { listen 80; + listen 443 ssl; server_name js-client-server.${DOMAIN} *.js-client-server.${DOMAIN}; + ssl_certificate /etc/nginx/certs/cert.crt; + ssl_certificate_key /etc/nginx/certs/cert.key; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers HIGH:!aNULL:!MD5; + location / { proxy_pass http://${JS_CLIENT_SERVER_BACKEND}:3032; proxy_redirect off; @@ -75,8 +99,14 @@ server { # JavaScript SDK - React Client Side (port 3034) server { listen 80; + listen 443 ssl; server_name js-react.${DOMAIN} *.js-react.${DOMAIN}; + ssl_certificate /etc/nginx/certs/cert.crt; + ssl_certificate_key /etc/nginx/certs/cert.key; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers HIGH:!aNULL:!MD5; + location / { proxy_pass http://${JS_REACT_CLIENT_SIDE_BACKEND}:3034; proxy_redirect off; @@ -93,8 +123,14 @@ server { # Server Side Integration (port 3033) server { listen 80; + listen 443 ssl; server_name server-side.${DOMAIN} *.server-side.${DOMAIN}; + ssl_certificate /etc/nginx/certs/cert.crt; + ssl_certificate_key /etc/nginx/certs/cert.key; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers HIGH:!aNULL:!MD5; + location / { proxy_pass http://${SERVER_SIDE_BACKEND}:3033; proxy_redirect off; @@ -111,8 +147,14 @@ server { # Google Secure Signals - Client Server (port 3041) server { listen 80; + listen 443 ssl; server_name secure-signals-client-server.${DOMAIN} *.secure-signals-client-server.${DOMAIN}; + ssl_certificate /etc/nginx/certs/cert.crt; + ssl_certificate_key /etc/nginx/certs/cert.key; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers HIGH:!aNULL:!MD5; + location / { proxy_pass http://${SECURE_SIGNALS_CLIENT_SERVER_BACKEND}:3041; proxy_redirect off; @@ -129,8 +171,14 @@ server { # Google Secure Signals - Client Side (port 3042) server { listen 80; + listen 443 ssl; server_name secure-signals-client-side.${DOMAIN} *.secure-signals-client-side.${DOMAIN}; + ssl_certificate /etc/nginx/certs/cert.crt; + ssl_certificate_key /etc/nginx/certs/cert.key; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers HIGH:!aNULL:!MD5; + location / { proxy_pass http://${SECURE_SIGNALS_CLIENT_SIDE_BACKEND}:3042; proxy_redirect off; @@ -147,8 +195,14 @@ server { # Google Secure Signals - Server Side (port 3043) server { listen 80; + listen 443 ssl; server_name secure-signals-server-side.${DOMAIN} *.secure-signals-server-side.${DOMAIN}; + ssl_certificate /etc/nginx/certs/cert.crt; + ssl_certificate_key /etc/nginx/certs/cert.key; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers HIGH:!aNULL:!MD5; + location / { proxy_pass http://${SECURE_SIGNALS_SERVER_SIDE_BACKEND}:3043; proxy_redirect off; @@ -165,8 +219,14 @@ server { # Google Secure Signals - React Client Side (port 3044) server { listen 80; + listen 443 ssl; server_name secure-signals-react.${DOMAIN} *.secure-signals-react.${DOMAIN}; + ssl_certificate /etc/nginx/certs/cert.crt; + ssl_certificate_key /etc/nginx/certs/cert.key; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers HIGH:!aNULL:!MD5; + location / { proxy_pass http://${SECURE_SIGNALS_REACT_CLIENT_SIDE_BACKEND}:3044; proxy_redirect off; @@ -183,8 +243,14 @@ server { # Prebid - Client Side (port 3051) server { listen 80; + listen 443 ssl; server_name prebid-client.${DOMAIN} *.prebid-client.${DOMAIN}; + ssl_certificate /etc/nginx/certs/cert.crt; + ssl_certificate_key /etc/nginx/certs/cert.key; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers HIGH:!aNULL:!MD5; + location / { proxy_pass http://${PREBID_CLIENT_BACKEND}:3051; proxy_redirect off; @@ -211,8 +277,14 @@ server { # Prebid - Client Server (port 3052) server { listen 80; + listen 443 ssl; server_name prebid-client-server.${DOMAIN} *.prebid-client-server.${DOMAIN}; + ssl_certificate /etc/nginx/certs/cert.crt; + ssl_certificate_key /etc/nginx/certs/cert.key; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers HIGH:!aNULL:!MD5; + location / { proxy_pass http://${PREBID_CLIENT_SERVER_BACKEND}:3052; proxy_redirect off; @@ -226,11 +298,41 @@ server { } } +# Prebid - Client Side Deferred (port 3053) - mergeConfig example +server { + listen 80; + listen 443 ssl; + server_name prebid-deferred.${DOMAIN} *.prebid-deferred.${DOMAIN}; + + ssl_certificate /etc/nginx/certs/cert.crt; + ssl_certificate_key /etc/nginx/certs/cert.key; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers HIGH:!aNULL:!MD5; + + location / { + proxy_pass http://${PREBID_CLIENT_SIDE_DEFERRED_BACKEND}:3053; + proxy_redirect off; + proxy_connect_timeout 5s; + proxy_send_timeout 60s; + proxy_read_timeout 60s; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} + # Prebid Secure Signals - Client Side (port 3061) server { listen 80; + listen 443 ssl; server_name prebid-secure-signals.${DOMAIN} *.prebid-secure-signals.${DOMAIN}; + ssl_certificate /etc/nginx/certs/cert.crt; + ssl_certificate_key /etc/nginx/certs/cert.key; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers HIGH:!aNULL:!MD5; + location / { proxy_pass http://${PREBID_SECURE_SIGNALS_CLIENT_SIDE_BACKEND}:3061; proxy_redirect off; @@ -243,4 +345,3 @@ server { proxy_set_header X-Forwarded-Proto $scheme; } } - diff --git a/tools/reverse-proxy/docker-entrypoint.sh b/tools/reverse-proxy/docker-entrypoint.sh index 564d297..bb31cb0 100644 --- a/tools/reverse-proxy/docker-entrypoint.sh +++ b/tools/reverse-proxy/docker-entrypoint.sh @@ -4,6 +4,22 @@ set -e # Default domain if not set DOMAIN=${DOMAIN:-sample-dev.com} +# Check if SSL certificates exist +if [ ! -f /etc/nginx/certs/cert.crt ] || [ ! -f /etc/nginx/certs/cert.key ]; then + echo "WARNING: SSL certificates not found at /etc/nginx/certs/" + echo "HTTPS will not work until you generate certificates." + echo "Run 'npm install && npm run createCA' in the project root to generate certificates." + echo "Then trust the CA certificate (ca/ca.crt) in your system/browser." + echo "" + echo "Creating self-signed fallback certificates for startup..." + # Create fallback self-signed certificate so nginx can start + mkdir -p /etc/nginx/certs + openssl req -x509 -nodes -days 1 -newkey rsa:2048 \ + -keyout /etc/nginx/certs/cert.key \ + -out /etc/nginx/certs/cert.crt \ + -subj "/CN=localhost" 2>/dev/null || true +fi + # Default backend host pattern (defaults to localhost for Kubernetes same-pod) # For Docker Compose with separate containers, set BACKEND_HOST="" to use service names # Check if BACKEND_HOST is explicitly set to empty string - if so, use service names @@ -20,6 +36,7 @@ if [ "${BACKEND_HOST+set}" = "set" ] && [ -z "$BACKEND_HOST" ]; then SECURE_SIGNALS_REACT_CLIENT_SIDE_BACKEND=${SECURE_SIGNALS_REACT_CLIENT_SIDE_BACKEND:-google-secure-signals-react-client-side} PREBID_CLIENT_BACKEND=${PREBID_CLIENT_BACKEND:-prebid-client} PREBID_CLIENT_SERVER_BACKEND=${PREBID_CLIENT_SERVER_BACKEND:-prebid-client-server} + PREBID_CLIENT_SIDE_DEFERRED_BACKEND=${PREBID_CLIENT_SIDE_DEFERRED_BACKEND:-prebid-client-side-deferred} PREBID_SECURE_SIGNALS_CLIENT_SIDE_BACKEND=${PREBID_SECURE_SIGNALS_CLIENT_SIDE_BACKEND:-prebid-secure-signals-client-side} else # BACKEND_HOST is unset (defaults to localhost) or set to a value - use it for all services @@ -34,6 +51,7 @@ else SECURE_SIGNALS_REACT_CLIENT_SIDE_BACKEND=${SECURE_SIGNALS_REACT_CLIENT_SIDE_BACKEND:-$BACKEND_HOST_VALUE} PREBID_CLIENT_BACKEND=${PREBID_CLIENT_BACKEND:-$BACKEND_HOST_VALUE} PREBID_CLIENT_SERVER_BACKEND=${PREBID_CLIENT_SERVER_BACKEND:-$BACKEND_HOST_VALUE} + PREBID_CLIENT_SIDE_DEFERRED_BACKEND=${PREBID_CLIENT_SIDE_DEFERRED_BACKEND:-$BACKEND_HOST_VALUE} PREBID_SECURE_SIGNALS_CLIENT_SIDE_BACKEND=${PREBID_SECURE_SIGNALS_CLIENT_SIDE_BACKEND:-$BACKEND_HOST_VALUE} fi @@ -49,10 +67,11 @@ export SECURE_SIGNALS_SERVER_SIDE_BACKEND export SECURE_SIGNALS_REACT_CLIENT_SIDE_BACKEND export PREBID_CLIENT_BACKEND export PREBID_CLIENT_SERVER_BACKEND +export PREBID_CLIENT_SIDE_DEFERRED_BACKEND export PREBID_SECURE_SIGNALS_CLIENT_SIDE_BACKEND # Substitute environment variables in the template -envsubst '${DOMAIN} ${JS_CLIENT_SIDE_BACKEND} ${JS_CLIENT_SERVER_BACKEND} ${JS_REACT_CLIENT_SIDE_BACKEND} ${SERVER_SIDE_BACKEND} ${SECURE_SIGNALS_CLIENT_SERVER_BACKEND} ${SECURE_SIGNALS_CLIENT_SIDE_BACKEND} ${SECURE_SIGNALS_SERVER_SIDE_BACKEND} ${SECURE_SIGNALS_REACT_CLIENT_SIDE_BACKEND} ${PREBID_CLIENT_BACKEND} ${PREBID_CLIENT_SERVER_BACKEND} ${PREBID_SECURE_SIGNALS_CLIENT_SIDE_BACKEND}' < /etc/nginx/templates/default.conf.template > /etc/nginx/conf.d/default.conf +envsubst '${DOMAIN} ${JS_CLIENT_SIDE_BACKEND} ${JS_CLIENT_SERVER_BACKEND} ${JS_REACT_CLIENT_SIDE_BACKEND} ${SERVER_SIDE_BACKEND} ${SECURE_SIGNALS_CLIENT_SERVER_BACKEND} ${SECURE_SIGNALS_CLIENT_SIDE_BACKEND} ${SECURE_SIGNALS_SERVER_SIDE_BACKEND} ${SECURE_SIGNALS_REACT_CLIENT_SIDE_BACKEND} ${PREBID_CLIENT_BACKEND} ${PREBID_CLIENT_SERVER_BACKEND} ${PREBID_CLIENT_SIDE_DEFERRED_BACKEND} ${PREBID_SECURE_SIGNALS_CLIENT_SIDE_BACKEND}' < /etc/nginx/templates/default.conf.template > /etc/nginx/conf.d/default.conf # Test nginx configuration nginx -t