# Deploy the solution on premises

> Deploy Self-Hosted Deployment on premises using the vpctl tool

Before deployment, check the [prerequisites](./prerequisites.md).

The deployment on premises uses the vpctl tool to manage the entire release lifecycle. If all prerequisites are met, the deployment takes 30 to 60 minutes. This time doesn't include the subsequent [administration tasks](../../admin/_index), such as setting up an identity provider for single sign-on (SSO).

> **Note:**
>
> For an end-to-end overview of how vpctl orchestrates the deployment (data flow, components, and trust boundaries), refer to [vpctl architecture](../../vpctl/architecture). This is useful for security teams reviewing the deployment.

Follow these steps to deploy Self-Hosted Deployment to your Kubernetes cluster.

## 1. Configure the registry credentials

Before you can pull releases, configure your ORAS registry credentials. This is a one-time setup.

Run the interactive configuration:

```sh
vpctl configure
```

For non-interactive setup and credential verification, see [Configure registry credentials](../../vpctl/install#configure-registry-credentials).

## 2. Initialize the manifest file

The manifest file `manifest.yaml` contains your deployment configuration. The vpctl tool automatically discovers `manifest.yaml` in the current directory or in the parent directories.

If you do not have a manifest file, create one:

```sh
vpctl manifest init
```

The interactive prompts ask for the platform, the release version, the source and target registries, the application domain, the Kubernetes namespace, the autoscaling settings, the monitoring options, the sizing profile, the Traefik service type, and the ArgoCD settings (if applicable).

### Validate the manifest

To validate your manifest against the built-in schema before continuing, run this command:

```sh
vpctl manifest validate
```

This command checks the required fields, the allowed values, and the cross-field rules (for example, `maxReplicas >= minReplicas`).

### Configure the manifest file

The manifest file controls the entire deployment. Here is a minimal skeleton:

```yaml
platform: onprem
releaseVersion: 0.13.0

artifactSync:
  sourceRepository: uccmpprivatecloud.azurecr.io

configuration:
  networking:
    appDomain: example.com
    ingress:
      traefik:
        type: LoadBalancer
  kubernetes:
    namespace: asset-solutions
    docker:
      repository: <your-registry-url>
      namespace: <your-registry-namespace>
    imagePullSecret: regcred
  infrastructure:
    sizing: medium
```

For the full schema, all configurable sections (networking, kubernetes, transformations, monitoring, authentication, infrastructure), and the `deployment.helmChartMode` and `deployment.argocd` options, refer to [vpctl manifest reference](../../vpctl/manifest).

## 3. Pull the release

Download the release package from the registry. The system reads the version from the manifest automatically:

```sh
vpctl release pull --clean-output
```

The system downloads the release archive and extracts it to `./extracted-release`.

For all flags (including `--version` to override the manifest version), refer to [vpctl release](../../vpctl/commands/release).

## 4. Sync the artifacts

Before deploying, sync the Docker images and the ORAS artifacts from the Unity source registry to your private registry. If you opted in to the `remote` Helm chart mode preview, also sync the published OCI Helm charts.

> **Note:**
>
> If you pull container images directly from the Unity source registry rather than mirroring them to your own private registry, you can skip this step. Mirroring is recommended for air-gapped environments and for full control over image distribution.

### 4.1 Authenticate to both registries

You must authenticate to the source and target registries before syncing:

```sh
docker login uccmpprivatecloud.azurecr.io
docker login <your-registry-url>
```

### 4.2 Run the preflight check

Verify your credentials before running a full sync:

```sh
vpctl artifact sync preflight
```

This command syncs one Docker image, one ORAS artifact, and (if `helmChartMode` is set to `remote`) one Helm chart as a test. If the test fails, it prints troubleshooting hints.

### 4.3 Sync the Docker images

Preview the sync commands first, then run the sync:

```sh
vpctl artifact sync images --dry-run
vpctl artifact sync images
```

### 4.4 Sync the ORAS artifacts

ORAS artifacts include OCI artifacts used by Helm charts. The sync reads authentication from the Docker credential store (`~/.docker/config.json`) automatically.

```sh
vpctl artifact sync oras --dry-run
vpctl artifact sync oras
```

### 4.5 Sync the OCI Helm charts (preview, remote chart mode only)

If your manifest includes the setting `deployment.helmChartMode: remote`, mirror the OCI Helm charts that are published to the Unity registry. If you use the default `local` mode, skip this step, because charts are bundled in the release package.

```sh
vpctl artifact sync charts --dry-run
vpctl artifact sync charts
```

For all flags (including `--skip-existing`, `--cleanup`, `--name`, `--concurrency`), refer to [vpctl artifact](../../vpctl/commands/artifact).

## 5. Generate and deploy the secrets

### Generate the secrets

To generate secrets:

1. Create a secrets import file based on the provided example: `secrets.import.example.yaml`.

This file contains secret values organized by secret name. Enter values in plain text; encoding is handled automatically. The example file enumerates every required secret (UVCS certificate, Elasticsearch, Mini-USF, Novu, MongoDB, PostgreSQL, RabbitMQ, Garage S3 credentials, Garage RPC secret, UVCS license, Valkey).

2. Generate the Kubernetes secret manifests:

   ```sh
   vpctl secret generate --import secrets.import.yaml --use-defaults
   ```

   By default, automatically-generated passwords are alphanumeric only. This limitation is to avoid breaking connection strings.

   > **Note:**
   >
   > With the `--use-defaults` option, the process sets any required field that has neither a default value nor an automatic-generation rule to `TBD` and logs a warning. Before deployment, replace all `TBD` values.

3. Optionally, persist the generated values for reuse on later runs:

   ```sh
   vpctl secret generate --import secrets.import.yaml --use-defaults --persist
   ```

   This command writes the generated values back to `secrets.import.yaml`. Subsequent runs reuse the persisted values, which keeps your deployments consistent across upgrades.

> **Note:**
>
> The custody of secrets is your responsibility. The vpctl tool bootstraps the initial values into Kubernetes secrets, but Unity doesn't store, rotate, or back up your secrets. These files all contain sensitive values: `secrets.import.yaml`, the persisted file written by `--persist`, and the generated `secrets.yaml`. Don't commit these files to Git, but add them to your `.gitignore` file, store them encrypted at rest, and grant access to only the people and systems that need them.
>
> For production environments, we recommend keeping the source of truth for these values in a secret manager that you already operate (HashiCorp Vault, AWS Secrets Manager, Azure Key Vault, GCP Secret Manager, or CyberArk). Feed the values into the `secrets.import.yaml` file from your secret manager at install or upgrade time. This pattern keeps rotation, audit, and access control under your existing security policies.

### Deploy the secrets

Preview the deployment, then deploy the secrets to your cluster:

```sh
vpctl secret deploy --dry-run
vpctl secret deploy
```

For all flags, refer to [vpctl secret](../../vpctl/commands/secret).

## 6. Generate and deploy the charts

Choose your deployment method: **Helm** or **ArgoCD**.

### Option A: Helm deployment

Generate the Helm charts:

```sh
vpctl release generate --clean-output
```

Preview the deployment first:

```sh
vpctl release deploy --dry-run
```

For a first-time deployment, deploy the release in waves, starting with the lowest wave, for example, `-3`. Validate each wave before deploying the next to ensure all dependencies are satisfied.

```sh
vpctl release deploy --wave -3
vpctl release deploy --wave -2
vpctl release deploy --wave -1
vpctl release deploy --wave 0
```

To deploy all charts at once:

```sh
vpctl release deploy
```

#### Verify the deployment

To check the status of the deployments:

```sh
kubectl get pods --all-namespaces --watch
```

Ensure that all pods eventually move to the **Running** state. If a pod isn't running, describe it and check its logs to find the issue.

### Option B: ArgoCD deployment

If the `deployment.argocd` section is set in the manifest, generate the ArgoCD charts:

```sh
vpctl release generate --format argocd --clean-output
```

ArgoCD deploys from a Git repository. Commit the generated charts:

```sh
git add generated-charts/
git commit -m "Add release charts"
git push
```

Preview and run the deployment:

```sh
vpctl release deploy --format argocd --dry-run
vpctl release deploy --format argocd
```

For all `release generate` and `release deploy` flags, refer to [vpctl release](../../vpctl/commands/release).

## 7. Configure the DNS and certificates

Configure DNS records and TLS certificates for your domain to make the solution secure and accessible.

1. Register a fully qualified domain name (FQDN) for the frontend, for example, `example.com`.

2. Point the DNS record to the external IP or hostname of the Traefik load balancer. To find this information, run this command:

   ```sh
   kubectl get svc -n <namespace> traefik
   ```

3. Configure a TLS certificate for the domain. You can use the Traefik ingress annotations in the manifest to reference your certificate, or configure it through your load balancer.

## Troubleshooting

If a step fails, refer to [vpctl troubleshooting](../../vpctl/troubleshooting) for common issues and resolutions.

## Next steps

[Postdeployment](./postdeployment.md)
