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

# Install an Outpost

> Add a Genesis Outpost, install it on a laptop, VM, Docker or Kubernetes, and confirm it connects.

The guided setup on **Config -> Outposts** gives you only the commands for the place you
choose, with your Genesis endpoint and the Outpost's settings already filled in. This page
explains each step so you know what you are running and why.

<Note>
  The Snowflake Native App supports Outposts from release 1.19.97, which exposes the
  `outposttunnel` endpoint the Outpost dials. An older Native App does not, so its Outposts page
  shows them as unavailable and they cannot be switched on until the app is upgraded. Outposts
  are also available when Genesis runs in Docker, Kubernetes or as a Databricks App.
</Note>

<Note>
  Setting up an Outpost needs a Genesis administrator. For Snowflake deployments you also need
  someone who can create users and roles in the Snowflake account (for example
  `ACCOUNTADMIN`).
</Note>

## Before you start

* **Outbound HTTPS.** The machine that runs the Outpost must be able to open outbound HTTPS
  (port 443) to the Genesis tunnel endpoint shown in the setup. For Snowflake it also signs
  in at `https://<orgname>-<account_name>.snowflakecomputing.com`. An outbound proxy is
  supported through `HTTPS_PROXY` and `NO_PROXY`.
* **Network reach.** From that machine, the systems you want Genesis to use (for example
  `db.corp.internal:5432`) must resolve and accept connections.
* **Resources.** The Outpost is a single binary of about 13 MB and needs around 64 MB of
  memory and a fraction of a CPU.

## Turn on Outposts

Outposts are off until an administrator turns them on. Open **Config -> Outposts** and switch
**Outposts** on. While they are off, nothing is routed through any Outpost.

## Add and install an Outpost

