About Ansible automation portal RHEL appliances

The Ansible automation portal RHEL virtual machine appliances provide pre-configured virtual machines that you can deploy across multiple virtualization platforms.

The appliances are available in the following formats:

  • QCOW2 - For Red Hat OpenShift Virtualization and KVM-based environments
  • VMDK - For VMware vSphere infrastructure

Supported platforms

You can deploy Ansible automation portal appliances on the following platforms:

Red Hat OpenShift Virtualization
Deploy the appliance as a virtual machine within your Red Hat OpenShift Container Platform environment using the QCOW2 image format.
VMware vSphere
Deploy the appliance on VMware infrastructure using ESXi hosts and VMFS datastores with the VMDK image format.
QEMU for local testing
Deploy the appliance on your local machine for testing and demonstrations using the QCOW2 image format. This deployment model is not supported for production environments.
Note

Ansible automation portal appliances support AMD64/x86_64 platforms only.

Initial configuration

The appliance requires configuration at first boot to connect to Ansible Automation Platform and start portal services. You must provide configuration through one of the following methods, listed in priority order:

Baked-in configuration
For advanced installations using the Ansible collection to build a customized appliance image with pre-baked settings.
VMware guestinfo properties
For VMware deployments, provide SSH keys and portal configuration through guestinfo properties set in vSphere.
cloud-init user-data
For cloud and Red Hat OpenShift Virtualization deployments, provide SSH keys and portal configuration through cloud-init user-data. The appliance configures itself automatically on first boot.
Pre-seeded configuration file
Place a YAML configuration file at /etc/portal/config.yaml before first boot for automated deployment.

If no configuration source is found at first boot, portal services do not start. You can provide configuration after deployment by editing /etc/portal/configs/app-config/app-config.production.yaml and restarting the portal service.

The initial configuration includes:

  • SSH key authentication for administrative access
  • Ansible Automation Platform URL, OAuth application credentials, and admin token
  • Database settings (built-in or external PostgreSQL)
  • Base URL and network configuration
Note

The admin user account is locked by default and console login is disabled. Administrative access is available only through SSH using the key you provided during configuration.

Disconnected environments

You can deploy Ansible automation portal appliances in disconnected or air-gapped environments. The pre-built appliance images include all required container images and plug-ins, so no external network access is required during initial deployment.

For appliance upgrades in disconnected environments, a mirror registry or OCI archive provides the updated container images. Use the ansible-portal registry-login command to authenticate to a private registry mirror.

Understanding the appliance

Before configuring or managing the appliance, review how its key components work together.

Configuration files

The Ansible automation portal RHEL appliance uses two YAML configuration files at /etc/portal/configs/app-config/:

app-config.yaml
Infrastructure configuration including the base URL, database connection, TLS, and system defaults. This file is set during initial deployment and is not typically modified.
app-config.production.yaml
Application configuration including Ansible Automation Platform connection, OAuth settings, SCM integrations, and catalog synchronization. Edit this file for day-to-day configuration changes. To apply changes, edit the file and restart the Ansible automation portal service. Changes take effect after the restart, which takes approximately 60 seconds.

Service management

The Ansible automation portal RHEL appliance runs three systemd services that manage Podman containers:

portal.service
Ansible automation portal application. Listens on port 443 (HTTPS).
postgres.service
PostgreSQL database. Listens on port 5432 (internal container network only). This service is skipped when an external database is configured.
devtools.service
Ansible development tools. Provides Ansible Navigator and content creator services for building execution environments and developing Ansible content from the Ansible automation portal interface.
Note

Restarting the portal service also restarts postgres and devtools due to service dependencies.

Use standard systemctl and journalctl commands to manage and inspect these services:

$ sudo systemctl restart portal
$ sudo journalctl -u portal -f

SSL certificates

The appliance generates self-signed SSL certificates at first boot and stores them at /etc/portal/ssl/. Replace these with certificates from a trusted certificate authority for production use.

Prerequisites for deploying Ansible automation portal on RHEL

Before you deploy an Ansible automation portal RHEL appliance, verify that your environment meets the system, network, and access requirements.

System requirements

Expand
Table 1. System requirements for Ansible automation portal RHEL appliances
Resource Minimum Recommended
CPU 4 vCPU 6 vCPU
Memory 16 GB 24 GB
Disk space 40 GB 60 GB
Architecture AMD64/x86_64 --
Operating system RHEL 9.6 or later (included in appliance) RHEL 9.7

The recommended values include headroom for the built-in database. For production deployments, use an external PostgreSQL database. The built-in database is suitable for evaluation and small environments.

Network requirements

The following table lists the default ports used by the Ansible automation portal RHEL appliance. The HTTPS port is configurable after deployment.

Expand
Table 2. Default ports for Ansible automation portal RHEL appliances
Direction Port Protocol Purpose
Inbound 443 (default) HTTPS User access to Ansible automation portal
Inbound 22 SSH Administrator access to the appliance
Outbound 443 HTTPS Communication with the Ansible Automation Platform instance
Outbound 443 HTTPS Image pulls from registry.redhat.io (upgrades only, not required with a mirror registry)

Port 5432 (PostgreSQL) is used internally between containers and is not exposed to the network.

Required access

  • An Ansible Automation Platform 2.5 or later instance with administrator privileges.
  • An active Red Hat Ansible Automation Platform subscription.
  • An active RHEL subscription (for the KVM host, if applicable).
  • The pre-built QCOW2 or VMDK appliance image, available from the Red Hat Ansible Automation Platform downloads page.
  • An SSH key pair for appliance access.

Prepare for installation

Before deploying the appliance, complete the prerequisite steps in the pre-installation configuration documentation. Create an OAuth application and generate an API token. You need the Client ID, Client Secret, and API Token values for the cloud-init configuration.

Optional: If you want to import custom templates from private GitHub or GitLab repositories, create a personal access token for each service before you begin. You provide these tokens in the cloud-init configuration.

Prepare the cloud-init configuration

The appliance uses cloud-init to apply your configuration at first boot. Cloud-init is a standard tool for automating the initial setup of virtual machines. It creates user accounts, injects SSH keys, and runs custom configuration scripts. The appliance extends cloud-init with custom fields for Ansible Automation Platform credentials and database settings.

Create a cloud-init user-data file with your SSH keys and Ansible Automation Platform credentials.

The following four Ansible Automation Platform fields are required. Without them, Ansible automation portal services do not start:

  • aap.host_url
  • aap.token
  • aap.oauth.client_id
  • aap.oauth.client_secret

SSH keys are required for access. The appliance has no default password.

All other fields are optional. The Ansible automation portal RHEL appliance auto-generates passwords for the default built-in database deployed during initial installation, backend secrets, and a user-accessible URL if you omit them.

Tip

Keep quotation marks around SSH public keys in the cloud-init user-data file.

Minimal cloud-init template

Replace the placeholder values in angle brackets. All other values auto-generate at first boot.

#cloud-config

users:
  - name: <username>
    sudo: ALL=(ALL) NOPASSWD:ALL
    ssh_authorized_keys:
      - "<your-ssh-public-key>"

aap:
  host_url: "https://<aap-host>"
  token: "<aap-api-token>"
  oauth:
    client_id: "<oauth-client-id>"
    client_secret: "<oauth-client-secret>"

Full cloud-init template

This template includes all supported fields. Replace values marked with angle brackets. Remove or leave optional sections as-is.

#cloud-config

users:
  - name: <username>
    sudo: ALL=(ALL) NOPASSWD:ALL
    ssh_authorized_keys:
      - "<your-ssh-public-key>"

aap:
  host_url: "https://<aap-host>"
  token: "<aap-api-token>"
  check_ssl: true
  oauth:
    client_id: "<oauth-client-id>"
    client_secret: "<oauth-client-secret>"

database:
  type: builtin
  builtin:
    password: "auto"
    admin_password: "auto"

security:
  backend_secret: "auto"

network:
  port: 443
  base_url: "https://portal.example.com"

