> For the complete documentation index, see [llms.txt](https://docs.openg2p.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.openg2p.org/operations/deployment/single-node-automation.md).

# Sandbox — Single-Node

The entire deployment process for a single-node setup has been automated and available as shell scripts. This is useful for bringing up an OpenG2P sandbox on your own machine — everything (K8s, Istio, Rancher, Nginx, per-environment Keycloak, environments) runs on a single VM.

<figure><img src="/files/AVss2p0Bctjrgkul9XCY" alt=""><figcaption><p>Single-node architecture — all services on one VM</p></figcaption></figure>

{% hint style="info" %}
**Flow:** optional [AWS Provisioning](/operations/deployment/single-node-automation/aws-provisioning.md) → **laptop orchestrator** (`openg2p-single-node.sh`) → on-box infra + environment scripts over SSH.
{% endhint %}

{% hint style="info" %}
For adding environments to an existing multi-node infrastructure, see [Environment Setup for Multi-Node](/operations/deployment/infrastructure-setup/environment-setup-multi-node.md).
{% endhint %}

{% hint style="success" %}
**Just want to run it?** Jump to [Quick Start](#quick-start). For the broader deployment model, see [OpenG2P Deployment Architecture](/operations/deployment/openg2p-deployment-model.md#sandbox-single-node).
{% endhint %}

## Overview

Automated single-node deployment of the complete OpenG2P platform — from bare Ubuntu to running modules. Drive everything from your **laptop**; scripts SSH into the VM and run the on-box install there.

| Script                             | Where it runs         | Purpose                                                                                 | Run when                |
| ---------------------------------- | --------------------- | --------------------------------------------------------------------------------------- | ----------------------- |
| `openg2p-single-node.sh`           | **Laptop**            | Orchestrator — stages files, SSHes in, runs infra then environment                      | Once per install        |
| `openg2p-single-node-uninstall.sh` | **Laptop**            | Tear down all infrastructure on the VM (keeps the VM)                                   | When resetting sandbox  |
| `roles/infra/run.sh`               | On the VM             | Base infrastructure (K8s, Istio, Rancher, monitoring, logging via OpenTelemetry + Loki) | Invoked by orchestrator |
| `roles/infra/uninstall.sh`         | On the VM             | On-box infra teardown                                                                   | Invoked by uninstall    |
| `openg2p-environment.sh`           | **Laptop** (SSH → VM) | Environment + modules (namespace, commons, etc.)                                        | Per environment         |
| `openg2p-environment-uninstall.sh` | **Laptop** (SSH → VM) | Remove one environment (keeps infrastructure)                                           | Per environment         |

{% hint style="info" %}
The source code for all automation scripts lives in the [`openg2p-deployment`](https://github.com/OpenG2P/openg2p-deployment) repository under `automation/single-node/`.
{% endhint %}

{% hint style="info" %}
Cluster logging uses **OpenTelemetry + Grafana Loki** (no Fluentd/OpenSearch). It is installed automatically by `roles/infra/run.sh`, collects logs from all pods, and is viewed in Grafana — including a ready-made **OpenG2P — Logs & Health** dashboard. See [System Monitoring](https://github.com/OpenG2P/openg2p-documentation/tree/latest/operations/platform/platform-services/system-monitoring/README.md) for architecture and usage.
{% endhint %}

### Authentication Architecture

There is **no Keycloak at the infrastructure level**. Rancher uses its own **local authentication** — administrators create Rancher users directly in the Rancher UI (see [User Access & Roles](#user-access--roles)).

Keycloak is installed **per environment** for the OpenG2P applications:

| Component            | Deployed by                  | Namespace             | Authentication           | Purpose                                                                                  |
| -------------------- | ---------------------------- | --------------------- | ------------------------ | ---------------------------------------------------------------------------------------- |
| **Rancher**          | `roles/infra/run.sh` Phase 2 | `cattle-system`       | Local users (no SSO)     | Cluster management UI — create users directly in Rancher                                 |
| **Per-env Keycloak** | `openg2p-commons-base` chart | environment namespace | `keycloak.<base_domain>` | Auth for all OpenG2P services (Superset, Kafka UI, MinIO, ODK, etc.) in that environment |

The per-environment Keycloak has its own admin account, database, users, realms, and clients. Its admin credentials are auto-generated by the chart and stored in the `commons-keycloak` K8s secret. It is unrelated to Rancher login.

## Domain & TLS

This is a **local-only sandbox** — no public domain names, DNS provider, or Let's Encrypt are involved. The infrastructure script always:

* Installs `dnsmasq` on the VM to resolve `*.<local_domain>` to the VM's IP (default `openg2p.test`)
* Generates a local Certificate Authority and self-signed certificates
* Configures a Wireguard VPN with split tunnel (only cluster traffic routed through the VPN)
* Pushes the VM as a DNS resolver to Wireguard peers, so they resolve hostnames automatically
* Auto-derives all hostnames:
  * Infra: `rancher.openg2p.test`
  * Per-env: `keycloak.<env>.openg2p.test`, `superset.<env>.openg2p.test`, etc.

You only set `local_domain` (optional — defaults to `openg2p.test`).

## Access Model — Private by Default

The sandbox is **not exposed to the public Internet by default, even if the VM has a public IP.** The host firewall (and the AWS security group) restrict the web ports (80/443) so they are reachable only:

* over **Wireguard** (the recommended path — DNS resolves automatically), or
* from **inside the VPC**.

Administrative/data-plane ports (Kubernetes API, NodePorts, etcd, NFS) are always VPC/Wireguard-only, so `kubectl`/`helm` access requires the VPN.

{% hint style="danger" %}
**Opening the sandbox to the public Internet (`public_access: true`)** exposes the Rancher cluster-admin UI and every environment service to anyone who can reach the public IP, protected only by a self-signed certificate and local passwords. This is a sandbox, not a hardened deployment. Only enable it if you understand and accept the risk — and prefer restricting the source IPs (ufw / security group) to the specific addresses that need access. See [Optional: Public Access](#optional-public-direct-access-without-wireguard).
{% endhint %}

## Prerequisites

| Requirement  | Needed                                                                                                                                               |
| ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Laptop**   | bash 4+, SSH client, rsync, AWS CLI (if using AWS provisioning). Works on **WSL2** and **Git Bash** (SSH multiplexing is auto-disabled on Git Bash). |
| **VM**       | Ubuntu 24.04 LTS, 16 vCPU, 64 GB RAM, 128 GB SSD, passwordless sudo                                                                                  |
| **Access**   | SSH from laptop to the VM (`ubuntu@` + `.pem`)                                                                                                       |
| **Internet** | Required on the VM for packages and Helm charts                                                                                                      |
| **DNS**      | Not needed — dnsmasq + your laptop handle it                                                                                                         |
| **TLS**      | Not needed — local CA handles it                                                                                                                     |
| **VPN**      | Wireguard client on your laptop (default access path after install)                                                                                  |

{% hint style="info" %}
**Don't have a VM yet?** Use optional [AWS Provisioning](/operations/deployment/single-node-automation/aws-provisioning.md) from your laptop first — it creates one `m5a.4xlarge` EC2 instance, security group, and Elastic IP, then writes `provision-output.yaml`. Continue with Quick Start below (still on the laptop).
{% endhint %}

## Quick Start

### Step 0 (optional): AWS Provisioning

From your **laptop**:

```bash
cd automation/single-node/aws
cp aws-config.example.yaml aws-config.yaml
# Edit: project, region (leave vpc_id / subnet_id blank to pick interactively)
./openg2p-aws-provision.sh --config aws-config.yaml
```

See [AWS Provisioning](/operations/deployment/single-node-automation/aws-provisioning.md) for IAM, sizing, teardown, and costs. Skip this step if you already have an Ubuntu 24.04 VM (set `node_ip`, `ssh_host`, `ssh_user`, `ssh_key` in `single-node-config.yaml` yourself).

### Step 1: Configure and probe (laptop)

```bash
cd automation/single-node
cp single-node-config.example.yaml single-node-config.yaml
cp env-config.example.yaml   env-config.yaml
# With AWS: node_ip / wireguard.endpoint / ssh_* come from provision-output.yaml
# Without AWS: set node_ip, ssh_host, ssh_user, ssh_key in single-node-config.yaml
# Optional: install_environment: false  — infra only; run --stage environment later

./openg2p-single-node.sh --config single-node-config.yaml --probe
```

{% tabs %}
{% tab title="Minimal (manual VM)" %}
Fill SSH + node fields when you are not using the AWS provisioner:

```yaml
node_ip: "172.16.0.10"
cluster_name: "openg2p"
node_name: "node1"
local_domain: "openg2p.test"
public_access: false
install_environment: true     # false = stop after infra
ssh_host: "54.x.x.x"          # reachable from your laptop
ssh_user: "ubuntu"
ssh_key:  "~/.ssh/my-vm.pem"
wireguard:
  endpoint: "54.x.x.x"        # often same as ssh_host
```

{% endtab %}

{% tab title="AWS EC2" %}
{% hint style="success" %}
**Recommended instance type: `m5a.4xlarge`** — 16 vCPU / 64 GB RAM. The [AWS provisioner](/operations/deployment/single-node-automation/aws-provisioning.md) defaults to this size with a 128 GB gp3 root volume.
{% endhint %}

When `provision-output.yaml` sits next to `single-node-config.yaml`, leave the `[AWS]` fields blank — the orchestrator loads the overlay automatically (`node_ip`, `wireguard.endpoint`, `ssh_host`, `ssh_user`, `ssh_key`).
{% endtab %}
{% endtabs %}

### Step 2: Install (laptop orchestrator)

```bash
./openg2p-single-node.sh --config single-node-config.yaml
```

This SSHes into the VM, stages `automation/single-node/` under `/tmp/openg2p-deploy/`, and runs `roles/infra/run.sh` then (when `install_environment: true`) `openg2p-environment.sh` under sudo. Artifacts (`peer1.conf`, CA cert, kubeconfig) are pulled back to `./artifacts/`. A summary is written to `setup-output/SETUP-SUMMARY.txt` — it states clearly whether the environment was installed and lists service URLs when it was.

Takes \~30–45 minutes total. Idempotent — re-run on failure.

Useful flags:

```bash
./openg2p-single-node.sh --config single-node-config.yaml --stage infra          # infra only
./openg2p-single-node.sh --config single-node-config.yaml --stage environment    # env only
./openg2p-single-node.sh --config single-node-config.yaml --skip-environment    # one-shot skip env
# Or set install_environment: false in single-node-config.yaml to skip env by default
./openg2p-single-node.sh --config single-node-config.yaml --force
```

{% hint style="info" %}
**Environment from the laptop.** After infra is up you can also run: `./openg2p-environment.sh --config env-config.yaml` (no sudo) — it SSHes into the VM and runs the on-box install there. Same for a full install via `./openg2p-single-node.sh --stage environment`.

**Advanced — run fully on-box.** SSH into the VM, `cd` to the staged tree (`/tmp/openg2p-deploy/` or a clone of `automation/single-node/`), then `sudo bash roles/infra/run.sh …` / `sudo ./openg2p-environment.sh …`.
{% endhint %}

### Step 3: Environment notes

`env-config.yaml` is auto-detected next to `single-node-config.yaml`. Minimal content:

```yaml
environment: "dev"
single_node_config: "single-node-config.yaml"
modules:
  commons: true
```

Run additional environments later with:

```bash
# Edit env-config.yaml (or pass --env-config env-qa.yaml)
./openg2p-environment.sh --config env-config.yaml
# or:
./openg2p-single-node.sh --config single-node-config.yaml --stage environment
```

Takes \~15-20 minutes per environment. The orchestrator refreshes `setup-output/SETUP-SUMMARY.txt` with the environment URLs when the env stage runs.

To remove one environment (keeps infrastructure):

```bash
./openg2p-environment-uninstall.sh --config env-config.yaml
```

## Post-Infrastructure Steps (on your laptop)

After the orchestrator completes, follow these steps to access the cluster. If you used `openg2p-single-node.sh`, artifacts are already under `./artifacts/` and `setup-output/SETUP-SUMMARY.txt` tells you whether the environment was installed (and its URLs) or how to install it next.

### 1. Wireguard VPN

```bash
# Prefer the file pulled by the orchestrator:
ls artifacts/peer1.conf

# Or pull manually from the VM:
scp -i <your-key.pem> ubuntu@<public-ip>:/tmp/peer1.conf .
# (on the VM first: sudo cp /etc/wireguard/peers/peer1/peer1.conf /tmp/ && sudo chmod 644 /tmp/peer1.conf)
```

Import `peer1.conf` into the [Wireguard client app](https://www.wireguard.com/install/) and activate the tunnel.

{% hint style="info" %}
The default is **split tunnel** — only Wireguard subnet + VPC traffic routes through the VPN. Your internet stays direct and fast.
{% endhint %}

### 2. DNS Resolution (split tunnel only)

{% tabs %}
{% tab title="macOS" %}

```bash
sudo mkdir -p /etc/resolver
echo "nameserver <node_ip>" | sudo tee /etc/resolver/<local_domain>
# e.g.: echo "nameserver 172.29.8.137" | sudo tee /etc/resolver/openg2p.test
```

> **Note:** `dig` bypasses the macOS resolver system. Use `dscacheutil -q host -a name rancher.openg2p.test` or `ping` to verify.
> {% endtab %}

{% tab title="Windows" %}
Run in PowerShell as Administrator:

```powershell
Add-DnsClientNrptRule -Namespace ".<local_domain>" -NameServers "<node_ip>"
# e.g.: Add-DnsClientNrptRule -Namespace ".openg2p.test" -NameServers "172.29.8.137"
```

{% endtab %}

{% tab title="Linux" %}

```bash
sudo resolvectl dns wg0 <node_ip>
sudo resolvectl domain wg0 '~<local_domain>'
```

{% endtab %}
{% endtabs %}

### 3. CA Certificate

Copy `/etc/openg2p/ca/ca.crt` from the VM to your laptop, then install:

{% tabs %}
{% tab title="macOS" %}

```bash
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain ca.crt
```

Or double-click `ca.crt` → System Settings → General → Profiles.
{% endtab %}

{% tab title="Windows" %}
Double-click `ca.crt` → Install Certificate → Local Machine → "Trusted Root Certification Authorities"
{% endtab %}

{% tab title="Linux" %}

```bash
sudo cp ca.crt /usr/local/share/ca-certificates/openg2p-ca.crt
sudo update-ca-certificates
```

{% endtab %}
{% endtabs %}

### 4. kubectl / helm Access

```bash
# On the VM:
sudo cp /etc/rancher/rke2/rke2-remote.yaml /tmp/
sudo chmod 644 /tmp/rke2-remote.yaml

# On your laptop:
scp -i <your-key.pem> <user>@<public-ip>:/tmp/rke2-remote.yaml ~/.kube/openg2p-config
export KUBECONFIG=~/.kube/openg2p-config
kubectl get nodes
```

{% hint style="warning" %}
Requires Wireguard VPN to be active — the K8s API is on the private IP.
{% endhint %}

### 5. Login to Rancher

Rancher uses **local authentication** — there is no Keycloak SSO for Rancher.

Open Rancher at `https://rancher.<domain>` and log in as the local admin:

* **Username:** `admin`
* **Password:** retrieve it from the cluster:

```bash
sudo KUBECONFIG=/etc/rancher/rke2/rke2.yaml kubectl -n cattle-system \
  get secret rancher-secret -o jsonpath='{.data.adminPassword}' | base64 -d && echo
```

{% hint style="info" %}
**Additional Rancher users must be created directly in Rancher.** There is no external identity provider — see [User Access & Roles](#user-access--roles) below.
{% endhint %}

## Optional: Public (Direct) Access Without Wireguard

By default the sandbox is reachable only over Wireguard or from inside the VPC. If you want to reach it **directly over a public IP — without the VPN** — you can opt in. The client just needs to map the hostnames to the public IP and accept the self-signed certificate.

{% hint style="danger" %}
**This exposes the Rancher cluster-admin UI and every environment service to the public Internet**, protected only by a self-signed certificate and local passwords. This is a sandbox, not a hardened deployment. Prefer restricting the opened ports to the specific source IPs that need access (see step 1/2 notes), and never enable this for a deployment holding real data.
{% endhint %}

**On the server — open the web ports:**

1. Set `public_access: true` in `single-node-config.yaml` and re-run phase 1 (this rewrites the firewall; it is the durable way — a manually-added `ufw` rule would be wiped on the next run):

   ```bash
   # From your laptop (recommended):
   ./openg2p-single-node.sh --config single-node-config.yaml --stage infra --phase 1 --force

   # Or on the VM, from automation/single-node/ (or /tmp/openg2p-deploy/):
   sudo bash roles/infra/run.sh --config single-node-config.yaml --phase 1
   ```
2. **On AWS, also open 80/443 in the security group.** Re-run the provisioner with `public_web: true` in `aws-config.yaml` (adds the missing rules), or use `./create-security-group.sh --vpc-id <VPC_ID> --public-web`, or add rules manually (ideally scoped to your client's IP rather than `0.0.0.0/0`):

   ```bash
   aws ec2 authorize-security-group-ingress --group-id sg-xxx \
     --protocol tcp --port 443 --cidr <your-client-ip>/32
   aws ec2 authorize-security-group-ingress --group-id sg-xxx \
     --protocol tcp --port 80  --cidr <your-client-ip>/32
   ```

**On the client laptop — resolve the hostnames + trust the CA:**

3. Add `/etc/hosts` entries pointing each hostname at the **public** IP (one line per environment hostname — wildcards are not supported in `/etc/hosts`):

   ```
   <public-ip>  rancher.openg2p.test
   <public-ip>  keycloak.dev.openg2p.test  superset.dev.openg2p.test
   ```
4. Install/trust the CA certificate (`/etc/openg2p/ca/ca.crt`, see step 3 above) or click through the browser warning. Always browse by **hostname** — the cert has no IP SAN, so `https://<public-ip>` will fail validation.

No other changes are required: Nginx already listens on all interfaces and routes by hostname, so once the firewall/security-group allow the traffic and the client resolves the names, access works exactly as it does over the VPN.

## User Access & Roles

Rancher uses **local authentication** — all users that need access to the Rancher UI must be **created directly in Rancher**. There is no Keycloak/SSO integration for Rancher.

**To create a Rancher user:**

1. Log in to Rancher as the local `admin`.
2. Go to **☰ → Users & Authentication → Users → Create**.
3. Set a username and password, and assign a global role (e.g. *Standard User*, or *Administrator* for a super admin).

Rancher ships with built-in project roles, but all include full Secrets access. The automation script creates two additional custom roles that exclude secrets:

| Role                               | Source                | Secrets Access | Permissions                                   |
| ---------------------------------- | --------------------- | -------------- | --------------------------------------------- |
| **Project Owner**                  | Rancher built-in      | Full           | Full control of the project                   |
| **Project Member**                 | Rancher built-in      | Full           | CRUD on workloads, services, configs, secrets |
| **Project Member (No Secrets)**    | Created by automation | None           | Same as Project Member, minus secrets         |
| **Project Read-Only (No Secrets)** | Created by automation | None           | View-only, no secrets                         |

**To give a user access to an environment:**

1. Create the user in **Rancher** (☰ → Users & Authentication → Users → Create), if not already created.
2. In **Rancher**, go to Project (environment) → Members → Add Member.
3. Search for the user and assign a role.

{% hint style="info" %}
The Rancher `admin` global role (super admin) has access to everything. The initial admin user configured during setup already has this role.
{% endhint %}

## Environment Setup Details

### Phase 1: Environment Infrastructure

| Step | What                   | Details                                                    |
| ---- | ---------------------- | ---------------------------------------------------------- |
| E1.1 | Validate prerequisites | Infra completed, kubeconfig works, base domain available   |
| E1.2 | TLS certificate        | Wildcard cert for `*.<base_domain>` signed by the local CA |
| E1.3 | Nginx server block     | `*.dev.openg2p.test` → Istio ingress                       |
| E1.4 | K8s namespace          | Creates the namespace                                      |
| E1.5 | Rancher Project        | Creates project and moves namespace into it (RBAC)         |
| E1.6 | Istio Gateway          | Gateway resource for hostname routing                      |

### Phase 2: Module Installation

openg2p-commons is split into two Helm charts installed sequentially:

| Step       | Chart                            | Details                                                                       |
| ---------- | -------------------------------- | ----------------------------------------------------------------------------- |
| E2.1       | **openg2p-commons-base**         | PostgreSQL, Kafka, MinIO, Redis, SoftHSM, **per-env Keycloak**, keycloak-init |
| E2.2       | **openg2p-commons-services**     | eSignet, KeyManager, Superset, ODK, master-data, reporting                    |
| *(future)* | Registry, PBMS, SPAR, G2P Bridge | Will be added as separate Helm installs                                       |

{% hint style="info" %}
The services chart automatically connects to base infrastructure via release name references (`commons-postgresql`, `commons-redis`, etc.).
{% endhint %}

## Command Reference

### Laptop orchestrator (recommended)

```bash
./openg2p-single-node.sh --config single-node-config.yaml --probe
./openg2p-single-node.sh --config single-node-config.yaml                    # infra + env (if install_environment: true)
./openg2p-single-node.sh --config single-node-config.yaml --stage infra
./openg2p-single-node.sh --config single-node-config.yaml --stage environment
./openg2p-single-node.sh --config single-node-config.yaml --skip-environment # one-shot: infra only
./openg2p-single-node.sh --config single-node-config.yaml --phase 1          # pass --phase to on-box script
./openg2p-single-node.sh --config single-node-config.yaml --force
./openg2p-single-node.sh --config single-node-config.yaml --dry-run
./openg2p-single-node.sh --reset-laptop                                # clear ./.state markers

./openg2p-single-node-uninstall.sh --config single-node-config.yaml    # tear down infra (keeps VM)
./openg2p-single-node-uninstall.sh --config single-node-config.yaml -y # skip typed confirmation
```

After a successful run, open `setup-output/SETUP-SUMMARY.txt`. If the environment was installed it lists service URLs and says you do not need to run the env stage again; if it was skipped it tells you how to install it next.

### On-box infrastructure (advanced / direct SSH)

Run these from the single-node directory on the VM (`automation/single-node/` or `/tmp/openg2p-deploy/` after staging):

```bash
sudo bash roles/infra/run.sh --config single-node-config.yaml              # Full setup
sudo bash roles/infra/run.sh --config single-node-config.yaml --phase 1    # Host setup only
sudo bash roles/infra/run.sh --config single-node-config.yaml --phase 2    # Helmfile only
sudo bash roles/infra/run.sh --config single-node-config.yaml --phase 3    # Rancher config only
sudo bash roles/infra/run.sh --config single-node-config.yaml --force
sudo bash roles/infra/run.sh --config single-node-config.yaml --dry-run
sudo bash roles/infra/run.sh --reset                                   # Clear on-box state markers
```

### Environment from laptop (recommended)

```bash
./openg2p-environment.sh --config env-config.yaml              # SSH → on-box install
./openg2p-single-node.sh --config single-node-config.yaml --stage environment

./openg2p-environment-uninstall.sh --config env-config.yaml    # remove one environment
./openg2p-environment-uninstall.sh --config env-config.yaml -y # skip typed confirmation
```

### On-box environment (advanced / direct SSH)

Same working directory as above (`automation/single-node/` or `/tmp/openg2p-deploy/`):

```bash
sudo ./openg2p-environment.sh --config env-config.yaml
sudo ./openg2p-environment.sh --config env-config.yaml --phase 1
sudo ./openg2p-environment.sh --config env-config.yaml --phase 2
sudo ./openg2p-environment.sh --config env-config.yaml --force
```

### Uninstalling

**Remove a single environment** (keeps infrastructure intact) — from your **laptop**:

```bash
./openg2p-environment-uninstall.sh --config env-config.yaml
```

Advanced — on the VM: `sudo ./openg2p-environment-uninstall.sh --config env-config.yaml`

**Remove the entire infrastructure** (keeps the VM) — from your **laptop** (recommended):

```bash
./openg2p-single-node-uninstall.sh --config single-node-config.yaml
```

Type the `cluster_name` to confirm. This SSHes in, runs `roles/infra/uninstall.sh` on the VM, and clears laptop `.state/` + `./artifacts/`.

Advanced — on the VM directly (from `automation/single-node/` or `/tmp/openg2p-deploy/`):

```bash
sudo bash roles/infra/uninstall.sh
```

{% hint style="danger" %}
Infrastructure uninstall is irreversible. Removes: RKE2 cluster, all environments, Wireguard VPN, dnsmasq, Nginx, NFS exports, TLS certificates, and all state. The VM is left clean for a fresh installation. AWS resources are separate — use `aws/openg2p-aws-destroy.sh` to tear down the EC2 instance.
{% endhint %}

## File Structure

```
automation/single-node/
├── openg2p-single-node.sh            # Laptop orchestrator (SSH → on-box scripts)
├── openg2p-single-node-uninstall.sh  # Laptop: tear down infra (keeps VM)
├── single-node-config.example.yaml   # Main config (SSH keys, install_environment, …)
├── provision-output.yaml             # AWS-derived overlay (from aws/ provisioner)
├── helmfile-infra.yaml.gotmpl        # Helmfile for platform components
├── openg2p-environment.sh            # Laptop (SSH → VM) or on-box: environment setup
├── openg2p-environment-uninstall.sh  # Laptop (SSH → VM) or on-box: remove one environment
├── env-config.example.yaml           # Config for environment
├── roles/
│   └── infra/
│       ├── run.sh                    # On-box: base infrastructure
│       └── uninstall.sh              # On-box uninstall: tears down entire infra
├── lib/
│   ├── ssh-utils.sh      # Laptop: SSH (ControlMaster on WSL/Linux; plain SSH on Git Bash), stage, push/pull
│   ├── utils.sh          # On-box: logging, state, config, wait helpers
│   ├── phase1.sh         # Infra Phase 1: tools, firewall, RKE2, Wireguard, NFS, DNS, TLS, Nginx
│   ├── phase2.sh         # Infra Phase 2: Istio, Helmfile sync
│   ├── phase3.sh         # Infra Phase 3: Rancher config
│   ├── env-phase1.sh     # Env Phase 1: certs, Nginx, namespace, Rancher project, Istio GW
│   └── env-phase2.sh     # Env Phase 2: commons helm install
├── aws/                              # Laptop-side AWS provisioning (optional)
│   ├── openg2p-aws-provision.sh      # Creates 1× EC2 (m5a.4xlarge) + SG + EIP
│   ├── openg2p-aws-destroy.sh        # Tears down ManagedBy=openg2p-aws-single-node
│   ├── aws-config.example.yaml
│   ├── create-security-group.sh      # Standalone SG helper
│   └── lib/aws-utils.sh
├── artifacts/                        # Pulled peer1.conf, CA, kubeconfig
├── setup-output/                     # SETUP-SUMMARY.txt (infra + optional env)
├── .state/                           # Laptop orchestrator markers
└── charts/
    ├── raw/
    └── istio-install/
```

## Troubleshooting

{% hint style="info" %}
**Script failed?** Re-run it. Completed steps are skipped. Error messages include diagnostic commands.
{% endhint %}

**`Kubeconfig not found` / `must be run as root` on your laptop?** You ran an on-box path without SSH. From the laptop use (no sudo): `./openg2p-environment.sh --config env-config.yaml` or `./openg2p-environment-uninstall.sh --config env-config.yaml` — they SSH into the VM. Infra install/uninstall: `./openg2p-single-node.sh` / `./openg2p-single-node-uninstall.sh`.

**Git Bash SSH / `ControlMaster` / `mux_client` errors?** Supported on Git Bash and WSL2. Multiplexing is auto-disabled on Git Bash. If you still see mux errors, clear stale sockets and retry: `rm -rf ~/.ssh/openg2p-single-node-ctrl`. Prefer WSL2 if issues persist. Force plain SSH anytime with `OPENG2P_SSH_NO_MUX=1`.

**Local DNS not resolving on your laptop?** Ensure Wireguard VPN is connected. Configure per-domain DNS on your laptop (see Step 2 above). On macOS, `dig` bypasses the resolver system — use `ping` or `dscacheutil` to test.

**Browser shows certificate warning?** The sandbox uses a self-signed CA — install the CA certificate on your laptop (see Step 3 above) to clear it.

**Check cluster status:**

```bash
kubectl get nodes                              # Node health
kubectl get pods -A | grep -v Running          # Problem pods
helm list -A                                    # Helm releases
journalctl -u rke2-server -n 50               # RKE2 logs
```

{% hint style="info" %}
This automation does not replace the Rancher UI. Your existing umbrella Helm charts with `questions.yml` continue to work for manual installs via the Rancher App Catalog.

Infra Phase 3 pre-registers the **OpenG2P Helm repository** (`https://openg2p.github.io/openg2p-helm/rancher`) as a Rancher catalog ClusterRepo named `openg2p`, so the OpenG2P charts are available out of the box under **Rancher UI → Apps → Repositories / Charts**.
{% endhint %}

## Related documentation

* [AWS Provisioning](/operations/deployment/single-node-automation/aws-provisioning.md) — optional EC2 provisioner (`m5a.4xlarge`)
* [OpenG2P Deployment Architecture](/operations/deployment/openg2p-deployment-model.md) — deployment model overview


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.openg2p.org/operations/deployment/single-node-automation.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