<Steps>
  <Step title="Name your Outpost">
    Click **Add Outpost** and give it a name such as `acme-prod`: lowercase letters, digits
    and `-`. The name cannot be changed later.

    You choose which systems use the Outpost on each connection, so nothing else is needed
    here. Under **Advanced: route a whole domain** you can optionally send every connection
    to matching hosts through this Outpost; see
    [Route a whole domain](/docs/Setup/Outposts-Connect-Systems#route-a-whole-domain).
  </Step>

  <Step title="Choose where it will run">
    | Option | Use it for |
    | - | - |
    | **Your laptop** | Trying Outposts out, for example on the corporate VPN. Evaluation only: it runs in your terminal, as you, and stops when you close it. |
    | **A cloud or on-prem VM** | EC2, Azure VM, GCE or a data-center server running Linux (systemd service) or Windows (scheduled task at boot). |
    | **Docker** | Any host that runs containers. |
    | **Kubernetes** | EKS, AKS, GKE, OpenShift or on-prem clusters. |

    For a laptop or VM, pick the operating system and processor. For Kubernetes, pick the
    namespace (default `genesis-outpost`).

    For a VM, Docker or Kubernetes you can fill in **Systems Genesis may reach through it**:
    a comma-separated list of `host:port` entries such as
    `db.corp.internal:5432, jira.corp.internal:443`. It becomes the Outpost's
    `ALLOWED_DESTINATIONS`; see [Allowed destinations](#allowed-destinations). You can also
    leave it empty and fill it in on the host.

    For VM, Docker or Kubernetes, you can also enable **Read connection secrets from your
    own store**; it is off by default and is not offered for laptop evaluation. Choose AWS
    Secrets Manager, Azure Key Vault or Google Secret Manager and set the secret-name prefix
    (default `genesis/`). AWS is selected by default; Azure can use the generated Key Vault URL
    placeholder or a URL you provide, while the Google Cloud project is optional. The wizard
    generates the Outpost settings for that store; give its cloud identity read access as
    described in [Keep credentials in your own secret store](#keep-credentials-in-your-own-secret-store).
  </Step>

  <Step title="Set up how it signs in to Genesis">
    The setup shows the identity steps for where your Genesis runs. See
    [How the Outpost signs in](#how-the-outpost-signs-in).
  </Step>

  <Step title="Install it">
    Run the install commands shown, in order. Replace any `<placeholder>` first. Then click
    **I've installed it**. See [What the install does](#what-the-install-does).
  </Step>

  <Step title="Wait for it to connect">
    Genesis checks every few seconds for up to 10 minutes. When the Outpost connects, the
    setup shows its reported release version (when available), capabilities and the number of
    destination routes it holds. Older releases may not report a version. This count excludes
    the Outpost's own tunnel control channel; zero means no connection is using the Outpost
    yet. If it does not connect, the setup shows why; see
    [Troubleshooting](/docs/Setup/Outposts-Troubleshooting).
  </Step>

  <Step title="Try it">
    Enter a host and port inside your network and click **Test route**. The Outpost resolves
    the name and opens a TCP connection from inside your network, and Genesis shows the
    result. Then click **Create a connection** to open the provider picker. When you select a
    provider with a host field, the new connection form starts with this Outpost selected;
    providers without a host field connect directly. If you started from the connection form,
    click **Use this Outpost** instead.
  </Step>
</Steps>

To reinstall or move an existing Outpost, click **Install** on its card on the Outposts page.
The setup starts at **Where will it run?**.

## How the Outpost signs in

Each Outpost has its own identity. Which one it uses depends on where Genesis runs.
The tunnel endpoint requires an Outpost release that offers the `genesis-outpost.v1` protocol
(0.7.0 or later); older releases receive HTTP 400 and cannot connect.

<Tabs>
  <Tab title="Snowflake Native App">
    <Note>
      Needs Genesis Native App release 1.19.97 or later. The Outpost dials the app's
      `outposttunnel` endpoint; the setup fills in `GENESIS_ENDPOINT` with its ingress URL
      (`https://<id>-<account>.snowflakecomputing.app`), looked up in Snowflake. Snowflake's
      ingress signs the Outpost's service user in before the connection reaches Genesis.
    </Note>

    The Outpost signs in as a dedicated Snowflake **service user** with a **key pair**. The
    setup generates the SQL for you. It:

    1. Creates a role that holds only the Genesis application role `APP_OUTPOST_TUNNEL`,
       which allows nothing but connecting to the Outpost tunnel endpoint.
    2. Creates the service user (for Outpost `acme-prod`, `GENESIS_OUTPOST_ACME_PROD`) with
       no password.
    3. Creates a network policy that pins the user to your Outpost's egress IP address.
    4. Registers the Outpost's public key on the user.

    ```sql theme={null}
    ALTER USER GENESIS_OUTPOST_ACME_PROD SET RSA_PUBLIC_KEY = '<public key>';
    ```

    Where the key pair is made depends on the target:

    * **VM (Linux), Docker, Kubernetes:** the setup's first step generates the key pair with
      `openssl` on the machine that will run the Outpost, and the SQL registers it in the
      same run. On Kubernetes the private key goes into a Kubernetes Secret.
    * **Laptop:** `outpost init` generates the key and prints the `ALTER USER` statement with
      the key filled in. Run it as printed.
    * **Windows VM:** `outpost keygen` generates the key after the download and prints the
      statement.

    <Tip>
      Keep the network-policy step for production: a stolen key is then useless from any other
      address. For a laptop trial whose IP address changes, you can leave out the two
      network-policy statements.
    </Tip>

    <Warning>
      The private key never leaves your network. Keep it in a secret store or a Kubernetes
      Secret, never in an environment variable, a container image or shell history, and never
      paste it into Genesis or a chat.
    </Warning>

    Behind the Snowflake ingress the Outpost also signs in inside the tunnel with its **own
    tunnel key**: in the setup's sign-in step choose **New tunnel key**
    (or, for an existing Outpost, **Install** on its card, then **New tunnel key**). Genesis
    shows the key once; give it to the Outpost as `OUTPOST_TUNNEL_KEY` and keep it in a
    secret store. The ingress admits any Snowflake user granted `APP_OUTPOST_TUNNEL`; behind
    it the key signs in only this Outpost and opens only this Outpost's own addresses.
  </Tab>

  <Tab title="Databricks App">
    The Outpost signs in as its **own Databricks service principal**:

    1. In the workspace admin settings, add a service principal, for example
       `genesis-outpost-acme-prod`.
    2. Create an OAuth secret for it and note the client ID and secret.
    3. In the Genesis App's **Permissions**, give that service principal **CAN USE**, and
       nothing else.
    4. Issue the Outpost's own tunnel key: in the setup's sign-in step choose **New tunnel
       key** (or **Install** on its card, then **New tunnel key**). Genesis shows it once;
       it is the Outpost's `OUTPOST_TUNNEL_KEY`.

    The Outpost mints a fresh short-lived token before every connection, so no long-lived
    token sits on the host.

    Genesis serves the tunnel itself at `/outpost-tunnel` on the App's own URL. Behind the
    App's sign-in, the Outpost signs in inside the tunnel with its tunnel key before anything
    else happens. Every Genesis Databricks App from version 1.19.97 runs the tunnel; an older
    App answers `/outpost-tunnel` with HTTP 503 until it is upgraded. That App package also includes the
    Outpost host-name resolver: when `/etc/hosts` is read-only, its launcher preloads
    `nss_wrapper` so Genesis can map routed host names to their tunnel listeners. See
    [Databricks App Outpost routing](/docs/deployments/Databricks/Genesis-On-Databricks#genesis-as-a-databricks-app)
    for package behavior and troubleshooting.
  </Tab>

  <Tab title="Self-hosted Genesis">
    When Genesis runs in your own environment (Kubernetes, a VM, Docker), it runs the tunnel
    itself and serves it at `/outpost-tunnel` on its own address, so the Outpost
    reaches it through the same HTTPS ingress as the UI. Nothing else runs beside Genesis.

    The Outpost signs in with its **own tunnel key**:

    1. In the setup's sign-in step choose **New tunnel key** (or **Install** on the
       Outpost's card, then **New tunnel key**). Genesis shows the key once.
    2. The Outpost sets `OUTPOST_TUNNEL_AUTH` to the value shown, `outpost-<slot>:<key>`.
       Keep it in a secret store.

    The setup fills in `GENESIS_ENDPOINT` as the address you opened it at, followed by
    `/outpost-tunnel`. Set `outpost.tunnel_endpoint_url` only if the Outpost must dial a
    different address.

    <Note>
      If an authenticating proxy (for example oauth2-proxy) fronts Genesis, exempt
      `/outpost-tunnel` from its login, as you do for health checks: the tunnel key
      authenticates it. With the Genesis Helm chart, add `/outpost-tunnel` to
      `ingress.authExemptHealth.paths`. The path must also pass WebSocket upgrades unchanged,
      including the `Sec-WebSocket-Protocol` header, which ingress-nginx and AWS load balancers
      do by default, and keep an idle WebSocket open longer than 20 seconds.
    </Note>
  </Tab>
</Tabs>

### Each Outpost's tunnel key

Every Outpost has a tunnel key of its own (Outpost 0.7.0 or later). It signs in only that
Outpost, opens only that Outpost's own addresses inside Genesis, and proves each of its
answers to Genesis with the key, so Genesis knows which Outpost answered. The sign-in is a
challenge-response in both directions: the key never crosses the network, and the Outpost
checks that the endpoint holds the same key before it carries anything. Genesis keeps the
key in its secret store and shows it once, when it is issued; issuing a new one replaces it
at once. That Outpost is refused until it restarts with the new key. The other Outposts keep
their keys and stay connected.

<Note>
  An Outpost signs in only with its own key, on every deployment model: there is no shared
  key and no sign-in without a key. Outpost 0.7.0 or later is required, and it refuses to
  start without its own tunnel key. An Outpost before 0.7.0 cannot connect to Genesis's tunnel;
  upgrade it. Until its key is issued an Outpost cannot connect, and the Outposts page says so
  on its card; issue the key (**Install**, then **New tunnel key**), set it on the Outpost,
  and start it on Outpost 0.7.0 or later.
</Note>

## What the install does

Every install downloads the same Outpost from the public release page,
[github.com/genesis-computing-ai/genesis-outpost/releases](https://github.com/genesis-computing-ai/genesis-outpost/releases),
or runs the container image `ghcr.io/genesis-computing-ai/genesis-outpost` built from it. The
current install is Outpost 0.7.0, which uses only the native `genesis-outpost.v1` tunnel
protocol; it does not use Chisel. Binaries are published for Linux, macOS and Windows on x64
and ARM, with a `SHA256SUMS` file beside them. The install commands check the download against
`SHA256SUMS` before installing it.

<AccordionGroup>
  <Accordion title="Laptop (evaluation)">
    1. Download the binary for your machine and check it against `SHA256SUMS`.
    2. Run `./outpost init` (Windows: `.\outpost.exe init`). It asks for the tunnel endpoint
       URL and slot, how the Outpost signs in, and which `host:port` destinations Genesis may
       reach through your machine. The setup page lists the answers to give. It writes
       `outpost.env` in your user config directory, readable by you only.
    3. For Snowflake, run the `ALTER USER` statement `outpost init` printed.
    4. Run `./outpost run`. It prints an evaluation-mode banner naming what it exposes, then
       every request Genesis makes. Stop it with Ctrl-C.

    Nothing is installed as a service and nothing starts on login. Evaluation mode enforces
    the same security checks as production.

    <Note>
      The binaries are not yet code-signed. On macOS the install command removes the download
      quarantine flag after the checksum passes (or allow it under **System Settings -> Privacy
      & Security**). On Windows, if SmartScreen warns, choose **More info**, then **Run anyway**.
    </Note>
  </Accordion>

  <Accordion title="VM: Linux with systemd">
    1. Download the binary to `/usr/local/bin/outpost` and check it.
    2. Write its settings to `/etc/genesis-outpost/outpost.env`, readable by root only.
    3. Create an unprivileged `genesis-outpost` system user and a `genesis-outpost` systemd
       service with `Restart=always`, then enable and start it. Follow its log with
       `sudo journalctl -u genesis-outpost -f`.

    systemd starts the Outpost at boot and restarts it if it stops.
  </Accordion>

  <Accordion title="VM: Windows">
    1. Download `outpost.exe` to `C:\Program Files\genesis-outpost` and check its hash.
    2. For Snowflake, run `outpost keygen`, then have a Snowflake administrator run the
       `ALTER USER` statement it prints.
    3. Write the settings to `C:\ProgramData\genesis-outpost\outpost.env`, readable only by
       SYSTEM and administrators.
    4. Create a scheduled task, **Genesis Outpost**, that starts it at boot as SYSTEM.

    The Outpost does not register itself as a Windows service. To restart it after a crash,
    set **If the task fails, restart every 1 minute** on the task, or run it under a service
    wrapper such as NSSM.
  </Accordion>

  <Accordion title="Docker">
    One `docker run` command starts the container `genesis-outpost-<name>` with
    `--restart unless-stopped`, its settings as environment variables, a named volume for its
    saved routes, and (for Snowflake) the private key mounted read-only. Follow its log with
    `docker logs -f genesis-outpost-<name>`.

    The image is distroless (the binary and CA certificates only) and runs as a non-root user.
  </Accordion>

  <Accordion title="Kubernetes">
    Save the generated manifest, replace any `<placeholder>`, and apply it:

    ```bash theme={null}
    kubectl apply -f genesis-outpost-acme-prod.yaml
    kubectl -n genesis-outpost logs deploy/genesis-outpost-acme-prod -f
    ```

    It creates a namespace, a service account, a Secret holding the sign-in settings, and a
    one-replica Deployment that runs as non-root with a read-only root filesystem and no Linux
    capabilities. For the `secrets` capability, give the pod your cloud's workload identity:
    on EKS, annotate the service account with an IAM role (IRSA); on AKS, annotate it with
    `azure.workload.identity/client-id: <managed identity client ID>` and label the pod
    `azure.workload.identity/use: "true"`; on GKE, annotate it with
    `iam.gke.io/gcp-service-account: <gsa>@<project>.iam.gserviceaccount.com`.

    The saved routes live in an `emptyDir`, so a rescheduled pod starts with none. Genesis
    re-sends its routes the next time a query or connection test through it fails to open,
    and in its hourly check. Use a small PersistentVolumeClaim instead if you want routes to
    survive rescheduling immediately.
  </Accordion>
</AccordionGroup>

## Outpost settings

The setup fills these in for you. You change them in the Outpost's settings file,
container environment or Kubernetes manifest, then restart it.

| Setting | Meaning |
| - | - |
| `GENESIS_ENDPOINT` | The Genesis tunnel endpoint URL the Outpost dials. |
| `OUTPOST_SLOT` | The slot Genesis assigned this Outpost (shown on its card). It must match. |
| `ALLOWED_DESTINATIONS` | The `host` or `host:port` patterns Genesis may reach through this Outpost. Empty allows none. |
| `OUTPOST_CAPABILITIES` | `tunnel` (default). Add `secrets` to let connections read credentials from your secret store. |
| `ALLOWED_SECRET_PREFIX` | With `secrets`: the secret-name prefix the Outpost may read, for example `genesis/`. Empty allows none. |
| `OUTPOST_SECRETS_SOURCE` | With `secrets`: your secret store, `aws` (AWS Secrets Manager, the default), `azure` (Azure Key Vault) or `gcp` (Google Secret Manager). |
| `AWS_REGION` | With `aws`: the region of your AWS Secrets Manager. On EC2 the Outpost reads its instance's region when this is unset. |
| `AZURE_KEY_VAULT_URL` | With `azure`: your vault's URL, `https://<vault>.vault.azure.net`. Required. |
| `GCP_PROJECT` | With `gcp`: the project holding your secrets. Optional on a GCE VM or GKE, where the Outpost uses its own project. |
| Sign-in settings | `SNOWFLAKE_ACCOUNT`, `SNOWFLAKE_USER`, `SNOWFLAKE_PRIVATE_KEY_FILE`, `OUTPOST_TUNNEL_KEY` (Snowflake); `DATABRICKS_HOST`, `DATABRICKS_CLIENT_ID`, `DATABRICKS_CLIENT_SECRET`, `OUTPOST_TUNNEL_KEY` (Databricks); `OUTPOST_TUNNEL_AUTH` (self-hosted). Exactly one set. |
| `HTTPS_PROXY`, `NO_PROXY` | An outbound proxy for the connection to Genesis. Your systems are always dialed directly. |

An Outpost that cannot use its settings (no slot, an unreadable key, two sign-in methods at
once) stops at startup with a log line naming the problem.

### Allowed destinations

`ALLOWED_DESTINATIONS` is your ceiling. The Outpost reaches only what it lists, whatever
Genesis asks for, and reports anything else as refused. List a `host:port` for each system;
wildcards work:

```text theme={null}
ALLOWED_DESTINATIONS=db.corp.internal:5432,*.corp.internal:5432,jira.corp.internal:443
```

Cloud metadata services and link-local addresses are never reachable through an Outpost, even
if you list them. See [Security](/docs/Setup/Outposts-Security).

### Keep credentials in your own secret store

To let connections read passwords from your own secret store instead of storing them in
Genesis:

1. Set `OUTPOST_CAPABILITIES=tunnel,secrets`.
2. Set `ALLOWED_SECRET_PREFIX` to the prefix of the secrets Genesis may read, for example
   `genesis/`. The Outpost refuses every other secret name.
3. Choose your store and give the Outpost's own identity read access to it:

   | Store | Settings | The Outpost's identity needs |
   | - | - | - |
   | AWS Secrets Manager | `OUTPOST_SECRETS_SOURCE=aws`, `AWS_REGION` | `secretsmanager:GetSecretValue` on the secrets under your prefix, for its instance role, IRSA role or profile |
   | Azure Key Vault | `OUTPOST_SECRETS_SOURCE=azure`, `AZURE_KEY_VAULT_URL=https://<vault>.vault.azure.net` | The **Key Vault Secrets User** role on the vault, for the VM's managed identity, AKS workload identity or a service principal (`AZURE_TENANT_ID`, `AZURE_CLIENT_ID`, `AZURE_CLIENT_SECRET`) |
   | Google Secret Manager | `OUTPOST_SECRETS_SOURCE=gcp`, optionally `GCP_PROJECT` | The **Secret Manager Secret Accessor** role, for the VM's service account, GKE workload identity or `GOOGLE_APPLICATION_CREDENTIALS` |

   The `tokens` capability still calls AWS when `OUTPOST_SECRETS_SOURCE` is `azure` or `gcp`.
   On EKS, the service account's IRSA role must also cover those AWS calls.

   On a laptop, your own `aws sso login`, `az login` or
   `gcloud auth application-default login` session works.
4. Restart the Outpost.

**Secret names in Azure and Google.** Key Vault and Secret Manager names cannot contain `/`,
so the Outpost stores each `/` of a Genesis secret name as `--`: the reference
`outpost_acme-prod/genesis/postgres-prod#password` reads the Key Vault secret (or Secret
Manager secret, latest version) named `genesis--postgres-prod`. Otherwise use only letters,
digits and `-` (Secret Manager also allows `_`); a name with other characters, or with `--`
itself, is refused. `ALLOWED_SECRET_PREFIX` stays in Genesis spelling (`genesis/`).

Then use a secret reference on the connection; see
[Use a secret from the Outpost](/docs/Setup/Outposts-Connect-Systems#use-a-secret-from-the-outpost).

## Rotate, revoke or remove

* **Rotate a Snowflake key without downtime.** Register a new public key in the free slot
  (`ALTER USER <user> SET RSA_PUBLIC_KEY_2 = '<new public key>'`), restart the Outpost with
  the new private key, then `ALTER USER <user> UNSET RSA_PUBLIC_KEY`.
* **Rotate a Databricks secret.** Add a second OAuth secret to the service principal, restart
  the Outpost with it, then delete the old secret.
* **Rotate or revoke the tunnel key.** Choose **New tunnel key** for the Outpost and restart
  it with the new key. The old key stops working within about 15 seconds: Genesis ends that
  Outpost's tunnel session (its log says its key was rotated or revoked). Other Outposts are
  not affected.
* **Revoke.** Unset the user's public keys or disable the user
  (`ALTER USER <user> SET DISABLED = TRUE`), or remove the service principal's CAN USE. The
  Outpost's next connection attempt is refused. A tunnel that is already open stays open
  until it reconnects; to cut it at once in Snowflake, also revoke the `APP_OUTPOST_TUNNEL`
  grant from the user's role or restart the Genesis service.
* **Remove.** Click **Delete** on the Outpost's card. If saved connections choose it or
  reference one of its secrets, Genesis lists them and asks for a second confirmation;
  choose **Delete anyway** to proceed. Those connections stop working until you move them
  to another Outpost or update their secret references as needed. When you delete the last Outpost,
  Genesis also clears its remaining routes so hosts no longer map to a loopback address with
  no listener. Then stop the Outpost where it runs and drop its Snowflake user or Databricks
  service principal.
