UiPath Documentation
test-cloud
latest
false
Important :
La localisation du contenu nouvellement publié peut prendre 1 à 2 semaines avant d’être disponible.

Guide de l'administrateur de Test Cloud

Deploying the Relay client as a container

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.

Prérequis

  • Container runtime: Podman, Docker, or a Kubernetes cluster.
  • Relay client container image: registry.uipath.com/relay-client:<tag>.
  • 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 and network requirements, refer to Deploying the Relay client.

Step 1: Get the configuration

  1. Open the Relay UI dashboard.
  2. Create or copy your relay configuration.
  3. Save the base64-encoded configuration string provided by the UI.

Step 2: Configure environment variables

Custom CA certificate

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

VariableObjectifRequis
RELAY_CUSTOM_CA_PATHPath to the custom CA certificateNon (No)
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. Both variables must be set together.

Proxy

To route outbound traffic through a proxy:

VariableObjectifRequis
HTTP_PROXY et HTTPS_PROXYProxy URLNon (No)
NO_PROXYComma-separated hostnames, domains, or IP addresses that bypass the proxyNon (No)

Step 3: Deploy

Podman

For high availability, run two containers on separate nodes with distinct names. Replace <RELAY_ID> with the actual ID from the Relay UI — for example, run relay1-<RELAY_ID> on host1 and relay2-<RELAY_ID> on host2.

Quick start:

# Create a config file with the base64-encoded content from the Relay UI
echo "YOUR_BASE64_CONFIG_HERE" > /tmp/relay_config

# Run the container
podman run -it --name relay1-<RELAY_ID> --hostname relay1-<RELAY_ID> --rm \
  --read-only --read-only-tmpfs \
  -v /tmp/relay_config:/relay.config.b64enc:z \
  -e LICENSE_AGREEMENT=accept \
  registry.uipath.com/relay-client:<tag> \
  start --config-file /relay.config.b64enc --accept-license-agreement
# Create a config file with the base64-encoded content from the Relay UI
echo "YOUR_BASE64_CONFIG_HERE" > /tmp/relay_config

# Run the container
podman run -it --name relay1-<RELAY_ID> --hostname relay1-<RELAY_ID> --rm \
  --read-only --read-only-tmpfs \
  -v /tmp/relay_config:/relay.config.b64enc:z \
  -e LICENSE_AGREEMENT=accept \
  registry.uipath.com/relay-client:<tag> \
  start --config-file /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 /tmp/relay_config:/relay.config.b64enc: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.b64enc --accept-license-agreement
podman run -it --name relay1-<RELAY_ID> --hostname relay1-<RELAY_ID> --rm \
  --read-only --read-only-tmpfs \
  -v /tmp/relay_config:/relay.config.b64enc: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.b64enc --accept-license-agreement

Start command options:

OptionDescriptionExemple
--configInline base64 configuration string--config "base64string..."
--config-filePath to the configuration file--config-file /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

Kubernetes

Create secrets:

# Configuration secret
kubectl create secret generic relay-config \
  --from-file=relay.conf=/tmp/relay_config

# 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=/tmp/relay_config

# 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-0, relay-client-1, and so on), which the Relay service uses to identify and validate clients.

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>

Opérations

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)

Accessing logs

# Podman
podman logs -f relay1

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

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

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

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

Sécurité

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.

Résolution des problèmes

SymptômeOrigineRésolution
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 outbound connectivity to <region>-relay.uipath.com:443
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

Cette page vous a-t-elle été utile ?

Connecter

Besoin d'aide ? Assistance

Vous souhaitez apprendre ? UiPath Academy

Vous avez des questions ? UiPath Forum

Rester à jour