UiPath Documentation
test-cloud
latest
false
Test Cloud admin guide

Deploying the Relay client as a container

Deploy the UiPath Relay client as a container image using Podman, Docker, or Kubernetes to establish secure outbound tunnels in containerized environments.

Run the Relay client as a container image to establish secure outbound tunnels to Test Cloud from containerized environments. Before you begin, configure a Relay Group and have the client configuration string ready from the Relay UI.

Prerequisites

  • Container runtime: Podman, Docker, or a Kubernetes cluster.
  • Relay client container image: registry.uipath.com/relay-client:<tag>. Replace <tag> with a relay version from the UiPath Customer Portal downloads page. The minimum supported version is 26.4.1, or 26.4.3 for TCP-based connections such as SAP BAPI.
  • A base64-encoded configuration file generated from the Relay UI.
  • License agreement acceptance: set LICENSE_AGREEMENT=accept as an environment variable, or append --accept-license-agreement to the start command.
  • (Optional) A custom CA certificate if your organization uses enterprise PKI.

For hardware requirements and version-specific network prerequisites, refer to Deploying the Relay client.

Important:

For supported TCP-based connections, such as SAP BAPI, you deploy the Relay client together with a second container, the on-prem executor. If you need one, skip Step 3 and follow SAP BAPI and other TCP-based connections instead. That section covers Docker and Podman.

Step 1: Get the configuration

  1. Open the Relay UI dashboard.
  2. Create or copy your relay configuration.
  3. Create a directory on the host for the configuration file. Any directory works; this page uses /opt/uipath/relay/config as an example. On Windows, use a Windows path such as C:\uipath\relay\config.
  4. Save the base64-encoded configuration string from the UI there as relay.config.b64enc. The deployment commands mount this directory into the container as /relay-config; replace the example path with yours.

Step 2: Configure environment variables

Pass these variables as -e flags with Podman or Docker, or as env: entries in the Kubernetes manifest, in Step 3.

Custom CA certificate

If your organization uses a corporate or self-signed CA, set the following variables together before starting the container:

VariablePurposeRequired
RELAY_CUSTOM_CA_PATHPath to the custom CA certificateYes, if using custom CA
RELAY_CA_BUNDLE_PATHPath where the merged CA bundle is writtenYes, if using custom CA

The Relay client merges the custom CA with the system certificate bundle before establishing any TLS connections.

Proxy

To route outbound traffic through a proxy:

VariablePurposeRequired
HTTP_PROXY and HTTPS_PROXYProxy URLNo
NO_PROXYComma-separated hostnames, domains, or IP addresses that bypass the proxyNo

Step 3: Deploy

Replace <RELAY_ID> with the actual ID from the Relay UI. For high availability with Docker or Podman, run two containers on separate nodes with distinct names, for example relay1-<RELAY_ID> on host1 and relay2-<RELAY_ID> on host2. In Kubernetes, use two replicas with pod anti-affinity, as in the manifest below. A successful start logs All prerequisite checks passed.

The Podman and Docker commands below run in the foreground with -it --rm, so you can watch the first start and the container is removed when you stop it. For a long-running deployment, replace -it --rm with -d.

Podman

Quick start:

podman run -it --name relay1-<RELAY_ID> --hostname relay1-<RELAY_ID> --rm \
  --read-only --read-only-tmpfs \
  -v /opt/uipath/relay/config:/relay-config:ro,z \
  registry.uipath.com/relay-client:<tag> \
  start --config-file /relay-config/relay.config.b64enc --accept-license-agreement
podman run -it --name relay1-<RELAY_ID> --hostname relay1-<RELAY_ID> --rm \
  --read-only --read-only-tmpfs \
  -v /opt/uipath/relay/config:/relay-config:ro,z \
  registry.uipath.com/relay-client:<tag> \
  start --config-file /relay-config/relay.config.b64enc --accept-license-agreement

With a custom CA certificate:

podman run -it --name relay1-<RELAY_ID> --hostname relay1-<RELAY_ID> --rm \
  --read-only --read-only-tmpfs \
  -v /opt/uipath/relay/config:/relay-config:ro,z \
  -v /tls/custom-ca.crt:/custom-ca.crt:z \
  -v /tmp/writable:/writable:z \
  -e RELAY_CUSTOM_CA_PATH=/custom-ca.crt \
  -e RELAY_CA_BUNDLE_PATH=/writable/merged-ca.crt \
  registry.uipath.com/relay-client:<tag> \
  start --config-file /relay-config/relay.config.b64enc --accept-license-agreement
podman run -it --name relay1-<RELAY_ID> --hostname relay1-<RELAY_ID> --rm \
  --read-only --read-only-tmpfs \
  -v /opt/uipath/relay/config:/relay-config:ro,z \
  -v /tls/custom-ca.crt:/custom-ca.crt:z \
  -v /tmp/writable:/writable:z \
  -e RELAY_CUSTOM_CA_PATH=/custom-ca.crt \
  -e RELAY_CA_BUNDLE_PATH=/writable/merged-ca.crt \
  registry.uipath.com/relay-client:<tag> \
  start --config-file /relay-config/relay.config.b64enc --accept-license-agreement

Docker

Quick start:

docker run -it --name relay1-<RELAY_ID> --hostname relay1-<RELAY_ID> --rm \
  --read-only --tmpfs /tmp \
  -v /opt/uipath/relay/config:/relay-config:ro \
  registry.uipath.com/relay-client:<tag> \
  start --config-file /relay-config/relay.config.b64enc --accept-license-agreement
docker run -it --name relay1-<RELAY_ID> --hostname relay1-<RELAY_ID> --rm \
  --read-only --tmpfs /tmp \
  -v /opt/uipath/relay/config:/relay-config:ro \
  registry.uipath.com/relay-client:<tag> \
  start --config-file /relay-config/relay.config.b64enc --accept-license-agreement

With a custom CA certificate:

docker run -it --name relay1-<RELAY_ID> --hostname relay1-<RELAY_ID> --rm \
  --read-only --tmpfs /tmp \
  -v /opt/uipath/relay/config:/relay-config:ro \
  -v /tls/custom-ca.crt:/custom-ca.crt:ro \
  -v /tmp/writable:/writable \
  -e RELAY_CUSTOM_CA_PATH=/custom-ca.crt \
  -e RELAY_CA_BUNDLE_PATH=/writable/merged-ca.crt \
  registry.uipath.com/relay-client:<tag> \
  start --config-file /relay-config/relay.config.b64enc --accept-license-agreement
docker run -it --name relay1-<RELAY_ID> --hostname relay1-<RELAY_ID> --rm \
  --read-only --tmpfs /tmp \
  -v /opt/uipath/relay/config:/relay-config:ro \
  -v /tls/custom-ca.crt:/custom-ca.crt:ro \
  -v /tmp/writable:/writable \
  -e RELAY_CUSTOM_CA_PATH=/custom-ca.crt \
  -e RELAY_CA_BUNDLE_PATH=/writable/merged-ca.crt \
  registry.uipath.com/relay-client:<tag> \
  start --config-file /relay-config/relay.config.b64enc --accept-license-agreement

Kubernetes

Create secrets:

# Configuration secret
kubectl create secret generic relay-config \
  --from-file=relay.conf=/opt/uipath/relay/config/relay.config.b64enc

# Custom CA certificate secret (optional)
kubectl create secret generic custom-ca \
  --from-file=custom-ca.crt=./custom-ca.crt

# Headless service for the StatefulSet
kubectl create service clusterip relay-client-<RELAY_ID> --clusterip="None"
# Configuration secret
kubectl create secret generic relay-config \
  --from-file=relay.conf=/opt/uipath/relay/config/relay.config.b64enc

# Custom CA certificate secret (optional)
kubectl create secret generic custom-ca \
  --from-file=custom-ca.crt=./custom-ca.crt

# Headless service for the StatefulSet
kubectl create service clusterip relay-client-<RELAY_ID> --clusterip="None"

Deploy a StatefulSet:

Use a StatefulSet when hostname restrictions are enforced. StatefulSets provide stable, predictable hostnames (relay-client-<RELAY_ID>-0, relay-client-<RELAY_ID>-1, and so on), which the Relay service uses to identify and validate clients.

The manifest mounts the custom-ca secret and sets the two RELAY_* variables. If you do not use a custom CA, remove those two variables, the custom-ca volume mount, and the custom-ca volume. The readiness probe uses the health endpoint, which requires Relay client 26.4.2 or later.

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: relay-client-<RELAY_ID>
spec:
  serviceName: relay-client-<RELAY_ID>
  replicas: 2
  selector:
    matchLabels:
      app: relay-client-<RELAY_ID>
  template:
    metadata:
      labels:
        app: relay-client-<RELAY_ID>
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - relay-client-<RELAY_ID>
            topologyKey: "kubernetes.io/hostname"
      containers:
      - name: relay
        image: registry.uipath.com/relay-client:<tag>
        args:
        - start
        - --config-file=/config/relay.conf
        - --accept-license-agreement
        - --log-level=info
        - --heartbeat-interval=30
        env:
        - name: RELAY_CUSTOM_CA_PATH
          value: "/tls/custom-ca.crt"
        - name: RELAY_CA_BUNDLE_PATH
          value: "/writable/merged-ca.crt"
        imagePullPolicy: IfNotPresent
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            drop:
            - ALL
          privileged: false
          readOnlyRootFilesystem: true
          runAsGroup: 1001
          runAsNonRoot: true
          runAsUser: 1001
        readinessProbe:
          httpGet:
            path: /healthz
            port: 9090
          initialDelaySeconds: 5
          timeoutSeconds: 1
          periodSeconds: 3
          successThreshold: 1
          failureThreshold: 2
        resources:
          requests:
            cpu: 50m
            memory: 100Mi
        volumeMounts:
        - name: relay-config
          mountPath: /config/relay.conf
          subPath: relay.conf
          readOnly: true
        - mountPath: /writable
          name: writable
        - name: custom-ca
          mountPath: /tls/custom-ca.crt
          subPath: custom-ca.crt
          readOnly: true
      volumes:
      - name: relay-config
        secret:
          secretName: relay-config
      - name: writable
        emptyDir: {}
      - name: custom-ca
        secret:
          secretName: custom-ca
      restartPolicy: Always
      terminationGracePeriodSeconds: 30
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: relay-client-<RELAY_ID>
spec:
  serviceName: relay-client-<RELAY_ID>
  replicas: 2
  selector:
    matchLabels:
      app: relay-client-<RELAY_ID>
  template:
    metadata:
      labels:
        app: relay-client-<RELAY_ID>
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - relay-client-<RELAY_ID>
            topologyKey: "kubernetes.io/hostname"
      containers:
      - name: relay
        image: registry.uipath.com/relay-client:<tag>
        args:
        - start
        - --config-file=/config/relay.conf
        - --accept-license-agreement
        - --log-level=info
        - --heartbeat-interval=30
        env:
        - name: RELAY_CUSTOM_CA_PATH
          value: "/tls/custom-ca.crt"
        - name: RELAY_CA_BUNDLE_PATH
          value: "/writable/merged-ca.crt"
        imagePullPolicy: IfNotPresent
        securityContext:
          allowPrivilegeEscalation: false
          capabilities:
            drop:
            - ALL
          privileged: false
          readOnlyRootFilesystem: true
          runAsGroup: 1001
          runAsNonRoot: true
          runAsUser: 1001
        readinessProbe:
          httpGet:
            path: /healthz
            port: 9090
          initialDelaySeconds: 5
          timeoutSeconds: 1
          periodSeconds: 3
          successThreshold: 1
          failureThreshold: 2
        resources:
          requests:
            cpu: 50m
            memory: 100Mi
        volumeMounts:
        - name: relay-config
          mountPath: /config/relay.conf
          subPath: relay.conf
          readOnly: true
        - mountPath: /writable
          name: writable
        - name: custom-ca
          mountPath: /tls/custom-ca.crt
          subPath: custom-ca.crt
          readOnly: true
      volumes:
      - name: relay-config
        secret:
          secretName: relay-config
      - name: writable
        emptyDir: {}
      - name: custom-ca
        secret:
          secretName: custom-ca
      restartPolicy: Always
      terminationGracePeriodSeconds: 30