integrations:
  github:
    url: "github.com"
    token: "<github-personal-access-token>"
  gitlab:
    url: "gitlab.com"
    token: "<gitlab-personal-access-token>"
  • aap.check_ssl -- Set to false if your Ansible Automation Platform instance uses a self-signed certificate.
  • network.base_url -- Set this when users access the Ansible automation portal RHEL appliance through a hostname, route, or load balancer. If omitted, the user-accessible URL is auto-detected from the VM IP address.
  • network.port -- The HTTPS listen port. Default is 443. If you are using the standard port 443, you do not need to specify the port. If you set a custom port, you must also open that port on any firewall and, for Red Hat OpenShift Virtualization deployments, update the Red Hat OpenShift Container Platform route to use the custom port.
  • integrations -- Optional. Only required if you need to import custom templates from private GitHub or GitLab repositories. Public repository access does not require a token.

External database cloud-init template

To connect to an existing PostgreSQL database instead of the built-in one, use the following database section:

database:
  type: external
  external:
    host: "<database-host>"
    port: 5432
    name: "portal_db"
    user: "<database-user>"
    password: "<database-password>"
    ssl: true

The database user requires the CREATEDB privilege.

Save the cloud-init user-data file. You will use it during the platform-specific installation procedure.

Install Ansible automation portal on RHEL with KVM

Deploy the Ansible automation portal appliance on a RHEL 9 host with KVM using virt-install.

Before you begin

About this task

The following procedure provides example commands that you can adapt to your environment.

Procedure

  1. Install the required packages and enable libvirtd.
    $ sudo dnf install -y qemu-kvm libvirt virt-install genisoimage
    $ sudo systemctl enable --now libvirtd
  2. Verify that KVM is available.
    $ lsmod | grep kvm
  3. Ensure you have an SSH key pair to use in the cloud-init configuration.

    If you do not have one, generate a key pair:

    $ ssh-keygen -t ed25519 -N ""
  4. Set environment variables for your deployment.

    Replace the placeholder values. The examples in this procedure use automation-portal as the VM and project name. You can choose any name that suits your environment.

    $ export QCOW2_PATH="/path/to/portal-appliance.qcow2"
    $ export VM_NAME="automation-portal"
    $ export VM_MEMORY=24576
    $ export VM_CPUS=6
    $ export WORK_DIR="$HOME/portal-deploy"
    $ export IMAGE_DIR="/var/lib/libvirt/images"
    $ mkdir -p "$WORK_DIR"
  5. Save your cloud-init user-data file as $WORK_DIR/cloud-init-user-data.yaml.
  6. Create a cloud-init ISO from your user-data file.

    KVM delivers cloud-init configuration to the VM as a small ISO disk image labeled cidata. Cloud-init expects two files on the ISO: user-data (your configuration) and meta-data (instance identity).

    $ cd "$WORK_DIR"
    $ cp cloud-init-user-data.yaml user-data
    $ echo "instance-id: ${VM_NAME}" > meta-data
    $ genisoimage -output cloud-init.iso -volid cidata -joliet -rock user-data meta-data
  7. Copy the disk image and create the VM.
    $ sudo cp "$QCOW2_PATH" "$IMAGE_DIR/${VM_NAME}.qcow2"
    $ sudo virt-install \
      --name "$VM_NAME" \
      --memory "$VM_MEMORY" \
      --vcpus "$VM_CPUS" \
      --disk "$IMAGE_DIR/${VM_NAME}.qcow2" \
      --disk "$WORK_DIR/cloud-init.iso,device=cdrom" \
      --osinfo rhel9-unknown \
      --network default \
      --noautoconsole \
      --import
  8. Wait 1-3 minutes for first-boot configuration to complete, then retrieve the VM IP address.
    $ sudo virsh domifaddr "$VM_NAME"

Results

SSH into the Ansible automation portal RHEL appliance and confirm that all services are running:

$ ssh -i <private-key> <username>@<vm-ip>
$ sudo systemctl status portal postgres devtools

Example output for a healthy Ansible automation portal RHEL appliance:

portal.service - Automation portal
     Active: active (running) since ...
postgres.service - PostgreSQL database
     Active: active (running) since ...
devtools.service - Ansible development tools
     Active: active (running) since ...

All three services should show active (running).

What to do next

Continue to Connect and verify Ansible automation portal to complete the post-installation steps.

Remove the VM

Delete the VM and its storage after an evaluation.

About this task

To delete the VM and its storage after an evaluation, run the following commands.

Procedure

Destroy the VM, remove its definition and storage, and clean up the working directory.
$ sudo virsh destroy "$VM_NAME"
$ sudo virsh undefine "$VM_NAME" --remove-all-storage
$ rm -rf "$WORK_DIR"

Install Ansible automation portal on Red Hat OpenShift Virtualization

Deploy the Ansible automation portal appliance on Red Hat OpenShift Virtualization to run the portal as a virtual machine alongside container workloads within your Red Hat OpenShift Container Platform cluster.

This approach enables you to use your existing OpenShift infrastructure to host the portal.

For more information about Red Hat OpenShift Virtualization, see the About OpenShift Virtualization documentation.

You can install the appliance using the CLI or the OpenShift web console. Both methods require the following prerequisites.

Prerequisites

  • Red Hat OpenShift Container Platform cluster (4.x) with Red Hat OpenShift Virtualization operator installed and configured.
  • Cluster administrator or equivalent permissions to create VirtualMachine resources.
  • A storage class configured that supports ReadWriteOnce (RWO) access mode for virtual machine disks.
  • The Ansible automation portal disk image in QCOW2 format.
  • The virtctl CLI tool installed. You can download it from the OpenShift web console under Virtualization > Overview > Download virtctl.
  • Access to the OpenShift web console or oc CLI tool.
  • Your cloud-init user-data file prepared with Ansible Automation Platform credentials and SSH keys.
  • Sufficient cluster resources: minimum 16 GiB allocatable memory for the virtual machine.

Install using the CLI

  1. Create a project for the deployment:
    $ oc new-project <project-name>
  2. Upload the QCOW2 disk image using virtctl:
    $ virtctl image-upload dv <disk-datavolume-name> \
      --size=50Gi \
      --image-path=/path/to/disk.qcow2 \
      --uploadproxy-url=https://cdi-uploadproxy-openshift-cnv.apps.<cluster-domain> \
      --wait-secs=600 \
      -n <project-name>
    Expand
    Option Description
    --size Set to at least 50 Gi. The QCOW2 expands during conversion to raw format and requires additional space.
    --insecure Add this flag if the Containerized Data Importer (CDI) upload proxy uses a self-signed certificate. Omit it when the proxy has a trusted certificate.
    --force-bind Add this flag if the storage class uses WaitForFirstConsumer volume binding mode.

    Wait for both upload and processing to complete. The "Processing completed successfully" message confirms that CDI converted the image. For more information about CDI, see the Managing data volumes section of the Red Hat OpenShift Virtualization documentation.

  3. Create a Secret from the cloud-init file:
    $ oc create secret generic <cloudinit-secret-name> \
      --from-file=userdata=cloud-init-user-data.yaml \
      -n <project-name>
  4. Create a VirtualMachine manifest.

    The following example shows a minimal configuration. Replace the resource names and namespace to match your environment:

    apiVersion: kubevirt.io/v1
    kind: VirtualMachine
    metadata:
      name: <vm-name>
      namespace: <project-name>
    spec:
      runStrategy: Always
      template:
        spec:
          domain:
            devices:
              disks:
                - disk:
                    bus: virtio
                  name: rootdisk
                - disk:
                    bus: virtio
                  name: cloudinitdisk
              interfaces:
                - masquerade: {}
                  name: default
            resources:
              requests:
                memory: 16Gi
          networks:
            - name: default
              pod: {}
          volumes:
            - name: rootdisk
              dataVolume:
                name: <disk-datavolume-name>
            - name: cloudinitdisk
              cloudInitNoCloud:
                secretRef:
                  name: <cloudinit-secret-name>

    The dataVolume name must match the DataVolume created by virtctl image-upload in step 2. The secretRef name must match the Secret created in step 3.

  5. Apply the manifest:
    $ oc apply -f <vm-manifest>.yaml
  6. Wait for the VM to reach Running status:
    $ oc get vmi -n <project-name> -w

    The VM is ready when PHASE shows Running and READY shows True.

  7. Create a Service and Route to expose Ansible automation portal:
    $ virtctl expose vm <vm-name> --port=443 --name=<service-name> -n <project-name>
    $ oc create route passthrough <route-name> --service=<service-name> --port=443 -n <project-name>
    $ ROUTE_HOST=$(oc get route <route-name> -o jsonpath='{.spec.host}' -n <project-name>)
    $ echo "Automation portal URL: https://$ROUTE_HOST"
  8. Update the Ansible automation portal user-accessible URL to match the route.

    SSH into the VM:

    $ virtctl ssh <username>@<vm-name> -n <project-name>

    Edit the configuration file:

    $ sudo vi /etc/portal/configs/app-config/app-config.production.yaml

    Set the following three values, replacing <route-host> with the route hostname from step 7:

    app:
      baseUrl: "https://<route-host>"
    backend:
      baseUrl: "https://<route-host>"
      cors:
        origin: "https://<route-host>"

    Save the file and restart the Ansible automation portal service. Restarting the portal service also restarts postgres and devtools due to service dependencies:

    $ sudo systemctl restart portal

