> ## Documentation Index
> Fetch the complete documentation index at: https://backstage.spotify.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Installation and Setup

> Step-by-step guide to install and deploy Portal Connect Agent

This guide walks you through installing and configuring the Portal Connect Agent.

## Overview

Installing Portal Connect involves:

1. Generating a client mTLS certificate for authentication
2. Creating a configuration file with your routes
3. Deploying the Agent container
4. Verifying the connection and registration

**Time to complete:** 15-30 minutes

## Before You Begin

Ensure you have completed the prerequisites:

* Docker installed and running
* Internal service URLs identified
* Network access verified

## Step 1: Generate mTLS Certificates

Portal Connect uses mTLS for secure authentication. Generate your client certificate using the Agent's built-in tool.

### Pull the Agent Image

First, obtain the Portal Connect Agent Docker image:

```bash theme={"theme":{"light":"github-light","dark":"dracula"}}
docker pull \
  europe-west1-docker.pkg.dev/spc-global-admin/spotify-portal-connect/portal-connect-agent:latest
```

### Generate Certificates

Run the certificate generation command:

```bash theme={"theme":{"light":"github-light","dark":"dracula"}}
# Create a directory for certificates
mkdir -p ./certs

# Generate certificates
docker run --rm \
  -v $(pwd)/certs:/tmp/certs \
  europe-west1-docker.pkg.dev/spc-global-admin/spotify-portal-connect/portal-connect-agent:latest \
  --generate-cert
```

This creates two files in the `./certs` directory:

* `portal-connect-client-<timestamp>.crt` - Client certificate (public)
* `portal-connect-client-<timestamp>.key` - Private key (private)

### Secure Your Private Key

Set appropriate permissions on the private key:

```bash theme={"theme":{"light":"github-light","dark":"dracula"}}
chmod 400 ./certs/portal-connect-client-<timestamp>.key
```

<Danger>
  **Important**

  Never share or commit the `portal-connect-client-<timestamp>.key` file. Treat it as a secret.
</Danger>

### Register Your Certificate with Spotify