Verify the deployment:

kubectl get statefulset relay-client-<RELAY_ID>
kubectl get statefulset relay-client-<RELAY_ID>

Start command options

These apply to every runtime.

OptionDescriptionExample
--configInline base64 configuration string--config "base64string..."
--config-filePath to the configuration file--config-file /relay-config/relay.config.b64enc
--log-levelLogging verbosity: trace, debug, info, warn, or error--log-level debug
--heartbeat-intervalHeartbeat interval in seconds (minimum: 10)--heartbeat-interval 10
--reconnect-intervalReconnect interval in seconds (minimum: 1800)--reconnect-interval 1800
--health-addrBind address for the /healthz endpoint. Defaults to 0.0.0.0:9090; use an empty value to disable it--health-addr=0.0.0.0:9090
--enable-onprem-executorConnects to the on-prem executor container on the default port 18080. See SAP BAPI and other TCP-based connections--enable-onprem-executor
--onprem-executor-listen-portConnects to the on-prem executor container on this port, which must match the container's SERVER_PORT. Either flag enables the executor--onprem-executor-listen-port 18080

SAP BAPI and other TCP-based connections

Important:

Requires Relay client 26.4.3 or later. This section covers Docker and Podman.

For supported TCP-based connections, such as SAP BAPI, you run two containers on the same host:

  • Relay client container: opens the secure outbound connection to UiPath.
  • On-prem executor container: connects to your on-premises system and handles the TCP-based connection.

The executor container shares the Relay client's network, so the Relay client reaches the executor on localhost.

Prerequisites

  • On-prem executor container image: registry.uipath.com/relay-onprem-executor:<tag>. Use the same <tag> as your Relay client image. The minimum supported version is 26.4.3.
  • The SAP JCo 3 libraries sapjco3.jar, sapidoc3.jar, and libsapjco3.so. Download them from the SAP Support Portal, which requires an SAP account; UiPath does not ship them.
    • sapjco3.jar and libsapjco3.so are in the SAP Java Connector 3.1 package for Linux on x86_64. The executor image is linux/amd64, so a package for any other platform does not load.
    • sapidoc3.jar is in the separate SAP Java IDoc Class Library 3.1 package.
  • The Relay host can resolve and reach the SAP system's hostname and port.

Stage the JCo libraries

The libraries can live in any directory on the host. This page uses /opt/uipath/relay/executor-deps as an example; what matters is that the deployment command mounts your directory at /opt/uipath/onprem-runtime/dep-libs inside the executor container. The commands use sudo because /opt requires root on Linux; omit it for a directory you own.

  1. Create the directory:

    sudo mkdir -p /opt/uipath/relay/executor-deps
    sudo mkdir -p /opt/uipath/relay/executor-deps
    
  2. Copy the three files into it. Place them directly in the directory, not in subdirectories:

    sudo cp sapjco3.jar sapidoc3.jar libsapjco3.so /opt/uipath/relay/executor-deps/
    sudo cp sapjco3.jar sapidoc3.jar libsapjco3.so /opt/uipath/relay/executor-deps/
    
  3. Confirm the native library is built for x86-64:

    file /opt/uipath/relay/executor-deps/libsapjco3.so
    # Expect: ELF 64-bit LSB shared object, x86-64
    file /opt/uipath/relay/executor-deps/libsapjco3.so
    # Expect: ELF 64-bit LSB shared object, x86-64
    

    If the output says ARM aarch64 or another architecture, download the Linux on x86_64 package instead. On Windows, where file is not available, check the package you extracted from: the correct one is named sapjco3-linuxx86_64-<version>.

Deploy both containers

Run the commands in this order: the Relay client first, then the executor. The executor joins the Relay client's network, so the Relay client must be running when the executor starts.