Verification

  • Verify that the virtual machine is running:
    $ oc get vmi -n <project-name>

    The output shows the virtual machine in Running phase with READY status set to True.

  • SSH into the appliance and verify that all services are running:
    $ sudo ansible-portal status
  • Access the portal URL from your browser.

Install using the OpenShift web console

You can also deploy the appliance from the OpenShift web console without using the CLI.

Prerequisites

  • Red Hat OpenShift Container Platform with the Red Hat OpenShift Virtualization operator installed and configured.
  • Cluster administrator or equivalent permissions.
  • The Ansible automation portal QCOW2 disk image available on your local machine.
  • Your cloud-init user-data file prepared with Ansible Automation Platform credentials and SSH keys.

Procedure

  1. Go to Storage > PersistentVolumeClaims.
  2. Create a PVC using Data upload form. Upload the QCOW2 image. Set the size to at least 50 Gi.
  3. Go to Workloads > Secrets. Create a key/value secret with a key named userdata. Paste the cloud-init user-data contents as the value.
  4. Go to Virtualization > VirtualMachines. Click Create VirtualMachine > From YAML. Apply the manifest from the CLI procedure.
  5. Wait for the VM status to change to Running.
  6. Go to Networking > Services. Create a service targeting port 443 on the VM.
  7. Go to Networking > Routes. Create a passthrough TLS route for the service. Note the route hostname.
  8. SSH into the VM. Set app.baseUrl, backend.baseUrl, and backend.cors.origin to https://<route-hostname>.
  9. Restart the portal service:
    $ sudo systemctl restart portal

Verification

  • SSH into the VM and confirm that all services are running:
    $ sudo ansible-portal status
  • Access the portal URL from your browser.

If you encounter upload, boot, or scheduling failures, see Troubleshooting RHEL appliances.

Install Ansible automation portal on VMware vSphere

Deploy the Ansible automation portal appliance on VMware vSphere using the vSphere web client.

Prerequisites

  • VMware vSphere/vCenter with permissions to create VMs and upload files to a datastore.
  • The Ansible automation portal disk image in VMDK format, available from the Red Hat Ansible Automation Platform downloads page.
  • Your cloud-init user-data file prepared with Ansible Automation Platform credentials and SSH keys.
  • An SSH key pair for appliance access.
  • genisoimage installed on your local machine (for creating the cloud-init ISO).

Install using the vSphere web client

  1. Upload the VMDK disk image to a datastore:
    1. Open the vCenter web client.
    2. Navigate to Storage > Datastores and select your datastore.
    3. Click Upload Files and upload the Ansible automation portal VMDK file.
  2. Save your cloud-init user-data file as cloud-init-user-data.yaml. Use the cloud-init template from the first boot configuration topic.
  3. Create a cloud-init ISO from your user-data file.

    VMware delivers cloud-init configuration to the VM as a small ISO disk image labeled cidata. Cloud-init expects two files on the ISO: user-data (your configuration) and meta-data (instance identity):

    $ cp cloud-init-user-data.yaml user-data
    $ echo "instance-id: automation-portal" > meta-data
    $ genisoimage -output cloud-init.iso -volid cidata -joliet -rock user-data meta-data
  4. Upload the cloud-init ISO to the same datastore.
  5. Create a virtual machine:
    1. Right-click the cluster or host and select New Virtual Machine > Create a new virtual machine.
    2. Set the following example values. Replace the name, CPU, and memory to match your environment:
      Expand
      Field Example value
      Name automation-portal
      Guest OS Red Hat Enterprise Linux 9 (64-bit)
      CPU 6 cores
      Memory 24 GB
      Hard disk Remove the default disk
      Network Select your VM network
    3. Click Next and then Finish.
  6. Attach the VMDK disk and cloud-init ISO to the VM:
    1. Copy the uploaded VMDK and cloud-init ISO to the VM folder on the datastore.
    2. Edit the VM settings.
    3. Click Add hard disk > Existing Hard Disk and browse to the copied VMDK.
    4. Click Add CD/DVD Drive > Datastore ISO File and browse to the copied cloud-init ISO.
    5. Save the VM settings.
  7. Power on the VM. First-boot configuration takes 2-3 minutes.

Verification

  • Open the VM console in vSphere or SSH into the VM and confirm that all services are running:
    $ sudo ansible-portal status
  • Access the portal URL from your browser.

Configure the appliance at first boot

Provide initial configuration for the Ansible automation portal appliance so that portal services can start and connect to Ansible Automation Platform.

You must supply SSH keys and portal settings through one of the supported configuration methods during or before deployment.

Prerequisites

  • The Ansible Automation Platform OAuth application Client ID and Client Secret.
  • The Ansible Automation Platform admin token.
  • An SSH public key for administrative access.
  • The URL of your Ansible Automation Platform instance.

Using cloud-init user-data

Use this method for Red Hat OpenShift Virtualization, cloud, and KVM/QEMU deployments.

  1. Create a cloud-init user-data file:
    #cloud-config
    users:
      - name: admin
        groups: sudo
        ssh_authorized_keys:
          - <your_ssh_public_key>
    
    aap:
      host_url: https://<aap_host>
      token: <aap_admin_token>
      oauth:
        client_id: <oauth_client_id>
        client_secret: <oauth_client_secret>
      check_ssl: true
    
    database:
      type: builtin

    Replace the placeholder values with your Ansible Automation Platform credentials and SSH public key.

    The appliance parses the custom aap and database fields directly from the cloud-init user-data at first boot.

    The following additional fields are available for cloud-init configuration:

    • network.base_url -- Set the user-accessible URL (auto-detected from the VM IP address if not specified). Set this when users access Ansible automation portal through a hostname, route, or load balancer.
    • network.port -- Set the HTTPS port (default: 443).
    • security.backend_secret -- Set the backend authentication secret (auto generates a random value).
    • database.builtin.password and database.builtin.admin_password -- Set built-in database passwords (auto generates random values).
    • database.external.* -- Configure an external PostgreSQL database (host, port, name, user, password, ssl). The database user requires the CREATEDB privilege.
    • integrations.github.url, integrations.github.token -- Configure GitHub integration (URL defaults to github.com).
    • integrations.gitlab.url, integrations.gitlab.token -- Configure GitLab integration (URL defaults to gitlab.com).
    • backup.enabled, backup.schedule, backup.retention_days -- Configure automated backups.
  2. Provide the user-data file during deployment:
    • For Red Hat OpenShift Virtualization, add a cloudInitNoCloud volume to the VirtualMachine manifest.
    • For cloud providers (AWS, GCP, Azure), pass the user-data through the instance launch configuration.
    • For local KVM/QEMU, create a cloud-init ISO or use the -smbios option to pass user-data.

Using VMware guestinfo properties

Use this method for VMware vSphere deployments.

  1. Set the following guestinfo properties on the virtual machine in vSphere:
    guestinfo.portal.ssh_public_key = "<your_ssh_public_key>"
    guestinfo.portal.config = "<base64_encoded_config_yaml>"

    Where <base64_encoded_config_yaml> is the Base64-encoded content of your portal configuration YAML.

  2. Power on the virtual machine. The appliance detects and applies the guestinfo properties on first boot.

Using a pre-seeded configuration file

Use this method for automated deployments with Ansible or Terraform.

  1. Place a YAML configuration file at /etc/portal/config.yaml on the appliance disk image before first boot:
    aap:
      host_url: https://<aap_host>
      token: <aap_admin_token>
      oauth:
        client_id: <oauth_client_id>
        client_secret: <oauth_client_secret>
    database:
      type: builtin
  2. Boot the appliance. The first-boot service detects and applies the configuration automatically.

