- Getting started
- Data security and compliance
- Organizations
- Authentication and security
- Licensing
- About licensing
- Unified Pricing: Licensing plan framework
- Activating your Enterprise license
- Migrate from Test Suite to Test Cloud
- License migration
- Assigning licenses to tenants
- Assigning user licenses
- Deallocating user licenses
- Monitoring license allocation
- License overallocation
- Licensing notifications
- User license management
- Tenants and services
- Accounts and roles
- AI Trust Layer
- External applications
- Notifications
- Logging
- Data Export
- Testing in your organization
- Troubleshooting
- Migrating to Test Cloud
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 is26.4.1, or26.4.3for TCP-based connections such as SAP BAPI. - A base64-encoded configuration file generated from the Relay UI.
- License agreement acceptance: set
LICENSE_AGREEMENT=acceptas an environment variable, or append--accept-license-agreementto 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.
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
- Open the Relay UI dashboard.
- Create or copy your relay configuration.
- Create a directory on the host for the configuration file. Any directory works; this page uses
/opt/uipath/relay/configas an example. On Windows, use a Windows path such asC:\uipath\relay\config. - 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:
| Variable | Purpose | Required |
|---|---|---|
RELAY_CUSTOM_CA_PATH | Path to the custom CA certificate | Yes, if using custom CA |
RELAY_CA_BUNDLE_PATH | Path where the merged CA bundle is written | Yes, 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:
| Variable | Purpose | Required |
|---|---|---|
HTTP_PROXY and HTTPS_PROXY | Proxy URL | No |
NO_PROXY | Comma-separated hostnames, domains, or IP addresses that bypass the proxy | No |
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.
| Option | Description | Example |
|---|---|---|
--config | Inline base64 configuration string | --config "base64string..." |
--config-file | Path to the configuration file | --config-file /relay-config/relay.config.b64enc |
--log-level | Logging verbosity: trace, debug, info, warn, or error | --log-level debug |
--heartbeat-interval | Heartbeat interval in seconds (minimum: 10) | --heartbeat-interval 10 |
--reconnect-interval | Reconnect interval in seconds (minimum: 1800) | --reconnect-interval 1800 |
--health-addr | Bind 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-executor | Connects 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-port | Connects 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
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 is26.4.3. - The SAP JCo 3 libraries
sapjco3.jar,sapidoc3.jar, andlibsapjco3.so. Download them from the SAP Support Portal, which requires an SAP account; UiPath does not ship them.sapjco3.jarandlibsapjco3.soare in the SAP Java Connector 3.1 package for Linux on x86_64. The executor image islinux/amd64, so a package for any other platform does not load.sapidoc3.jaris 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.
-
Create the directory:
sudo mkdir -p /opt/uipath/relay/executor-depssudo mkdir -p /opt/uipath/relay/executor-deps -
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/ -
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-64file /opt/uipath/relay/executor-deps/libsapjco3.so # Expect: ELF 64-bit LSB shared object, x86-64If the output says
ARM aarch64or another architecture, download the Linux on x86_64 package instead. On Windows, wherefileis not available, check the package you extracted from: the correct one is namedsapjco3-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.
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/configand/opt/uipath/relay/executor-depswith 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:
| Flag | Effect |
|---|---|
--enable-onprem-executor | Connects 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:
| Runtime | Relay client logs | Executor logs |
|---|---|---|
| Podman | podman logs relay1-<RELAY_ID> | podman logs relay-executor-<RELAY_ID> |
| Docker | docker logs relay1-<RELAY_ID> | docker logs relay-executor-<RELAY_ID> |
- In the Relay client logs, confirm the prerequisite line
On-prem executor checks: OK. - In the same logs, find the executor endpoint, named
relay1-<RELAY_ID>-system-onprem-executor-<id>, and confirm it reacheshealth check success. - In the executor logs, confirm
Started OnPremRuntimeApplication. - Run a test call from the connector that uses this endpoint, to confirm the full path works.
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.
| Task | What to do |
|---|---|
| Restart the executor | docker restart relay-executor-<RELAY_ID>. The Relay client keeps running |
| Upgrade the executor | docker rm -f relay-executor-<RELAY_ID>, then run the executor command again with the new <tag> |
| Restart the Relay client | docker restart relay1-<RELAY_ID>, then docker restart relay-executor-<RELAY_ID> |
| Upgrade the Relay client | Remove 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
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
| Symptom | Cause | Resolution |
|---|---|---|
license agreement not accepted on startup | License flag or variable not set | Add --accept-license-agreement to the start command, or set LICENSE_AGREEMENT=accept |
| Configuration file not found | Incorrect volume mount path or secret | Run kubectl describe secret relay-config and kubectl describe pod <pod-name> to verify mounts |
| Cannot connect to relay service | Network or firewall issue | Check pod logs with kubectl logs <pod-name> and verify the required outbound destinations in Deploying the Relay client |
| Custom CA merge failed | CA environment variables not both set | Set both RELAY_CUSTOM_CA_PATH and RELAY_CA_BUNDLE_PATH together |
| Hostname not recognized by relay service | Pod name is random (standalone Pod, not StatefulSet) | Use a StatefulSet instead of a standalone Pod |
| x509 certificate errors | Invalid or inaccessible CA certificate | Verify the certificate format with openssl x509 -in custom-ca.crt -text -noout and check file permissions |
Executor endpoint never reaches health check success | The executor container does not share the Relay client's network namespace, or --onprem-executor-listen-port does not match the executor's SERVER_PORT | Start 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 recover | With --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 namespace | Start the Relay client first so it owns the namespace. After any Relay client restart, restart the executor container too |
| Executor cannot find the JCo libraries | The files are in a subdirectory of the mounted volume, or the volume is mounted at the wrong path | Mount 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.
- Prerequisites
- Step 1: Get the configuration
- Step 2: Configure environment variables
- Custom CA certificate
- Proxy
- Step 3: Deploy
- Podman
- Docker
- Kubernetes
- Start command options
- SAP BAPI and other TCP-based connections
- Prerequisites
- Stage the JCo libraries
- Deploy both containers
- Verify
- Restarting and upgrading
- Operations
- Configuration details
- Heartbeat interval
- Reconnect interval
- Health endpoint
- Accessing logs
- Security
- Troubleshooting