Warning:

If you restart or recreate the Relay client, the executor loses its network and does not recover on its own. Restart the executor afterwards, as described in Restarting and upgrading.

Before you run the commands:

  • Replace /opt/uipath/relay/config and /opt/uipath/relay/executor-deps with the host directories you chose in Step 1 and Stage the JCo libraries. Keep the container-side paths as shown.
  • If you already started a Relay client from Step 3, stop and remove it. A running container's arguments cannot be changed.
  • If you use a custom CA or a proxy, add the variables from Step 2, and for a custom CA the two volume mounts from Step 3, to the Relay client command. The Relay client is the container that connects to UiPath.
  • Do not publish the executor port with -p. Only the Relay client needs to reach it.

Enable the executor on the Relay client with either flag:

FlagEffect
--enable-onprem-executorConnects to the executor on the default port 18080
--onprem-executor-listen-port <port>Connects to the executor on <port>. Must match the executor container's SERVER_PORT

The other executor flags, --onprem-executor-java-home and --onprem-executor-dep-dir, have no effect in a container: the executor image includes its own Java runtime and reads its libraries from /opt/uipath/onprem-runtime/dep-libs.

Podman
# 1. Relay client. It owns the network namespace that the executor joins.
podman run -d --name relay1-<RELAY_ID> --hostname relay1-<RELAY_ID> \
  --read-only --read-only-tmpfs \
  -v /opt/uipath/relay/config:/relay-config:ro,z \
  registry.uipath.com/relay-client:<tag> \
  start --config-file /relay-config/relay.config.b64enc \
  --accept-license-agreement \
  --onprem-executor-listen-port 18080

# 2. On-prem executor. SERVER_ADDRESS=127.0.0.1 restricts it to loopback,
#    which is where the Relay client reaches it. Without it, the executor
#    image listens on all interfaces of the shared namespace.
podman run -d --name relay-executor-<RELAY_ID> \
  --network container:relay1-<RELAY_ID> \
  -e SERVER_ADDRESS=127.0.0.1 \
  -e SERVER_PORT=18080 \
  -v /opt/uipath/relay/executor-deps:/opt/uipath/onprem-runtime/dep-libs:ro,z \
  registry.uipath.com/relay-onprem-executor:<tag>
# 1. Relay client. It owns the network namespace that the executor joins.
podman run -d --name relay1-<RELAY_ID> --hostname relay1-<RELAY_ID> \
  --read-only --read-only-tmpfs \
  -v /opt/uipath/relay/config:/relay-config:ro,z \
  registry.uipath.com/relay-client:<tag> \
  start --config-file /relay-config/relay.config.b64enc \
  --accept-license-agreement \
  --onprem-executor-listen-port 18080

# 2. On-prem executor. SERVER_ADDRESS=127.0.0.1 restricts it to loopback,
#    which is where the Relay client reaches it. Without it, the executor
#    image listens on all interfaces of the shared namespace.
podman run -d --name relay-executor-<RELAY_ID> \
  --network container:relay1-<RELAY_ID> \
  -e SERVER_ADDRESS=127.0.0.1 \
  -e SERVER_PORT=18080 \
  -v /opt/uipath/relay/executor-deps:/opt/uipath/onprem-runtime/dep-libs:ro,z \
  registry.uipath.com/relay-onprem-executor:<tag>

Alternatively, create a Podman pod and run both containers in it with --pod. The pod's infra container owns the network namespace, so either container can restart on its own.

Docker
# 1. Relay client. It owns the network namespace that the executor joins.
docker run -d --name relay1-<RELAY_ID> --hostname relay1-<RELAY_ID> \
  --read-only --tmpfs /tmp \
  -v /opt/uipath/relay/config:/relay-config:ro \
  registry.uipath.com/relay-client:<tag> \
  start --config-file /relay-config/relay.config.b64enc \
  --accept-license-agreement \
  --onprem-executor-listen-port 18080