Configure after deployment

If you deployed the appliance without providing configuration, portal services do not start. You can configure the appliance after deployment by editing the configuration files directly.

  1. SSH into the appliance using the key you provided through cloud-init or another method.
  2. Edit the application configuration file:
    $ sudo vi /etc/portal/configs/app-config/app-config.production.yaml
  3. Restart the portal service:
    $ sudo systemctl restart portal

Verification

  • Verify that portal services are running:
    $ sudo ansible-portal status
  • Access the portal URL from your browser.
  • Log in using your Ansible Automation Platform credentials.

Connect and verify Ansible automation portal

After deploying the Ansible automation portal appliance, update the OAuth redirect URI, verify service health, and sign in to the portal.

About this task

Complete these post-installation steps after deploying the Ansible automation portal appliance on any platform.

Procedure

Update the OAuth redirect URI
  1. Log in to Ansible Automation Platform as an administrator.
  2. Navigate to Access Management > OAuth Applications > automation-portal.
  3. Update Redirect URIs to https://<portal-address>/api/auth/rhaap/handler/frame.
    • For RHEL with KVM: use the VM IP address.
    • For Red Hat OpenShift Virtualization: use the route hostname.
    • For VMware vSphere: use the VM IP address or hostname.
  4. Click Save.
Verify service health
  1. SSH into the Ansible automation portal RHEL appliance and check the service status.
    $ sudo systemctl status portal postgres devtools

    Example output for a healthy Ansible automation portal RHEL appliance:

    portal.service - Automation portal
         Active: active (running) since ...
    postgres.service - PostgreSQL database
         Active: active (running) since ...
    devtools.service - Ansible development tools
         Active: active (running) since ...

    All three services should show active (running).

    To view detailed logs for a specific service:

    $ sudo journalctl -u portal -n 100 --no-pager
Sign in to Ansible automation portal
  1. Open https://<portal-address> in a browser.
  2. Click Sign in with RHAAP.
  3. Authenticate with your Ansible Automation Platform credentials.

Results

A successful login confirms that the OAuth integration with Ansible Automation Platform is working. The Ansible automation portal catalog displays synchronized job templates from Ansible Automation Platform. If no templates appear, verify that the API token has access to job templates in Ansible Automation Platform.

Deploy a RHEL appliance in a disconnected environment

Deploy the Ansible automation portal RHEL appliance in a disconnected or air-gapped environment where the appliance has no access to external registries or the internet.

Before you begin

  • You have downloaded the appliance disk image (QCOW2 or VMDK) from the Red Hat Ansible Automation Platform downloads page on a connected system.
  • You have a method to transfer the disk image to the disconnected environment (for example, portable media or a secure file transfer system).
  • You have a virtualization platform available in the disconnected environment (Red Hat OpenShift Virtualization, VMware vSphere, or KVM).
  • You have network connectivity from the appliance to your Ansible Automation Platform instance (internal network).
  • You have Ansible Automation Platform credentials: host URL, API token, OAuth client ID, and OAuth client secret.
  • You have an SSH key pair for appliance access.

About this task

The appliance image includes everything needed to run without pulling content from external registries:

Pre-bundled Ansible plugins
Dynamic plugins are extracted at build time and stored at /usr/share/portal/plugins/. The appliance loads plugins from the local filesystem, not from a registry.
Pre-pulled container images
The Ansible automation portal and PostgreSQL container images are embedded in the appliance image. No container image pulls occur at runtime.
Self-signed SSL certificates
Generated locally at first boot. You can replace them with your own certificates after deployment.
No registry authentication required
The appliance starts and runs without registry credentials. Registry authentication is only needed for future upgrades.

Procedure

  1. On a connected system, download the appliance disk image from the Red Hat Ansible Automation Platform downloads page.
  2. Transfer the disk image to the disconnected environment using your organization's approved transfer method.
  3. Deploy the appliance on your virtualization platform following the standard deployment procedure for your environment:
  4. Provide initial configuration through cloud-init, VMware guestinfo properties, or a pre-seeded configuration file.

    The appliance starts and runs without external network access because all required container images and plug-ins are pre-loaded in the appliance image.

    The following differences apply in a disconnected environment:

    • Source control integrations require network access. The integrations.github and integrations.gitlab cloud-init fields require network access to the source control service. If your disconnected environment has internal GitHub Enterprise or GitLab instances, configure these fields with the internal hostnames.
    • Set network.base_url to match your internal DNS or IP. Set network.base_url to the hostname or IP address that users will use to access the Ansible automation portal RHEL appliance on your internal network. If omitted, the appliance auto-detects the VM IP address.
  5. If no registry is available for image upgrades, bypass the registry authentication gate:
    $ sudo touch /etc/portal/.registry-auth-override
  6. Verify that the portal services are running:
    $ sudo ansible-portal status
  7. Verify that Ansible plugins loaded from the local filesystem:
    $ sudo podman exec portal ls /opt/app-root/src/dynamic-plugins-root/

    You should see plugin directories listed. These plugins were loaded from the pre-baked files at /usr/share/portal/plugins/, not from a registry.

Results

  • Verify that the portal URL is accessible from your browser.
  • Verify that all services show a healthy status in the ansible-portal status output.

What to do next

For appliance upgrades in disconnected environments, see Upgrading in disconnected environments.

Replace self-signed SSL certificates

The Ansible automation portal RHEL appliance generates self-signed SSL certificates at first boot and stores them at /etc/portal/ssl/. Replace these certificates with certificates from a trusted certificate authority for production use.

Replace the SSL certificates

Prerequisites:

  • A TLS certificate and private key in PEM format, issued by a certificate authority trusted by your organization.
  • SSH access to the appliance.

Procedure:

  1. Copy your certificates to the appliance:
    $ sudo cp certificate-file.pem /etc/portal/ssl/cert.pem
    $ sudo cp private-key-file.pem /etc/portal/ssl/key.pem
    $ sudo chmod 644 /etc/portal/ssl/cert.pem
    $ sudo chmod 600 /etc/portal/ssl/key.pem
  2. Restart the Ansible automation portal service:
    $ sudo systemctl restart portal

Verification:

  • Verify that the Ansible automation portal is using the new certificate:
    $ curl -vk https://localhost 2>&1 | grep -i "issuer"

    The output displays the issuer from your certificate, not the self-signed issuer.

Trust a custom certificate authority

If your organization uses a custom certificate authority (CA) or a self-signed certificate for your Ansible Automation Platform instance, configure the Ansible automation portal RHEL appliance to trust it.

Prerequisites:

  • The CA certificate or self-signed certificate in PEM format.
  • SSH access to the appliance.

Procedure:

  1. Copy the CA certificate or self-signed certificate to the appliance:
    $ sudo cp ca-certificate-file.pem /etc/portal/ssl/ca-bundle.crt

    If you have multiple CA certificates to trust, concatenate them into a single bundle file before copying it to the appliance.

  2. Create a Quadlet drop-in to set the NODE_EXTRA_CA_CERTS environment variable:
    $ sudo mkdir -p /etc/containers/systemd/portal.container.d
    $ echo -e '[Container]\nEnvironment=NODE_EXTRA_CA_CERTS=/etc/portal/ssl/ca-bundle.crt' \
      | sudo tee /etc/containers/systemd/portal.container.d/ca-certs.conf
  3. Reload systemd and restart the Ansible automation portal service:
    $ sudo systemctl daemon-reload
    $ sudo systemctl restart portal

Verification:

  • Verify that the environment variable is set in the portal container:
    $ sudo podman exec portal env | grep NODE_EXTRA_CA_CERTS

    The output displays NODE_EXTRA_CA_CERTS=/etc/portal/ssl/ca-bundle.crt.

Set a custom user-accessible URL or port

The Ansible automation portal RHEL appliance auto-detects the user-accessible URL from the VM IP address at each boot. To set a custom hostname or port, update the configuration file and restart the service.

Before you begin

  • SSH access to the appliance.
  • The hostname or IP address and port that users will use to access Ansible automation portal.

