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

# On-Premise Deployment

> Deploy Bifrost Enterprise in on-premise or air-gapped environments using Docker credentials

Bifrost Enterprise supports on-premise deployments for environments that cannot use cloud-native identity federation. Images are pulled from GCP Artifact Registry using username/password authentication.

## Architecture

```mermaid theme={null}
flowchart LR
    subgraph OnPrem[On-Premise Environment]
        subgraph K8s[Kubernetes Cluster]
            Pod[Bifrost Pod]
            Secret[imagePullSecret]
        end
        Docker[Docker Daemon]
    end
    
    subgraph GCP[GCP]
        AR[Artifact Registry<br/>Bifrost Images]
    end
    
    Secret -->|Credentials| Pod
    Pod -->|Pull| AR
    Docker -->|Pull| AR
    AR -->|Image| Pod
    AR -->|Image| Docker
```

## Prerequisites

* Kubernetes cluster (v1.23+) or Docker runtime
* Network access to `us-central1-docker.pkg.dev` (or your designated region)
* Docker credentials provided by Bifrost team

<Note>
  Contact the Bifrost team to receive your Docker username and password credentials.
</Note>

## Credentials

The Bifrost team will provide you with:

| Credential     | Description                                                  |
| -------------- | ------------------------------------------------------------ |
| **Username**   | `_json_key` (fixed value for GCP Artifact Registry)          |
| **Password**   | Service account JSON key (base64 encoded or raw JSON)        |
| **Registry**   | `REGION-docker.pkg.dev` (e.g., `us-central1-docker.pkg.dev`) |
| **Repository** | `REGION-docker.pkg.dev/BIFROST_PROJECT/YOUR_HUB_SLUG`        |

<Warning>
  Store credentials securely. Never commit them to version control or expose them in logs.
</Warning>

## Docker Deployment

### Step 1: Login to Registry

```bash theme={null}
# Using the JSON key file
cat bifrost-credentials.json | docker login -u _json_key --password-stdin https://REGION-docker.pkg.dev

# Or using the password directly
docker login -u _json_key -p "$(cat bifrost-credentials.json)" https://REGION-docker.pkg.dev
```

### Step 2: Pull the Image

```bash theme={null}
docker pull REGION-docker.pkg.dev/BIFROST_PROJECT/YOUR_HUB_SLUG/bifrost:latest
```

### Step 3: Run Bifrost

```bash theme={null}
docker run -d \
  --name bifrost \
  -p 8080:8080 \
  -v /path/to/config.json:/app/data/config.json:ro \
  -v /path/to/data:/app/data \
  REGION-docker.pkg.dev/BIFROST_PROJECT/YOUR_HUB_SLUG/bifrost:latest
```

## Kubernetes Deployment

### Step 1: Create Namespace

```bash theme={null}
kubectl create namespace bifrost
```

### Step 2: Create imagePullSecret

<Tabs>
  <Tab title="From JSON Key File">
    ```bash theme={null}
    kubectl create secret docker-registry bifrost-pull-secret \
      --docker-server=REGION-docker.pkg.dev \
      --docker-username=_json_key \
      --docker-password="$(cat bifrost-credentials.json)" \
      --namespace=bifrost
    ```
  </Tab>

  <Tab title="From Base64 Key">
    ```bash theme={null}
    # If you received a base64-encoded key
    kubectl create secret docker-registry bifrost-pull-secret \
      --docker-server=REGION-docker.pkg.dev \
      --docker-username=_json_key \
      --docker-password="$(echo 'BASE64_ENCODED_KEY' | base64 -d)" \
      --namespace=bifrost
    ```
  </Tab>

  <Tab title="Using YAML">
    ```yaml theme={null}
    apiVersion: v1
    kind: Secret
    metadata:
      name: bifrost-pull-secret
      namespace: bifrost
    type: kubernetes.io/dockerconfigjson
    data:
      .dockerconfigjson: <BASE64_ENCODED_DOCKER_CONFIG>
    ```

    Generate the base64-encoded config:

    ```bash theme={null}
    # Create docker config
    cat <<EOF > docker-config.json
    {
      "auths": {
        "REGION-docker.pkg.dev": {
          "username": "_json_key",
          "password": "$(cat bifrost-credentials.json | tr -d '\n')",
          "auth": "$(echo -n '_json_key:'$(cat bifrost-credentials.json | tr -d '\n') | base64 -w 0)"
        }
      }
    }
    EOF

    # Base64 encode for secret
    cat docker-config.json | base64 -w 0
    ```
  </Tab>
</Tabs>

### Step 3: Create Bifrost Configuration