# 2. On-prem executor. SERVER_ADDRESS=127.0.0.1 restricts it to loopback,
#    which is where the Relay client reaches it. Without it, the executor
#    image listens on all interfaces of the shared namespace.
docker run -d --name relay-executor-<RELAY_ID> \
  --network container:relay1-<RELAY_ID> \
  -e SERVER_ADDRESS=127.0.0.1 \
  -e SERVER_PORT=18080 \
  -v /opt/uipath/relay/executor-deps:/opt/uipath/onprem-runtime/dep-libs:ro \
  registry.uipath.com/relay-onprem-executor:<tag>
# 1. Relay client. It owns the network namespace that the executor joins.
docker run -d --name relay1-<RELAY_ID> --hostname relay1-<RELAY_ID> \
  --read-only --tmpfs /tmp \
  -v /opt/uipath/relay/config:/relay-config:ro \
  registry.uipath.com/relay-client:<tag> \
  start --config-file /relay-config/relay.config.b64enc \
  --accept-license-agreement \
  --onprem-executor-listen-port 18080

# 2. On-prem executor. SERVER_ADDRESS=127.0.0.1 restricts it to loopback,
#    which is where the Relay client reaches it. Without it, the executor
#    image listens on all interfaces of the shared namespace.
docker run -d --name relay-executor-<RELAY_ID> \
  --network container:relay1-<RELAY_ID> \
  -e SERVER_ADDRESS=127.0.0.1 \
  -e SERVER_PORT=18080 \
  -v /opt/uipath/relay/executor-deps:/opt/uipath/onprem-runtime/dep-libs:ro \
  registry.uipath.com/relay-onprem-executor:<tag>

Verify

Read the logs with the commands for your runtime:

RuntimeRelay client logsExecutor logs
Podmanpodman logs relay1-<RELAY_ID>podman logs relay-executor-<RELAY_ID>
Dockerdocker logs relay1-<RELAY_ID>docker logs relay-executor-<RELAY_ID>
  1. In the Relay client logs, confirm the prerequisite line On-prem executor checks: OK.
  2. In the same logs, find the executor endpoint, named relay1-<RELAY_ID>-system-onprem-executor-<id>, and confirm it reaches health check success.
  3. In the executor logs, confirm Started OnPremRuntimeApplication.
  4. Run a test call from the connector that uses this endpoint, to confirm the full path works.
Note:

While the executor container is still starting, step 2 may show one health check failed: dial tcp [::1]:18080: connect: connection refused first. That is expected and clears on the next check, about 10 seconds later, without restarting the Relay client.

For problems, see Troubleshooting on this page first, then On-prem executor issues.

Restarting and upgrading

You can restart or upgrade the executor on its own. If you restart or recreate the Relay client, restart or recreate the executor afterwards as well: the executor runs inside the Relay client's network, and restarting or recreating the Relay client replaces that network, so the existing executor container cannot recover on its own. Use the same <tag> for both images when you upgrade. For Podman, replace docker with podman.

TaskWhat to do
Restart the executordocker restart relay-executor-<RELAY_ID>. The Relay client keeps running
Upgrade the executordocker rm -f relay-executor-<RELAY_ID>, then run the executor command again with the new <tag>
Restart the Relay clientdocker restart relay1-<RELAY_ID>, then docker restart relay-executor-<RELAY_ID>
Upgrade the Relay clientRemove both containers, then run both commands again with the new <tag>, Relay client first. A recreated Relay client is a new container, so the executor must be recreated too

Operations

Configuration details

The configuration file must contain the base64-encoded JSON string generated by the Relay UI. On startup, the Relay client reads the configuration, decodes it, validates it, and connects to the specified relay service endpoint.

  • First run: Configuration is stored encrypted in the data directory.
  • Subsequent runs: The encrypted configuration is automatically decrypted and used.
  • Config file changes: Require a container restart to take effect.

Heartbeat interval

The heartbeat keeps idle TCP connections alive. Lower the interval if your firewall, proxy, or network address translation (NAT) drops idle connections before 30 seconds:

--heartbeat-interval=30    # Default
--heartbeat-interval=10    # For aggressive firewall or NAT environments
--heartbeat-interval=30    # Default
--heartbeat-interval=10    # For aggressive firewall or NAT environments