Procedure

  1. Edit the configuration file:
    $ sudo vi /etc/portal/configs/app-config/app-config.production.yaml
  2. Update the following three values.

    This example uses port 8443. If you are using the standard port 443, you do not need to specify the port:

    app:
      baseUrl: "https://portal.example.com:8443"
    backend:
      baseUrl: "https://portal.example.com:8443"
      cors:
        origin: "https://portal.example.com:8443"
  3. Save the file and restart the Ansible automation portal service.

    Restarting the portal service also restarts postgres and devtools due to service dependencies:

    $ sudo systemctl restart portal
  4. If you set a custom port, open that port on any firewall and, for Red Hat OpenShift Virtualization deployments, update the OpenShift route.
  5. Update the OAuth redirect URI in Ansible Automation Platform to match the new URL.

Results

Verify that Ansible automation portal is accessible at the new URL:

$ curl -fk https://new-url

A successful response confirms that the URL and port are configured correctly.

Configure an external database

By default, the Ansible automation portal RHEL appliance runs a built-in PostgreSQL database. For production deployments, connect to an external PostgreSQL database.

Before you begin

  • A PostgreSQL database instance accessible from the appliance.
  • A database user with the CREATEDB privilege.
  • The database password.
  • SSH access to the appliance.

About this task

You can provide external database settings in the cloud-init user-data at first boot or configure the database after deployment. For the cloud-init template fields, see External database cloud-init template.

Procedure

  1. Edit the configuration file:
    $ sudo vi /etc/portal/configs/app-config/app-config.production.yaml
  2. Update the backend.database section:
    backend:
      database:
        connection:
          host: database-host
          port: 5432
          user: database-user
          ssl:
            require: true
        client: pg

    The database user requires the CREATEDB privilege.

  3. Store the database password as a Podman secret.

    Write the value to a temporary file on tmpfs to avoid exposing it in the process list:

    $ temp_file=$(mktemp -p /dev/shm) && chmod 600 "$temp_file"
    $ printf '%s' "database-password" > "$temp_file"
    $ sudo podman secret create portal_postgresql_password "$temp_file"
    $ rm -f "$temp_file"
  4. Restart the Ansible automation portal service:
    $ sudo systemctl restart portal

Results

Check the portal logs to verify the database connection:

$ sudo journalctl -u portal --no-pager | grep -i "database"

The output shows a successful database connection with no errors.

Upgrade the Ansible automation portal RHEL appliance

The Ansible automation portal RHEL appliance uses RHEL image mode (bootc) for atomic upgrades. Your configuration, data, and secrets are preserved, and you can roll back to the previous image if needed.

Important

If you are upgrading from plug-in version 2.1 to 2.2, you must grant navigation permissions to existing roles. The Templates and History sidebar items now require explicit ansible.templates.view and ansible.history.view permission grants. Without these permissions, non-admin users cannot see the Templates and History navigation items. Administrators and superusers are unaffected.

After upgrading, log in as an administrator, navigate to Administration > RBAC, and add ansible.templates.view and ansible.history.view to each role that requires access. For more information, see Configure role-based access control for Ansible automation portal.

When you upgrade, the entire system image is replaced atomically. If an upgrade causes issues, you can roll back to the previous image in one command.

Bootc downloads only the layers that changed between the current and new image, making incremental upgrades fast and bandwidth-efficient.

Bootc divides the filesystem into three categories that determine what happens during an upgrade:

Expand
Path Upgrade behavior What the appliance stores here
/usr Replaced atomically with the new image Portal scripts, pre-baked Ansible plugins, image version stamp
/etc Three-way merged (your changes are preserved) Portal configuration (app-config.production.yaml), Quadlet files, Quadlet drop-ins, SSL certificates
/var Never touched by bootc PostgreSQL database, backups, Podman secrets, generated configs

Your configuration files in /etc are preserved through upgrades using a three-way merge: bootc compares the original file from the old image, your modified version, and the new file from the new image. Your changes take precedence. Files in /var (database, backups) are never modified by bootc.

For more information about RHEL image mode, see Managing RHEL bootc images.

Prerequisites:

Authenticate to the container registry

To pull new appliance images from registry.redhat.io, authenticate to the registry and save the credentials where bootc can find them.

Important

Bootc and Podman use separate credential stores. The --authfile /etc/ostree/auth.json flag saves credentials to the location that bootc upgrade and bootc switch read. Running podman login without --authfile stores credentials only for Podman and does not authenticate bootc operations.

Procedure:

  1. SSH into the Ansible automation portal RHEL appliance and log in to the container registry:
    $ sudo podman login --authfile /etc/ostree/auth.json registry.redhat.io

Upgrade the appliance

Procedure:

  1. Back up and restore data.
  2. Run the upgrade:
    $ sudo bootc upgrade

    The upgrade is staged and does not take effect until you reboot. The current version continues running. You can schedule the reboot for a convenient maintenance window.

    bootc upgrade pulls the latest image for the current tag. To upgrade to a specific version, use bootc switch with a version tag:

    $ sudo bootc switch registry.redhat.io/ansible-automation-platform/bootc-automation-portal-rhel9:version
  3. Reboot to activate the new image:
    $ sudo systemctl reboot

Verification:

  • Verify that the new image is booted:
    $ sudo bootc status

    The booted digest matches the digest from the upgrade output. The previous version is retained as a rollback target.

  • Check the portal service logs:
    $ sudo journalctl -u portal -f
  • Verify that all services are running:
    $ sudo systemctl status portal postgres devtools

    All three services (portal, postgres, devtools) show active (running).

Roll back an upgrade

Bootc maintains two image slots: the booted image and one rollback image. After an upgrade, the previous version becomes the rollback target. After a rollback, the upgraded version becomes the rollback target. You can switch between the two versions as needed.

If the new version has issues, roll back to the previous image.

Procedure:

  1. Roll back to the previous image:
    $ sudo bootc rollback
  2. Reboot to activate the rollback image:
    $ sudo systemctl reboot

Verification:

  • Confirm the rollback was applied:
    $ sudo bootc status

    The booted image shows the previous digest. The upgraded image is now listed as the rollback target.

  • Verify that all services are running:
    $ sudo systemctl status portal postgres devtools

What survives an upgrade

The following table describes what happens to each type of content during a bootc upgrade of the Ansible automation portal RHEL appliance.

Expand
Content Location Survives upgrade Notes
Portal configuration /etc/portal/configs/ Yes Three-way merge preserves your modifications
SSL certificates /etc/portal/ssl/ Yes Three-way merge
Quadlet drop-ins /etc/containers/systemd/portal.container.d/ Yes Three-way merge
Quadlet port customization /etc/containers/systemd/ Yes Three-way merge
PostgreSQL data /var/lib/portal/postgres-data/ Yes Never touched by bootc
Backups /var/lib/portal/backups/ Yes Never touched by bootc
Podman secrets /var/lib/containers/ Yes Never touched by bootc
Ansible plugins /usr/share/portal/plugins/ Updated New plugins from the new image
Portal scripts /usr/share/portal/scripts/ Updated New scripts from the new image
Dynamic plugin configs /var/lib/portal/dynamic-plugins-root/ Cleared Regenerated from new plugins on first start

Post-upgrade reconciliation

After reboot, the appliance automatically reconciles Ansible plugins and configuration with the new image version:

  1. Clears the dynamic plugins directory so that plugins are regenerated from the new image.
  2. Clears generated configuration files (regenerated on portal start).
  3. Creates any new directories required by the new image version.
  4. Fixes file ownership for portal and PostgreSQL directories.

Upgrade the Ansible automation portal RHEL appliance in a disconnected environment

In disconnected environments, you can upgrade the Ansible automation portal RHEL appliance using a mirror registry. Configure the mirror registry so that bootc upgrade pulls images from your internal registry instead of registry.redhat.io.

Before you begin

  • A mirror registry is accessible from the Ansible automation portal RHEL appliance on the internal network.
  • The new appliance image is copied to the mirror registry.
  • You have SSH access to the appliance.

About this task

Once the mirror registry is configured, bootc upgrade checks the mirror automatically.