<Note>
  If you use PostgreSQL for `config_store` or `logs_store`, ensure the target database is UTF8 encoded. See [PostgreSQL UTF8 Requirement](../../quickstart/gateway/setting-up#postgresql-utf8-requirement).
</Note>

```yaml theme={null}
apiVersion: v1
kind: Secret
metadata:
  name: bifrost-config
  namespace: bifrost
type: Opaque
stringData:
  config.json: |
    {
      "config_store": {
        "enabled": true,
        "type": "postgres",
        "config": {
          "host": "postgres.bifrost.svc.cluster.local",
          "port": "5432",
          "user": "bifrost",
          "password": "YOUR_PASSWORD",
          "db_name": "bifrost",
          "ssl_mode": "disable"
        }
      },
      "logs_store": {
        "enabled": true,
        "type": "postgres",
        "config": {
          "host": "postgres.bifrost.svc.cluster.local",
          "port": "5432",
          "user": "bifrost",
          "password": "YOUR_PASSWORD",
          "db_name": "bifrost",
          "ssl_mode": "disable"
        }
      }
    }
```

### Step 4: Deploy Bifrost

```yaml theme={null}
apiVersion: apps/v1
kind: Deployment
metadata:
  name: bifrost
  namespace: bifrost
spec:
  replicas: 2
  selector:
    matchLabels:
      app: bifrost
  template:
    metadata:
      labels:
        app: bifrost
    spec:
      imagePullSecrets:
      - name: bifrost-pull-secret
      containers:
      - name: bifrost
        image: REGION-docker.pkg.dev/BIFROST_PROJECT/YOUR_HUB_SLUG/bifrost:latest
        ports:
        - containerPort: 8080
          name: http
        resources:
          requests:
            cpu: "250m"
            memory: "512Mi"
          limits:
            cpu: "1000m"
            memory: "2Gi"
        livenessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 10
          periodSeconds: 5
        volumeMounts:
        - name: config
          mountPath: /app/data/config.json
          subPath: config.json
        - name: data
          mountPath: /app/data
      volumes:
      - name: config
        secret:
          secretName: bifrost-config
      - name: data
        persistentVolumeClaim:
          claimName: bifrost-data
---
apiVersion: v1
kind: Service
metadata:
  name: bifrost
  namespace: bifrost
spec:
  selector:
    app: bifrost
  ports:
  - port: 80
    targetPort: 8080
    protocol: TCP
  type: ClusterIP
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: bifrost-data
  namespace: bifrost
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
```

### Step 5: Expose Bifrost (Optional)

<Tabs>
  <Tab title="Ingress">
    ```yaml theme={null}
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: bifrost
      namespace: bifrost
      annotations:
        nginx.ingress.kubernetes.io/proxy-body-size: "50m"
    spec:
      ingressClassName: nginx
      rules:
      - host: bifrost.your-domain.com
        http:
          paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: bifrost
                port:
                  number: 80
      tls:
      - hosts:
        - bifrost.your-domain.com
        secretName: bifrost-tls
    ```
  </Tab>

  <Tab title="LoadBalancer">
    ```yaml theme={null}
    apiVersion: v1
    kind: Service
    metadata:
      name: bifrost-lb
      namespace: bifrost
    spec:
      selector:
        app: bifrost
      ports:
      - port: 80
        targetPort: 8080
        protocol: TCP
      type: LoadBalancer
    ```
  </Tab>

  <Tab title="NodePort">
    ```yaml theme={null}
    apiVersion: v1
    kind: Service
    metadata:
      name: bifrost-nodeport
      namespace: bifrost
    spec:
      selector:
        app: bifrost
      ports:
      - port: 80
        targetPort: 8080
        nodePort: 30080
        protocol: TCP
      type: NodePort
    ```
  </Tab>
</Tabs>

## Docker Compose Deployment

For simpler deployments without Kubernetes:

```yaml theme={null}
version: '3.8'

services:
  bifrost:
    image: REGION-docker.pkg.dev/BIFROST_PROJECT/YOUR_HUB_SLUG/bifrost:latest
    container_name: bifrost
    ports:
      - "8080:8080"
    volumes:
      - ./config.json:/app/data/config.json:ro
      - bifrost-data:/app/data
    environment:
      - BIFROST_LOG_LEVEL=info
    healthcheck:
      test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s
    restart: unless-stopped

  postgres:
    image: postgres:15-alpine
    container_name: bifrost-postgres
    environment:
      - POSTGRES_USER=bifrost
      - POSTGRES_PASSWORD=YOUR_PASSWORD
      - POSTGRES_DB=bifrost
    volumes:
      - postgres-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U bifrost"]
      interval: 10s
      timeout: 5s
      retries: 5
    restart: unless-stopped

volumes:
  bifrost-data:
  postgres-data:
```

Login to registry before running:

```bash theme={null}
cat bifrost-credentials.json | docker login -u _json_key --password-stdin https://REGION-docker.pkg.dev
docker compose up -d
```

## Air-Gapped Environments

For environments without internet access, you can mirror the image to your internal registry.

### Step 1: Pull Image (Internet-Connected Machine)

```bash theme={null}
# Login and pull
cat bifrost-credentials.json | docker login -u _json_key --password-stdin https://REGION-docker.pkg.dev
docker pull REGION-docker.pkg.dev/BIFROST_PROJECT/YOUR_HUB_SLUG/bifrost:latest

# Save to tar file
docker save REGION-docker.pkg.dev/BIFROST_PROJECT/YOUR_HUB_SLUG/bifrost:latest > bifrost-image.tar
```

### Step 2: Transfer and Load (Air-Gapped Machine)

```bash theme={null}
# Load image
docker load < bifrost-image.tar

# Tag for internal registry
docker tag REGION-docker.pkg.dev/BIFROST_PROJECT/YOUR_HUB_SLUG/bifrost:latest \
  internal-registry.company.com/bifrost:latest

# Push to internal registry
docker push internal-registry.company.com/bifrost:latest
```

### Step 3: Update Kubernetes Manifests

Update the image reference in your deployment:

```yaml theme={null}
containers:
- name: bifrost
  image: internal-registry.company.com/bifrost:latest
```

## Credential Rotation

When the Bifrost team rotates your credentials:

### Update Docker Login

```bash theme={null}
cat new-credentials.json | docker login -u _json_key --password-stdin https://REGION-docker.pkg.dev
```

### Update Kubernetes Secret

```bash theme={null}
# Delete old secret
kubectl delete secret bifrost-pull-secret -n bifrost

# Create new secret
kubectl create secret docker-registry bifrost-pull-secret \
  --docker-server=REGION-docker.pkg.dev \
  --docker-username=_json_key \
  --docker-password="$(cat new-credentials.json)" \
  --namespace=bifrost

# Restart deployment to pick up new secret
kubectl rollout restart deployment/bifrost -n bifrost
```

## Verifying Access

### Test Docker Authentication

```bash theme={null}
# Verify login
docker login -u _json_key -p "$(cat bifrost-credentials.json)" https://REGION-docker.pkg.dev

# Test pull
docker pull REGION-docker.pkg.dev/BIFROST_PROJECT/YOUR_HUB_SLUG/bifrost:latest
```

### Verify Kubernetes Secret

```bash theme={null}
# Check secret exists
kubectl get secret bifrost-pull-secret -n bifrost

# Verify secret content (base64 encoded)
kubectl get secret bifrost-pull-secret -n bifrost -o jsonpath='{.data.\.dockerconfigjson}' | base64 -d
```

## Troubleshooting

### ImagePullBackOff Errors

```bash theme={null}
# Check pod events
kubectl describe pod -l app=bifrost -n bifrost

# Common issues:
# - "unauthorized": Invalid credentials - check username/password
# - "not found": Wrong repository path - verify with Bifrost team
# - "connection refused": Network issue - check firewall rules
```

### Network Connectivity

```bash theme={null}
# Test DNS resolution
nslookup REGION-docker.pkg.dev

# Test HTTPS connectivity
curl -v https://REGION-docker.pkg.dev/v2/

# Required outbound access:
# - REGION-docker.pkg.dev:443
# - oauth2.googleapis.com:443 (for token refresh)
```

### Credential Issues

```bash theme={null}
# Verify JSON key format
cat bifrost-credentials.json | jq .

# Check key hasn't expired
cat bifrost-credentials.json | jq '.private_key_id'

# Contact Bifrost team if credentials are invalid
```

## Security Best Practices

1. **Store credentials securely**: Use a secrets manager (Vault, AWS Secrets Manager) for credential storage
2. **Limit access**: Only grant imagePullSecret access to required namespaces
3. **Rotate regularly**: Request credential rotation from Bifrost team periodically
4. **Audit access**: Monitor image pull logs for unauthorized access attempts
5. **Network isolation**: Restrict outbound access to only required registry endpoints

## Next Steps

* Configure [Bifrost settings](/quickstart/gateway/setting-up) for your use case
* Set up [observability](/features/observability/default) for monitoring
* Enable [clustering](/enterprise/clustering) for high availability
