# Gateway with Podman

<figure><img src="https://762006384-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MJXOXEifAmpyvNVL1to%2Fuploads%2FssWnUrMwyggb57aW0gFH%2FPodman%20Container%20App%20install.jpg?alt=media&#x26;token=73677058-24bd-4f5d-8c9d-823ecfbec103" alt=""><figcaption></figcaption></figure>

### Overview

This document contains information on how to install, configure, and update your Keeper Gateway on Podman. The Keeper Gateway container is built upon the base image of Rocky Linux 9 and it is hosted in [DockerHub](https://hub.docker.com/r/keeper/gateway).

Podman is an OCI-compatible, daemonless container engine. It uses the same `keeper/gateway` image as Docker and requires no modifications to the image itself. Key differences from Docker include the `docker.io/` registry prefix, SELinux `:Z` volume labels, and systemd-based service management instead of a background daemon.

#### Prerequisites

* A Linux host with a x86 AMD processor for all PAM capabilities
* `podman` installed (version 4.0+ required, 5.0+ recommended)
* `podman-compose` installed (only if using the Compose method)

> **Note:** Podman ships by default on RHEL 9, Fedora 39+, Rocky 9, and Alma 9. On Ubuntu 24.04+ and Debian 12+, install from the system repositories.

**Installing Podman**

**RHEL / Alma / Rocky / Fedora**

```
sudo dnf install -y podman
```

**Ubuntu / Debian**

```
sudo apt update && sudo apt install -y podman
```

Verify the installation:

```
podman --version
```

***

#### Create a Gateway

A new Gateway deployment can be created by clicking on **Create New** > **Gateway** from the Web Vault or Desktop App.

You can also create a Gateway and configuration file from the Commander CLI:

```
pam gateway new -n "<Gateway Name>" -a <Application Name or UID> -c b64
```

The Application names and UIDs can be found with `secrets-manager app list`

#### Installation Options

Keeper provides 2 ways of setting up the Gateway on Podman:

* Podman Compose Installation
* Manual Installation

***

### Option 1: Podman Compose Installation

If you prefer a Compose-based workflow similar to Docker Compose, use `podman-compose`.

#### Step 1. Install podman-compose

**RHEL / Alma / Rocky / Fedora**

```
sudo dnf install -y podman-compose
```

**Ubuntu / Debian**

```
sudo apt install -y podman-compose
```

#### Step 2. Create the Compose File

Create a working directory and save the Compose file:

```
sudo mkdir -p /opt/keeper-gateway && cd /opt/keeper-gateway
```

Create a file called `docker-compose.yml` with the following contents:

```
services:
  keeper-gateway:
    platform: linux/amd64
    image: docker.io/keeper/gateway:latest
    container_name: keeper-gateway
    shm_size: 16g
    security_opt:
      - seccomp:docker-seccomp.json
    environment:
      LC_ALL: "C.UTF-8"
      ACCEPT_EULA: Y
      GATEWAY_CONFIG: XXXXXXXXXXXXXXXXX
    volumes:
      - gateway-data:/etc/keeper-gateway:Z

volumes:
  gateway-data:
```

> **Important:** The `shm_size` is a critical parameter. We recommend maximizing this value to at least half of the available server memory. Production gateways should have as much memory and CPU allocated as possible. When using remote browser isolation sessions, Chromium uses a lot of memory for each process.

The only required environment variable setting is `GATEWAY_CONFIG` which is the resulting base64-encoded configuration provided by Keeper when creating a Gateway.

> **Note — SELinux hosts (RHEL / Fedora / Rocky / Alma):** The `:Z` suffix on volume mounts is **required**. It applies the correct SELinux label so the container can access the mounted directory. On non-SELinux systems (Ubuntu / Debian) it is harmless and can be left in place.

> **Note:** On Ubuntu/Debian, add `- apparmor:gateway-apparmor-profile` to the `security_opt` section and follow Step 4 below to download and activate the AppArmor profile.

#### Step 3. Download the Seccomp File

The file called `docker-seccomp.json` needs to be downloaded and placed in the same folder as your Compose file.

[Download File](https://raw.githubusercontent.com/Keeper-Security/KeeperPAM/refs/heads/main/gateway/docker-seccomp.json) or:

```
curl -O https://raw.githubusercontent.com/Keeper-Security/KeeperPAM/refs/heads/main/gateway/docker-seccomp.json
```

#### Step 4. AppArmor Profile (Required for Ubuntu/Debian distributions)

> **Note:** This step is **required** for Ubuntu and Debian-based distributions. For all other Linux distributions (RHEL, CentOS, Fedora, Amazon Linux, etc.) skip to Step 5.

The file called `gateway-apparmor-profile` needs to be placed in the same folder as your Compose file.

[Download File](https://raw.githubusercontent.com/Keeper-Security/KeeperPAM/refs/heads/main/gateway/gateway-apparmor-profile) or:

{% code overflow="wrap" %}

```bash
curl -O https://raw.githubusercontent.com/Keeper-Security/KeeperPAM/refs/heads/main/gateway/gateway-apparmor-profile
```

{% endcode %}

Activate the AppArmor config:

```bash
sudo apparmor_parser -r gateway-apparmor-profile
sudo cp gateway-apparmor-profile /etc/apparmor.d/
```

#### Step 5. Start the Service

Ensure that you are located in the folder where the `docker-compose.yml` and `docker-seccomp.json` files are saved. Executing the following command will run the Keeper Gateway in the background:

```bash
cd /opt/keeper-gateway
sudo podman-compose up -d
```

> **Note:** Unlike Docker, `podman-compose` does **not** honor the `restart:` directive in the Compose file. See Starting the Gateway Automatically on Reboot for the correct approach using systemd.

***

### Option 2: Manual Podman Installation

If you prefer to run the container directly without a Compose file, follow the instructions below.

#### Step 1. Pull the Gateway Image

```bash
sudo podman pull docker.io/keeper/gateway:latest
```

> **Note:** Podman requires the explicit `docker.io/` registry prefix when pulling images from Docker Hub. Without it, Podman may search other configured registries first, depending on `/etc/containers/registries.conf`.

#### Step 2. Download the Seccomp File

{% code overflow="wrap" %}

```bash
curl -O https://raw.githubusercontent.com/Keeper-Security/KeeperPAM/refs/heads/main/gateway/docker-seccomp.json
```

{% endcode %}

#### Step 3. AppArmor Profile (Ubuntu/Debian only)

> **Note:** This step is **required** for Ubuntu and Debian-based distributions. For all other Linux distributions, skip to Step 4.

{% code overflow="wrap" %}

```bash
curl -O https://raw.githubusercontent.com/Keeper-Security/KeeperPAM/refs/heads/main/gateway/gateway-apparmor-profile
sudo apparmor_parser -r gateway-apparmor-profile
sudo cp gateway-apparmor-profile /etc/apparmor.d/
```

{% endcode %}

#### Step 4. Start the Container

Run the Keeper Gateway container:

```bash
sudo podman run -d \
    --name keeper-gateway \
    --shm-size=16g \
    --security-opt seccomp=docker-seccomp.json \
    -e LC_ALL="C.UTF-8" \
    -e ACCEPT_EULA=Y \
    -e GATEWAY_CONFIG="XXXXXXXXXXXXXXXXX" \
    -v gateway-data:/etc/keeper-gateway:Z \
    docker.io/keeper/gateway:latest
```

> **Important:** The `--shm-size` is a critical parameter. We recommend maximizing this value to at least half of the available server memory.

Replace `XXXXXXXXXXXXXXXXX` with the base64-encoded configuration provided by Keeper when creating the Gateway.

On Ubuntu/Debian, add the AppArmor security option:

```bash
sudo podman run -d \
    --name keeper-gateway \
    --shm-size=16g \
    --security-opt seccomp=docker-seccomp.json \
    --security-opt apparmor=gateway-apparmor-profile \
    -e LC_ALL="C.UTF-8" \
    -e ACCEPT_EULA=Y \
    -e GATEWAY_CONFIG="XXXXXXXXXXXXXXXXX" \
    -v gateway-data:/etc/keeper-gateway:Z \
    docker.io/keeper/gateway:latest
```

***

### Logging

View the logs from the Keeper Gateway:

```
sudo podman logs keeper-gateway
```

On the Vault UI in the **Secrets Manager** > **Applications** > **Gateways** screen, the Gateway will show Online.

***

### Gateway Service Management

#### **Starting the service**

```
sudo podman start keeper-gateway
```

#### **Stopping the service**

```
sudo podman stop keeper-gateway
```

#### **Restarting the service**

```
sudo podman restart keeper-gateway
```

#### **Connecting to the Gateway container**

```
sudo podman exec -it keeper-gateway bash
```

***

### Starting the Gateway Automatically on Reboot

Podman does not use a background daemon. The `restart:` directive in Compose files and the `--restart` flag on `podman run` are **not** enforced across reboots. To ensure the Gateway starts automatically, generate a systemd service unit.

#### **Rootful (recommended)**

```
sudo podman generate systemd --name keeper-gateway --new --files
sudo mv container-keeper-gateway.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable container-keeper-gateway.service
sudo systemctl start container-keeper-gateway.service
```

> **Note:** The `--new` flag instructs systemd to create a fresh container from the image on every start, rather than restarting a stopped container. This ensures that image updates take effect after a reboot.

#### **Rootless (alternative)**

If you run Podman without root privileges, install the unit as a user service:

```
podman generate systemd --name keeper-gateway --new --files
mkdir -p ~/.config/systemd/user/
mv container-keeper-gateway.service ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable container-keeper-gateway.service
systemctl --user start container-keeper-gateway.service
loginctl enable-linger $(whoami)
```

> **Note:** `loginctl enable-linger` allows user services to start at boot even when no user session is active.

Important: On Ubuntu/Debian, ensure that the AppArmor file is loaded and available on reboot:

```
sudo apparmor_parser -r gateway-apparmor-profile
sudo cp gateway-apparmor-profile /etc/apparmor.d/
```

After a reboot, verify that the service is running:

```
sudo systemctl status container-keeper-gateway.service
```

***

### Debugging

If you need to enable verbose debug logs on the Gateway, add the following environment variables when starting the container:

```bash
sudo podman run -d \
    --name keeper-gateway \
    --shm-size=16g \
    --security-opt seccomp=docker-seccomp.json \
    -e LC_ALL="C.UTF-8" \
    -e ACCEPT_EULA=Y \
    -e GATEWAY_CONFIG="XXXXXXXXXXXXXXXXX" \
    -e KEEPER_GATEWAY_LOG_LEVEL="debug" \
    -e LOG_LEVEL="debug" \
    -v gateway-data:/etc/keeper-gateway:Z \
    docker.io/keeper/gateway:latest
```

Or, if using `podman-compose`, add the variables to the `environment` section of your `docker-compose.yml`:

```
services:
  keeper-gateway:
    .....
    environment:
      LC_ALL: "C.UTF-8"
      KEEPER_GATEWAY_LOG_LEVEL: "debug"
      LOG_LEVEL: "debug"
```

After changing the log level, restart the container:

```
sudo podman restart keeper-gateway
```

Tail the logs of the Keeper Gateway using this command:

```
sudo podman logs -f keeper-gateway
```

***

### Updating

Executing the following commands will update the Keeper Gateway container to the latest version and restart the service:

```
sudo podman pull docker.io/keeper/gateway:latest
```

If using systemd (recommended):

```
sudo systemctl restart container-keeper-gateway.service
```

If managing the container manually:

```bash
sudo podman stop keeper-gateway
sudo podman rm keeper-gateway
sudo podman run -d \
    --name keeper-gateway \
    --shm-size=16g \
    --security-opt seccomp=docker-seccomp.json \
    -e LC_ALL="C.UTF-8" \
    -e ACCEPT_EULA=Y \
    -v gateway-data:/etc/keeper-gateway:Z \
    docker.io/keeper/gateway:latest
```

> **Note:** After the first initialization, the Gateway stores its device keys in the persistent volume. You do not need to provide `GATEWAY_CONFIG` again on subsequent runs if the volume is preserved.

***

#### Health Checks

To monitor the Gateway service, you can configure health checks that expose its operational status. These checks are useful for container orchestration, load balancing, and automated monitoring. See the Health Check section for full setup details and examples.

***

#### Connecting to the Host Instance

A very useful capability of the Keeper Gateway is being able to open connections and tunnels to the host machine. By adding the `--add-host` flag with a value of `host.docker.internal:host-gateway`, you can open sessions directly to the host.

Manual run example:

```
sudo podman run -d \
    --name keeper-gateway \
    --shm-size=16g \
    --add-host host.docker.internal:host-gateway \
    --security-opt seccomp=docker-seccomp.json \
    -e LC_ALL="C.UTF-8" \
    -e ACCEPT_EULA=Y \
    -e GATEWAY_CONFIG="XXXXXXXXXXXXXXXXX" \
    -v gateway-data:/etc/keeper-gateway:Z \
    docker.io/keeper/gateway:latest
```

Or add the following to your `docker-compose.yml`:

```
services:
  keeper-gateway:
    platform: linux/amd64
    image: docker.io/keeper/gateway:latest
    shm_size: 16g
    extra_hosts:
      - "host.docker.internal:host-gateway"
    security_opt:
      - seccomp:docker-seccomp.json
    environment:
      LC_ALL: "C.UTF-8"
      ACCEPT_EULA: Y
      GATEWAY_CONFIG: xxxxxxxx
    volumes:
      - gateway-data:/etc/keeper-gateway:Z
```

Enabling this option allows you to establish a Connection to the host. For example, to open an SSH connection:

* Create a PAM User record with the SSH private key
* Create a PAM Machine record with the hostname set to `host.docker.internal` and port `22`
* Activate the SSH connection in PAM settings referencing the PAM User

#### Upgrading the Keeper Gateway service through the host

If you use KeeperPAM to SSH over to the host service, you can upgrade the container by running the container update of the gateway in the background:

```
sudo podman pull docker.io/keeper/gateway:latest
nohup sudo podman-compose up -d keeper-gateway &
```

The Keeper Gateway establishes outbound-only connections and does not require any inbound firewall rules. The following outbound connections must be allowed:

| Destination Endpoint                                                                                                                      | Ports Needed                                                                              | More Info                                                                                                       |
| ----------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------- |
| **Keeper Cloud** `keepersecurity.[x]` Endpoints: US: `.com` EU: `.eu` AU: `.com.au` JP: `.jp` CA: `.ca` US\_GOV: `.us`                    | TLS Port 443                                                                              | Communicates with Keeper Cloud to access target infrastructure via native protocols (e.g., SSH, RDP)            |
| **Keeper Router** `connect.keepersecurity.[x]` Endpoints: US: `.com` EU: `.eu` AU: `.com.au` JP: `.jp` CA: `.ca` US\_GOV: `.us`           | TLS Port 443                                                                              | Communicates with Keeper Router to establish secure, real-time WebSocket connections                            |
| **Keeper Stun/Turn Service** `krelay.keepersecurity.[x]` Endpoints: US: `.com` EU: `.eu` AU: `.com.au` JP: `.jp` CA: `.ca` US\_GOV: `.us` | TCP and UDP opened on Port 3478. Outbound access to TCP and UDP ports 49152 through 65535 | Facilitates secure and encrypted WebRTC connections between end-user's vault and target systems via the Gateway |

The Gateway preserves zero knowledge by performing all encryption and decryption of data locally. Keeper Secrets Manager APIs are used to communicate with the Keeper cloud.

***

#### Managing Disk Space

Over time, as new versions of the Gateway are deployed, old container images may accumulate on the host server. This can consume a significant amount of disk space. To ensure smooth operation and avoid storage issues, we recommend periodically checking your available disk space and removing unused images.

**Checking Disk Space Usage**

To view your current disk usage, run the following command on your Keeper Gateway server:

```
df -h
```

This command displays available disk space on all mounted filesystems in a human-readable format. Pay particular attention to the partition where Podman stores its data (typically `/var/lib/containers` for rootful or `~/.local/share/containers` for rootless).

You can also view Podman-specific storage usage:

```
sudo podman system df
```

If you notice the disk space running low (for example, more than 80–90% full), it's a good idea to clean up old images.

**Cleaning Up Old Images**

When you update the Keeper Gateway, Podman keeps older images on your system. To remove all unused images, you can use the following command:

```
sudo podman image prune -a
```

* The `-a` flag ensures that **all** unused images are deleted (not just dangling ones).
* You may be prompted to confirm the action — type `y` when prompted.

**Example output:**

```
WARNING! This will remove all images without at least one container associated to them.
Are you sure you want to continue? [y/N] y
Deleted Images:
...
Total reclaimed space: 4.8GB
```

This operation safely removes old images that are no longer used by any running containers.

***

#### Troubleshooting

| Problem you see                                 | Likely reason                                     | Quick remedy                                                                                           |
| ----------------------------------------------- | ------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| **`podman pull` fails with "manifest unknown"** | Missing `docker.io/` registry prefix              | Use `docker.io/keeper/gateway:latest` as the full image reference                                      |
| **Permission denied errors on Fedora/RHEL**     | Missing SELinux label                             | Add `:Z` to each volume mount, then restart the container                                              |
| **Container exits immediately**                 | Invalid or expired `GATEWAY_CONFIG`               | Run `sudo podman logs keeper-gateway` and check the output; regenerate the config if the token expired |
| **Gateway not showing Online in Vault**         | DNS or firewall blocking outbound HTTPS           | Verify the host can reach `keepersecurity.com` and `connect.keepersecurity.com` on port 443            |
| **Service dies after a reboot**                 | Podman does not enforce `restart:` across reboots | Follow the systemd instructions to generate a service unit                                             |
| **Rootless: port binding to 127.0.0.1**         | Rootless containers bind to localhost by default  | Run rootful (`sudo podman`) or place a reverse proxy (nginx/HAProxy) in front                          |
| **"Error: name already in use"**                | A stopped container with the same name exists     | Run `sudo podman rm -f keeper-gateway` before creating a new container                                 |

When in doubt, run `sudo podman logs keeper-gateway` and read the last few lines — it usually tells you what went wrong.

***

#### References:

* DockerHub listing: <https://hub.docker.com/r/keeper/gateway>
* Quick reference for [Gateway with Docker](https://docs.keeper.io/en/keeperpam/privileged-access-manager/getting-started/gateways/gateway-with-docker)
* Quick reference for [Installing Docker and Docker Compose on Linux](https://docs.keeper.io/en/keeperpam/privileged-access-manager/references/installing-docker-on-linux)
* Podman Install for [Keeper Connection Manager](https://app.gitbook.com/s/b7weUpu7VBcMnESSH8vG/installation/podman-install)