Procedure

  1. On a connected machine, copy the new appliance image to your internal registry:
    $ skopeo copy \
      docker://registry.redhat.io/ansible-automation-platform/bootc-automation-portal-rhel9:version \
      docker://mirror.internal.example.com:5000/ansible-automation-platform/bootc-automation-portal-rhel9:version
  2. On the Ansible automation portal RHEL appliance, create a registry mirror configuration:
    $ sudo tee /etc/containers/registries.conf.d/50-mirror.conf > /dev/null << 'EOF'
    [[registry]]
    prefix = "registry.redhat.io"
    location = "registry.redhat.io"
    
    [[registry.mirror]]
    location = "mirror.internal.example.com:5000"
    insecure = false
    EOF

    Replace mirror.internal.example.com:5000 with your mirror registry address.

  3. If your mirror registry uses a self-signed certificate, add the CA certificate to the system trust store:
    $ sudo cp ca.crt /etc/pki/ca-trust/source/anchors/
    $ sudo update-ca-trust

    Alternatively, set insecure = true in the mirror block. This is not recommended for production environments.

  4. Authenticate to the mirror registry:
    $ sudo ansible-portal registry-login
  5. Authenticate bootc to the mirror registry.

    Bootc requires credentials in /etc/ostree/auth.json to pull images:

    $ sudo podman login --authfile /etc/ostree/auth.json mirror.internal.example.com:5000
  6. Run the upgrade:
    $ sudo bootc upgrade

    If your mirror does not carry Red Hat GPG signatures, add --no-signature-verification to the bootc switch command when switching image sources. This flag is not needed for bootc upgrade when the image source is already configured.

  7. Reboot to activate the new image:
    $ sudo systemctl reboot

Results

Note

The mirror configuration in /etc/containers/registries.conf.d/ survives bootc upgrades because bootc preserves /etc using a three-way merge. You do not need to reconfigure the mirror after each upgrade.

Verify that the new image is booted:

$ sudo bootc status

Verify that all services are running:

$ sudo systemctl status portal postgres devtools

What to do next

Sync new versions to the mirror

When a new appliance version is available, copy it to the mirror from a connected machine:

  1. Copy the new image version to the mirror registry:
    $ skopeo copy \
      docker://registry.redhat.io/ansible-automation-platform/bootc-automation-portal-rhel9:new-version \
      docker://mirror.internal.example.com:5000/ansible-automation-platform/bootc-automation-portal-rhel9:new-version
  2. On the appliance, run the upgrade and reboot:
    $ sudo bootc upgrade
    $ sudo systemctl reboot

Cloud-init reference

The following tables describe all cloud-init fields supported by the Ansible automation portal RHEL appliance.

SSH access (standard cloud-init)

Expand
Table 3. SSH access fields
Field Required Default Description
users[].name Yes -- Linux username for SSH access.
users[].sudo Yes -- Sudo privileges. Use ALL=(ALL) NOPASSWD:ALL.
users[].ssh_authorized_keys[] Yes -- One or more SSH public keys.

Ansible Automation Platform connection

Expand
Table 4. Ansible Automation Platform connection fields
Field Required Default Description
aap.host_url Yes -- Ansible Automation Platform URL (for example, https://aap.example.com).
aap.token Yes -- Ansible Automation Platform API token with administrator privileges.
aap.check_ssl No true Set false for self-signed Ansible Automation Platform certificates.
aap.oauth.client_id Yes -- OAuth 2.0 application client ID.
aap.oauth.client_secret Yes -- OAuth 2.0 application client secret.

Database

Expand
Table 5. Database fields
Field Required Default Description
database.type No builtin builtin or external.
database.builtin.password No auto PostgreSQL user password. auto generates a random value.
database.builtin.admin_password No auto PostgreSQL admin password. auto generates a random value.
database.builtin.name No portal_db Database name.
database.builtin.user No portal_user Database user.
database.external.host Yes (if external) -- External PostgreSQL hostname.
database.external.port No 5432 External PostgreSQL port.
database.external.name No portal_db External database name.
database.external.user No portal_user External database user. Requires the CREATEDB privilege.
database.external.password Yes (if external) -- External database password.
database.external.ssl No true Enable SSL for external database connection.

Security

Expand
Table 6. Security fields
Field Required Default Description
security.backend_secret No auto Backend authentication secret. auto generates a random value.

Network

Expand
Table 7. Network fields
Field Required Default Description
network.port No 443 Ansible automation portal HTTPS listen port. If you are using the standard port 443, you do not need to specify this field.
network.base_url No Auto-detected User-accessible URL that users enter in their browser. Set this when users access Ansible automation portal through a hostname, route, or load balancer. If omitted, auto-detected from the VM IP address.

Source control integrations

Expand
Table 8. Source control integration fields
Field Required Default Description
integrations.github.url No github.com GitHub hostname. For GitHub Enterprise, omit https://.
integrations.github.token No -- GitHub personal access token.
integrations.gitlab.url No gitlab.com GitLab hostname. For self-hosted GitLab, omit https://.
integrations.gitlab.token No -- GitLab personal access token.

Portal CLI commands reference

The Ansible automation portal appliance provides the ansible-portal management CLI for administration and troubleshooting.

Accessing the appliance

You can access the appliance using SSH with the key you provided during initial configuration:

ssh -i /path/to/ssh-key/id_ed25519 -p port_number admin@VM_IP

Replace the following placeholders:

  • /path/to/ssh-key/id_ed25519 with the path to your SSH private key.
  • port_number with the SSH port number (default is 22).
  • VM_IP with the IP address or hostname of your appliance.

The ansible-portal CLI

The ansible-portal command is the primary management interface for the appliance, following Red Hat Ansible tooling conventions (ansible-navigator, ansible-builder, ansible-lint).

ansible-portal <command> [options]
Expand
Table 9. Available commands
Command Description
status Show portal service status and diagnostics.
backup Create portal backup. Use --list to list backups.
restore file Restore from backup archive. Use --latest for most recent.
registry-login Log in to container registry for image upgrades.

Run ansible-portal command --help for command-specific options.

ansible-portal status

Displays the current status of all Ansible automation portal services.

Usage:

sudo ansible-portal status            # One-shot status display
sudo ansible-portal status --watch    # Refresh status every 5 seconds

Description:

Displays the current status of all Ansible automation portal services, including:

  • Setup completion status
  • PostgreSQL database state and connectivity
  • Devtools service state
  • Portal service state and plug-in installation status
  • Scheduled backup status
  • Disk and memory resource usage

Use this command to verify that all services are running correctly after installation or troubleshooting. Use --watch to continuously monitor service status.

ansible-portal backup

Creates a backup of the portal configuration and data.

Usage:

sudo ansible-portal backup                          # Interactive backup (select content)
sudo ansible-portal backup --full                   # Full backup (all items)
sudo ansible-portal backup --minimal                # Required items only
sudo ansible-portal backup --list                   # List existing backups
sudo ansible-portal backup --export /path/to/dir/   # Copy latest backup to a directory

Description:

Creates a backup archive containing the portal configuration, Podman secrets, and data. Use this command before making significant configuration changes or for disaster recovery planning.

  • backup without options starts an interactive backup where you select the content to include.
  • --full creates a complete backup of all configuration and data.
  • --minimal backs up only the required configuration items.
  • --list lists existing backups.
  • --export copies the latest backup to the specified directory. If no backup exists, one is created first.
Important

Backup archives contain credentials in plain text. Restrict file permissions on backup archives. Encrypt archives before transferring to remote storage:

gpg --symmetric --cipher-algo AES256 /var/lib/portal/backups/backup-file.tar.gz

Example output:

Portal Backup Tool
==================
1) Full backup (config + database + secrets) [recommended]
2) Config only (config + secrets, no database)
3) Database only

Select backup type [1]: 1

Creating backup...
  Backing up configuration... done
  Backing up secrets... done
  Backing up database... done

Backup created: /var/lib/portal/backups/portal-backup-2026-05-07-143022.tar.gz

ansible-portal restore

Restores the portal from a backup.

Usage:

sudo ansible-portal restore --list                  # List available backups
sudo ansible-portal restore --latest                # Restore the newest backup
sudo ansible-portal restore --latest --dry-run      # Preview restore without changes
sudo ansible-portal restore /path/to/backup.tar.gz  # Restore a specific backup file

Description:

Restores the portal configuration, Podman secrets, Quadlet drop-in files, and data from a backup created by ansible-portal backup.

  • --list lists all available backups.
  • --latest restores from the most recent backup.
  • --dry-run previews what would be restored without making changes.
  • Specify a file path to restore from a specific backup archive.
Note

Restoring a backup overwrites the current portal configuration. Use --dry-run to preview the restore before executing. Create a backup of the current state before restoring if you want to preserve it.