Visit the [Support Center](https://support.backstage.byspotify.com/tickets) and submit a new ticket asking to register your Portal Connect certificate. Under Attachments, upload your `portal-connect-client-<timestamp>.crt` file (public certificate only). Spotify will use this file to register your certificate. Note that the private key should never leave your infrastructure.

<Warning>
  **Certificate Expiry**

  Certificates are valid for only **180 days**. Repeat step 1 before the certificate expires, delivering the new certificate to Spotify first, before deploying the new key and certificate to your agents.
</Warning>

## Step 2: Create Configuration File

Create a YAML configuration file named `app-config.yaml`:

### Basic Configuration

```yaml theme={"theme":{"light":"github-light","dark":"dracula"}}
agent:
  # WebSocket URL (provided by Spotify)
  brokerUrl: wss://broker.${subdomain}.spotifyportal.com

  # Routes to external services
  routes:
    - https://api.github.com/*
    - https://internal-api.company.com/v1/*

  # mTLS authentication
  mtls:
    clientCertPath: /certs/portal-connect-client-<timestamp>.crt
    clientKeyPath: /certs/portal-connect-client-<timestamp>.key
```

### Configuration with Headers

If your external services require authentication, add headers per route:

```yaml theme={"theme":{"light":"github-light","dark":"dracula"}}
agent:
  brokerUrl: wss://broker.${subdomain}.spotifyportal.com

  routes:
    'https://api.github.com/*':
      headers:
        authorization: 'Bearer ${GITHUB_TOKEN}'

    'https://internal-api.company.com/v1/*':
      headers:
        x-api-key: '${INTERNAL_API_KEY}'
        x-forwarded-by: 'portal-connect-agent'

  mtls:
    clientCertPath: /certs/portal-connect-client-<timestamp>.crt
    clientKeyPath: /certs/portal-connect-client-<timestamp>.key
```

<Tip>
  **Using Environment Variables**

  * Reference environment variables with `${VAR_NAME}`
  * For file-based secrets, use `${VAR_NAME_FILE}` to read from a file path
</Tip>

### Configuration File Location

Save the `app-config.yaml` file in a secure location accessible to Docker:

```
./portal-connect/
  ├── app-config.yaml
  └── certs/
      ├── portal-connect-client-<timestamp>.crt
      └── portal-connect-client-<timestamp>.key
```

## Step 3: Deploy the Agent

You can deploy the Agent using Docker run, Docker Compose, or orchestration platforms like Kubernetes.

### Option A: Docker Run

Deploy using a simple docker run command:

```bash theme={"theme":{"light":"github-light","dark":"dracula"}}
docker run -d \
  --name portal-connect-agent \
  -v $(pwd)/app-config.yaml:/app/config/app-config.yaml:ro \
  -v $(pwd)/certs:/certs:ro \
  -e CONFIG_PATH=/app/config/app-config.yaml \
  -e GITHUB_TOKEN="your-github-token" \
  -e INTERNAL_API_KEY="your-api-key" \
  -p 9466:9466 \
  --restart unless-stopped \
  europe-west1-docker.pkg.dev/spc-global-admin/spotify-portal-connect/portal-connect-agent:latest
```

**Parameters explained:**

* `--name` - Container name for easy reference
* `-v` - Mount configuration file and certificates (read-only)
* `-e CONFIG_PATH` - Path to configuration file inside container
* `-e GITHUB_TOKEN` - Environment variable for token substitution
* `-p 9466:9466` - Expose metrics port (optional)
* `--restart unless-stopped` - Automatic restart policy

### Option B: Docker Compose

Create a `docker-compose.yml` file:

```yaml theme={"theme":{"light":"github-light","dark":"dracula"}}
version: '3.8'

services:
  portal-connect-agent:
    image: europe-west1-docker.pkg.dev/spc-global-admin/spotify-portal-connect/portal-connect-agent:latest
    container_name: portal-connect-agent
    restart: unless-stopped
    volumes:
      - ./app-config.yaml:/app/config/app-config.yaml:ro
      - ./certs:/certs:ro
    environment:
      - CONFIG_PATH=/app/config/app-config.yaml
      - GITHUB_TOKEN=${GITHUB_TOKEN}
      - INTERNAL_API_KEY=${INTERNAL_API_KEY}
    ports:
      - '9466:9466'
```

Create a `.env` file for environment variables:

```bash theme={"theme":{"light":"github-light","dark":"dracula"}}
GITHUB_TOKEN=your-github-token
INTERNAL_API_KEY=your-api-key
```

Deploy with Docker Compose:

```bash theme={"theme":{"light":"github-light","dark":"dracula"}}
docker-compose up -d
```

### Option C: Kubernetes

Create a Kubernetes deployment:

```yaml theme={"theme":{"light":"github-light","dark":"dracula"}}
apiVersion: apps/v1
kind: Deployment
metadata:
  name: portal-connect-agent
spec:
  replicas: 1
  selector:
    matchLabels:
      app: portal-connect-agent
  template:
    metadata:
      labels:
        app: portal-connect-agent
    spec:
      containers:
        - name: agent
          image: europe-west1-docker.pkg.dev/spc-global-admin/spotify-portal-connect/portal-connect-agent:latest
          env:
            - name: CONFIG_PATH
              value: /app/config/app-config.yaml
            - name: GITHUB_TOKEN
              valueFrom:
                secretKeyRef:
                  name: portal-connect-secrets
                  key: github-token
          volumeMounts:
            - name: config
              mountPath: /app/config
              readOnly: true
            - name: certs
              mountPath: /certs
              readOnly: true
          ports:
            - containerPort: 9466
              name: metrics
      volumes:
        - name: config
          configMap:
            name: portal-connect-config
        - name: certs
          secret:
            secretName: portal-connect-certs
```

Create the ConfigMap and Secrets:

```bash theme={"theme":{"light":"github-light","dark":"dracula"}}
# Create ConfigMap for configuration
kubectl create configmap portal-connect-config \
  --from-file=app-config.yaml=./app-config.yaml

# Create Secret for certificates
kubectl create secret generic portal-connect-certs \
  --from-file=portal-connect-client-<timestamp>.crt=./certs/portal-connect-client-<timestamp>.crt \
  --from-file=portal-connect-client-<timestamp>.key=./certs/portal-connect-client-<timestamp>.key

# Create Secret for API credentials
kubectl create secret generic portal-connect-secrets \
  --from-literal=github-token='your-github-token' \
  --from-literal=internal-api-key='your-api-key'

# Deploy
kubectl apply -f deployment.yaml
```

## Step 4: Verify the Deployment

### Check Agent Logs

View the Agent logs to confirm successful startup:

```bash theme={"theme":{"light":"github-light","dark":"dracula"}}
# Docker
docker logs portal-connect-agent

# Docker Compose
docker-compose logs -f portal-connect-agent

# Kubernetes
kubectl logs -f deployment/portal-connect-agent
```

**Expected log messages:**

```
Agent starting...
Loading configuration from /app/config/app-config.yaml
Validating mTLS certificates...
mTLS certificates validated successfully
Connecting to broker at wss://broker.${subdomain}.spotifyportal.com
WebSocket connected
Registering routes...
Registration completed successfully
```

### Check Metrics

Query the metrics endpoint to verify the Agent is healthy:

```bash theme={"theme":{"light":"github-light","dark":"dracula"}}
curl http://localhost:9466/metrics
```

Look for metrics indicating:

* WebSocket connection state: `agent_websocket_connected{} 1`
* Registered routes count
* No connection errors

## Troubleshooting Installation

### Certificate Validation Fails

**Error message:** `mTLS certificate validation failed`

**Solutions:**

* Verify certificate files exist at the specified paths
* Check file permissions (should be readable by container user)
* Ensure certificates are valid and not expired
* Verify certificates are in PEM format

### Cannot Connect to Broker

**Error message:** `Failed to connect to broker` or `WebSocket connection failed`

**Solutions:**

* Verify broker URL is correct in configuration
* Check network connectivity to the broker URL
* Ensure firewall allows outbound WSS connections (the Agent only needs outbound access)
* Verify client certificate is registered with Spotify
* Check that your Portal instance is operational (contact Spotify support)

<Info>
  **Outbound Connection Only**

  This is an outbound connection from the Agent. You should NOT need to configure any inbound firewall rules.
</Info>

### Configuration File Not Found

**Error message:** `Configuration file not found` or `ENOENT`

**Solutions:**

* Verify volume mount path is correct
* Check `CONFIG_PATH` environment variable matches mounted path
* Ensure configuration file has correct filename
* Check file permissions allow read access

### Container Exits Immediately

**Solutions:**

* Check logs: `docker logs portal-connect-agent`
* Verify configuration file syntax:
  ```bash theme={"theme":{"light":"github-light","dark":"dracula"}}
  docker run --rm -v $(pwd)/app-config.yaml:/config.yaml <image> --validate-config /config.yaml
  ```
* Check all required environment variables are set
* Ensure certificates are mounted correctly