Reconnect interval

Proactive reconnect re-establishes the connection on a fixed schedule. Use this in environments where a proxy or load balancer has an idle-connection timeout:

--reconnect-interval=0     # Disabled (default)
--reconnect-interval=1800  # Reconnect every 30 minutes (minimum)
--reconnect-interval=0     # Disabled (default)
--reconnect-interval=1800  # Reconnect every 30 minutes (minimum)

Health endpoint

Note:

The --health-addr option is available with Relay client 26.4.2 and later.

The container image enables an HTTP /healthz endpoint by default on 0.0.0.0:9090. Use --health-addr=<address> to change the bind address, or --health-addr= to disable the endpoint. The Kubernetes readiness probe in the example manifest uses this endpoint.

Accessing logs

# Podman
podman logs -f relay1-<RELAY_ID>

# Docker
docker logs -f relay1-<RELAY_ID>

# Kubernetes (current run)
kubectl logs -f relay-client-<RELAY_ID>-0

# Kubernetes (previous run, if the container restarted)
kubectl logs relay-client-<RELAY_ID>-0 --previous
# Podman
podman logs -f relay1-<RELAY_ID>

# Docker
docker logs -f relay1-<RELAY_ID>

# Kubernetes (current run)
kubectl logs -f relay-client-<RELAY_ID>-0

# Kubernetes (previous run, if the container restarted)
kubectl logs relay-client-<RELAY_ID>-0 --previous

Container log retention is controlled by your container runtime or Kubernetes cluster logging policy, not by the Relay client.

Security

Apply the following security settings in your container manifest:

  • readOnlyRootFilesystem: true: prevents modification of the container filesystem.
  • runAsNonRoot: true: runs the process as a non-root user.
  • allowPrivilegeEscalation: false: prevents privilege escalation.
  • capabilities.drop: [ALL]: drops all Linux capabilities.
  • privileged: false: disables privileged mode.

Store relay configuration in Kubernetes secrets and use role-based access control (RBAC) to restrict secret access. Do not embed the base64 configuration in the container image or pass it as a plain environment variable.

Troubleshooting

SymptomCauseResolution
license agreement not accepted on startupLicense flag or variable not setAdd --accept-license-agreement to the start command, or set LICENSE_AGREEMENT=accept
Configuration file not foundIncorrect volume mount path or secretRun kubectl describe secret relay-config and kubectl describe pod <pod-name> to verify mounts
Cannot connect to relay serviceNetwork or firewall issueCheck pod logs with kubectl logs <pod-name> and verify the required outbound destinations in Deploying the Relay client
Custom CA merge failedCA environment variables not both setSet both RELAY_CUSTOM_CA_PATH and RELAY_CA_BUNDLE_PATH together
Hostname not recognized by relay servicePod name is random (standalone Pod, not StatefulSet)Use a StatefulSet instead of a standalone Pod
x509 certificate errorsInvalid or inaccessible CA certificateVerify the certificate format with openssl x509 -in custom-ca.crt -text -noout and check file permissions
Executor endpoint never reaches health check successThe executor container does not share the Relay client's network namespace, or --onprem-executor-listen-port does not match the executor's SERVER_PORTStart the executor with --network container:relay1-<RELAY_ID> and set both ports to the same value
After restarting one container, the other loses all network access and does not recoverWith --network container:, the joining container's networking is destroyed when the owning container restarts. A Podman pod is not affected, because its infra container owns the namespaceStart the Relay client first so it owns the namespace. After any Relay client restart, restart the executor container too
Executor cannot find the JCo librariesThe files are in a subdirectory of the mounted volume, or the volume is mounted at the wrong pathMount a directory that holds the files directly, with no subdirectories, at /opt/uipath/onprem-runtime/dep-libs

For executor problems that are not specific to containers, such as a JCo native library built for the wrong architecture, see On-prem executor issues.

Was this page helpful?

Connect

Need help? Support

Want to learn? UiPath Academy

Have questions? UiPath Forum

Stay updated