Example output:

Portal Restore Tool
===================
Restoring from: /var/lib/portal/backups/portal-backup-2026-05-07-143022.tar.gz

Stopping services...
  Restoring configuration... done
  Restoring secrets... done
  Restoring database... done
Starting services...

Restore complete.

Services stop during restore and restart automatically.

ansible-portal registry-login

Manages container registry credentials for pulling portal images.

Usage:

sudo ansible-portal registry-login                 # Log in to registry.redhat.io (default)
sudo ansible-portal registry-login registry_host # Log in to a specific registry
sudo ansible-portal registry-login --test          # Test stored credentials
sudo ansible-portal registry-login --logout        # Remove stored credentials

Description:

Manages authentication to container registries used for pulling Ansible automation portal images and updates.

  • registry-login without arguments prompts for credentials for registry.redhat.io.
  • Specify a registry hostname to authenticate to a different registry, such as a private mirror.
  • --test verifies that stored credentials are valid by inspecting the registry without downloading images.
  • --logout clears stored credentials for the registry.

Use this command to configure registry authentication for bootc upgrade operations. In disconnected environments, use this command to authenticate to your private registry mirror.

In disconnected environments where no registry is available, you can bypass the registry authentication gate by creating an override marker:

sudo touch /etc/portal/.registry-auth-override

Configuration management

The appliance uses two YAML configuration files at /etc/portal/configs/app-config/:

app-config.yaml
Infrastructure configuration (base URL, database connection, TLS, system defaults). This file is set during initial deployment and is not typically modified.
app-config.production.yaml
Application configuration (Ansible Automation Platform connection, OAuth settings, SCM integrations, catalog sync). Edit this file for day-to-day configuration changes.

Sensitive values such as tokens and passwords are stored as Podman secrets and injected into the portal container through environment variable interpolation (${VAR} syntax in the YAML files).

Updating configuration

To update the portal configuration:

  1. Edit the application configuration file:
    sudo vi /etc/portal/configs/app-config/app-config.production.yaml
  2. Restart the portal service to apply the changes:
    sudo systemctl restart portal

Managing secrets

The portal stores sensitive values as Podman secrets, separate from the configuration files.

Expand
Table 10. Portal secrets reference
Secret name Environment variable Type
portal_backend_secret BACKEND_SECRET Auto-generated
portal_postgresql_password POSTGRESQL_PASSWORD Auto-generated or user-provided
portal_postgresql_admin_password POSTGRESQL_ADMIN_PASSWORD Auto-generated
portal_aap_token AAP_TOKEN User-provided
portal_aap_oauth_client_secret AAP_OAUTH_CLIENT_SECRET User-provided
portal_github_token GITHUB_TOKEN Optional
portal_gitlab_token GITLAB_TOKEN Optional
portal_github_app_id GITHUB_APP_ID User-provided (EE Builder, GitHub App)
portal_github_app_client_id GITHUB_APP_CLIENT_ID User-provided (EE Builder, GitHub App)
portal_github_app_client_secret GITHUB_APP_CLIENT_SECRET User-provided (EE Builder, GitHub App)
portal_github_app_private_key GITHUB_APP_PRIVATE_KEY User-provided (EE Builder, GitHub App)
portal_github_oauth_client_id GITHUB_OAUTH_CLIENT_ID User-provided (EE Builder, GitHub OAuth)
portal_github_oauth_client_secret GITHUB_OAUTH_CLIENT_SECRET User-provided (EE Builder, GitHub OAuth)
portal_gitlab_oauth_client_id GITLAB_OAUTH_CLIENT_ID User-provided (EE Builder, GitLab OAuth)
portal_gitlab_oauth_client_secret GITLAB_OAUTH_CLIENT_SECRET User-provided (EE Builder, GitLab OAuth)
Note

EE Builder secrets (prefixed with portal_github_app_, portal_github_oauth_, or portal_gitlab_oauth_) require a Quadlet drop-in file (ee-builder-secrets.conf) to map Podman secrets to container environment variables. See the Configuring execution environment builder guide for instructions.

Important

The portal-backup utility does not capture EE Builder secrets or custom Quadlet drop-in files. Store secret values and the contents of ee-builder-secrets.conf in a secure external location.

Listing secrets

sudo podman secret ls

Updating a secret

To update a secret value, remove the existing secret and create a new one. Write the value to a temporary file on tmpfs to avoid exposing it in the process list:

sudo podman secret rm portal_aap_token
temp_file=$(mktemp -p /dev/shm) && chmod 600 "$temp_file"
printf '%s' "new_token_value" > "$temp_file"
sudo podman secret create portal_aap_token "$temp_file"
rm -f "$temp_file"
sudo systemctl restart portal

Troubleshooting RHEL appliances

Common issues and solutions for deploying and managing Ansible automation portal RHEL appliances.

View logs and service status

Start troubleshooting by checking the status of all services and reviewing recent logs.

Check the status of all services:

$ sudo systemctl status portal postgres devtools

A service that failed to start shows active (failed) or inactive (dead).

View recent portal logs:

$ sudo journalctl -u portal -n 200 --no-pager

Check the bootc image status:

$ sudo bootc status

Portal services do not start

Symptom: The Ansible automation portal service is not running after boot.

Cause: The Ansible automation portal RHEL appliance requires Ansible Automation Platform credentials in the cloud-init user-data to complete setup. If you provided SSH keys but no aap: section, you can SSH in but Ansible automation portal services do not start.

Resolution:

  1. Check the portal service logs for errors:
    $ sudo journalctl -u portal -b --no-pager
  2. Verify that your cloud-init user-data includes the required aap: section with host_url, token, client_id, and client_secret.
  3. If the configuration is missing or incorrect, edit the configuration file directly:
    $ sudo vi /etc/portal/configs/app-config/app-config.production.yaml

    Update ansible.rhaap.baseUrl, auth.providers.rhaap.production.clientId, and other required values.

  4. If Ansible Automation Platform credentials need to be updated, use Podman secrets:
    $ temp_file=$(mktemp -p /dev/shm) && chmod 600 "$temp_file"
    $ printf '%s' "aap-token" > "$temp_file"
    $ sudo podman secret rm portal_aap_token
    $ sudo podman secret create portal_aap_token "$temp_file"
    $ rm -f "$temp_file"
    $ temp_file=$(mktemp -p /dev/shm) && chmod 600 "$temp_file"
    $ printf '%s' "oauth-client-secret" > "$temp_file"
    $ sudo podman secret rm portal_aap_oauth_client_secret
    $ sudo podman secret create portal_aap_oauth_client_secret "$temp_file"
    $ rm -f "$temp_file"
  5. Restart the Ansible automation portal service:
    $ sudo systemctl restart portal

OAuth login fails

Symptom: After clicking Sign in with RHAAP, the browser redirects back to the login page or Ansible Automation Platform returns "Invalid redirect_uri."

Cause: The OAuth redirect URI in Ansible Automation Platform does not match the Ansible automation portal user-accessible URL, or the app.baseUrl, backend.baseUrl, and backend.cors.origin values in the configuration file are not consistent with each other.

Resolution:

  1. Check the current user-accessible URL and CORS configuration:
    $ grep -E 'baseUrl|origin' /etc/portal/configs/app-config/app-config.production.yaml
  2. Verify that app.baseUrl, backend.baseUrl, and backend.cors.origin all use the same address.
  3. Verify that the OAuth application redirect URI in Ansible Automation Platform matches the format https://portal-address/api/auth/rhaap/handler/frame.
  4. If the values do not match, update either:
    • The OAuth redirect URI in Ansible Automation Platform (if the Ansible automation portal address is correct), or
    • The Ansible automation portal user-accessible URL and CORS origin in app-config.production.yaml (if the OAuth URI is correct).
  5. Restart the Ansible automation portal service after any configuration change:
    $ sudo systemctl restart portal

GitHub login appears instead of RHAAP

Symptom: The login page shows a "Sign in with GitHub" option instead of "Sign in with RHAAP," or both options appear.

Cause: The app.baseUrl, backend.baseUrl, and backend.cors.origin values in the configuration file do not match the URL used to access the Ansible automation portal RHEL appliance. This commonly happens when accessing the VM by IP address but the configuration uses a domain name, or vice versa. The CORS mismatch can cause the RHAAP provider to fail silently, falling back to a GitHub provider if one is configured.

Resolution:

  1. Check the configured authentication providers:
    $ grep -A 5 'auth:' /etc/portal/configs/app-config/app-config.production.yaml
  2. Verify that the auth.providers section contains rhaap and does not contain github. If a github provider is present, remove it.
  3. Verify that app.baseUrl, backend.baseUrl, and backend.cors.origin all match the URL you use to access the Ansible automation portal RHEL appliance in your browser:
    $ grep -E 'baseUrl|origin' /etc/portal/configs/app-config/app-config.production.yaml
  4. Restart the Ansible automation portal service after any configuration change:
    $ sudo systemctl restart portal

Login fails with a 500 error

Symptom: After clicking Sign in with RHAAP, the browser shows a 500 Internal Server Error or redirects to an error page instead of completing the login.

Cause: A 500 error during login typically indicates that the Ansible Automation Platform API token or OAuth client secret is invalid, expired, or missing. The Ansible automation portal cannot authenticate with the Ansible Automation Platform instance.

Resolution:

  1. Check the portal logs for authentication errors:
    $ sudo journalctl -u portal -n 100 --no-pager | grep -i -E 'auth|oauth|401|403|500|error'
  2. Verify that the required Podman secrets exist:
    $ sudo podman secret ls | grep -E 'aap_token|oauth'

    You should see both portal_aap_token and portal_aap_oauth_client_secret listed. If either is missing or the values need to be updated, recreate them:

    $ temp_file=$(mktemp -p /dev/shm) && chmod 600 "$temp_file"
    $ printf '%s' "new-aap-token" > "$temp_file"
    $ sudo podman secret rm portal_aap_token
    $ sudo podman secret create portal_aap_token "$temp_file"
    $ rm -f "$temp_file"
  3. Verify that the Ansible Automation Platform instance is reachable from the appliance:
    $ curl -sk https://aap-host/api/v2/ping/
  4. Verify that the OAuth client ID in the configuration matches the OAuth application in Ansible Automation Platform:
    $ grep clientId /etc/portal/configs/app-config/app-config.production.yaml
  5. Restart the Ansible automation portal service after any changes:
    $ sudo systemctl restart portal

Cannot SSH to the VM

Symptom: SSH connection refused or permission denied.

Cause: The appliance enforces SSH key-only authentication. Password login is disabled.

Resolution:

  • Verify that your SSH private key matches the public key you provided in the cloud-init user-data.
  • Verify that you are using the correct username from your cloud-init configuration.

If you have lost access to your SSH key, use platform-specific recovery:

  • KVM: Access the VM console with virsh console vm-name and add a new SSH key.
  • Red Hat OpenShift Virtualization: Access the VM console with virtctl console vm-name -n namespace.
  • VMware vSphere: Use the vSphere console with systemd.unit=rescue.target boot parameter to add a new SSH key.

VM is inaccessible

Symptom: The VM was deployed without cloud-init user-data. No SSH keys or Ansible Automation Platform credentials are configured.

Cause: The appliance has no default password. Without cloud-init configuration, the VM is not accessible.

Resolution: Redeploy the VM with a cloud-init configuration attached. See Configure the appliance at first boot.

Red Hat OpenShift Virtualization issues

Symptom: Upload, boot, or scheduling failures when deploying on Red Hat OpenShift Virtualization.

Resolution:

Upload fails with "effective image size is larger than available storage"
Increase --size (for example, from 40 Gi to 50 Gi). Check the virtual size with qemu-img info disk.qcow2.
Upload hangs at "Waiting for PVC upload pod to be ready"
The storage class uses WaitForFirstConsumer binding. Add --force-bind to the virtctl command.
VM shows "Boot failed: not a bootable disk"
The disk image was not properly converted during upload. Verify the upload completed with "Processing completed successfully." If processing was interrupted, delete the DataVolume and PVC and re-upload.
VM stuck in Scheduling with "Insufficient memory"
Reduce the VM memory request or add cluster resources.

VMware vSphere troubleshooting

Disk conversion fails with vmkfstools
  • Verify that you have SSH access to the ESXi host.
  • Verify that the disk.vmdk file was uploaded successfully to the datastore.
  • Check that you have sufficient permissions to run vmkfstools on the ESXi host.
  • Verify that there is sufficient free space on the datastore for the converted disk.
Virtual machine fails to boot after attaching the disk
  • Verify that you selected the correct disk file.
  • Verify that the disk is attached to the correct SCSI controller and bus.
  • Check the virtual machine boot order settings and ensure the hard disk is the first boot device.
Cannot upload disk image to datastore
  • Verify that your user account has permissions to upload files to the datastore.
  • Check that there is sufficient free space on the datastore.
  • Verify that the vSphere web client is properly connected.

Collect diagnostic information

If an issue persists, collect the following information before contacting support:

$ sudo systemctl status portal postgres devtools > service-status.txt
$ sudo journalctl -u portal -n 200 > portal-logs.txt
$ sudo journalctl -u postgres -n 100 > postgres-logs.txt
$ sudo journalctl -u devtools -n 100 > devtools-logs.txt
$ sudo bootc status > bootc-status.txt
$ cat /etc/os-release > os-release.txt

SSH key recovery

After initial configuration, the admin user account is locked and console login is disabled. If you lose SSH access, use one of the following recovery methods for your deployment environment.

Important

Back up your SSH private key before configuring the appliance. If you lose your SSH key, you must use infrastructure-level access (hypervisor console, cloud provider tools) to recover.

Recovery on Red Hat OpenShift Virtualization

  1. Access the virtual machine console through the Red Hat OpenShift Container Platform web console.
  2. Reboot the virtual machine.
  3. At the GRUB boot menu, press e to edit boot parameters.
  4. Add init=/bin/bash to the end of the kernel line.
  5. Press Ctrl+X to boot into an emergency shell.
  6. Remount the filesystem and add a new SSH key:
    mount -o remount,rw /
    passwd -u admin
    mkdir -p /home/admin/.ssh
    echo "your_ssh_public_key" >> /home/admin/.ssh/authorized_keys
    chown -R admin:admin /home/admin/.ssh
    chmod 600 /home/admin/.ssh/authorized_keys
    restorecon -R /home/admin/.ssh
    passwd -l admin
    exec /sbin/init

Recovery on VMware vSphere

  1. Open the virtual machine console in vCenter.
  2. Reboot the virtual machine.
  3. At the GRUB boot menu, press e to edit boot parameters.
  4. Add init=/bin/bash to the end of the kernel line.
  5. Press Ctrl+X to boot into an emergency shell.
  6. Remount the filesystem and add a new SSH key:
    mount -o remount,rw /
    passwd -u admin
    mkdir -p /home/admin/.ssh
    echo "your_ssh_public_key" >> /home/admin/.ssh/authorized_keys
    chown -R admin:admin /home/admin/.ssh
    chmod 600 /home/admin/.ssh/authorized_keys
    restorecon -R /home/admin/.ssh
    passwd -l admin
    exec /sbin/init

Recovery on KVM

Shut down the virtual machine and mount the QCOW2 image directly to add a new SSH key:

$ sudo modprobe nbd max_part=8
$ sudo qemu-nbd --connect=/dev/nbd0 disk.qcow2
$ sudo fdisk -l /dev/nbd0
$ sudo mount /dev/nbd0pN /mnt
$ sudo mkdir -p /mnt/home/admin/.ssh
$ echo "your_ssh_public_key" | sudo tee -a /mnt/home/admin/.ssh/authorized_keys
$ sudo chown 1000:1000 /mnt/home/admin/.ssh/authorized_keys
$ sudo chmod 600 /mnt/home/admin/.ssh/authorized_keys
$ sudo umount /mnt
$ sudo qemu-nbd --disconnect /dev/nbd0

Where:

  • fdisk -l /dev/nbd0 lists partitions to identify the root filesystem. The root partition is typically the largest partition.
  • Replace N in /dev/nbd0pN with the correct root partition number from the fdisk output.

Account locking behavior

When the admin account is locked with passwd -l, the system adds a ! prefix to the password hash in /etc/shadow. This disables all password-based authentication (console login, SSH password auth) while SSH key authentication continues to work.

To temporarily unlock the account for recovery, use passwd -u admin. After adding a new SSH key, lock the account again with passwd -l admin for security.