AWX is the open source upstream of Red Hat Ansible Automation Platform (formerly Ansible Tower). It gives Ansible a web interface, a REST API, role-based access control, stored credentials and a history of every job run. AWX is installed on Kubernetes through the AWX Operator. In this tutorial you will set up a single-node K3s cluster on Ubuntu 24.04, deploy AWX with the operator, and run your first playbook from the web interface.
Prerequisites
To follow this tutorial, you need:
- A server running Ubuntu 24.04 LTS with at least 4 vCPUs, 8 GB of RAM and 40 GB of disk, for example a CubePath VPS. AWX runs several containers plus PostgreSQL, and smaller servers leave pods stuck in
Pending. - A non-root user with
sudoprivileges. - Git installed (
sudo apt install git), used by kubectl to fetch the operator manifests. - An SSH client on your workstation, used to reach the AWX interface through a tunnel.
- Optionally, another server that AWX will manage, reachable over SSH with a key.
NoteThe older Docker Compose installation of AWX is only meant for AWX development. The AWX Operator on Kubernetes is the supported installation method.
Step 1 - Installing K3s
K3s is a lightweight, certified Kubernetes distribution that installs as a single binary, which makes it a good fit for a one-server AWX. Its official installer is a script; download it and review it before running it:
curl -sfL https://get.k3s.io -o k3s-install.sh
less k3s-install.sh
Run the installer. It installs K3s as a systemd service and creates a kubectl command:
sudo sh k3s-install.sh
The cluster configuration is readable only by root. Copy it to your user so you can run kubectl without sudo:
mkdir -p ~/.kube
sudo cp /etc/rancher/k3s/k3s.yaml ~/.kube/config
sudo chown "$USER":"$USER" ~/.kube/config
chmod 600 ~/.kube/config
echo 'export KUBECONFIG=$HOME/.kube/config' >> ~/.bashrc
source ~/.bashrc
Check that the node is ready:
kubectl get nodes
NAME STATUS ROLES AGE VERSION
awx01 Ready control-plane,master 45s v1.33.4+k3s1
K3s includes a local storage provisioner, so the PostgreSQL volume that AWX requests is created automatically on the server's disk.
Step 2 - Deploying the AWX Operator
The operator is deployed with Kustomize, which is built into kubectl. Look up the latest release on the AWX Operator releases page and use that tag in the two places below. This guide uses 2.19.1 as an example.
Create a working directory and the Kustomize file:
mkdir -p ~/awx
cd ~/awx
nano kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- github.com/ansible/awx-operator/config/default?ref=2.19.1
images:
- name: quay.io/ansible/awx-operator
newTag: 2.19.1
namespace: awx
Apply it. Kustomize downloads the manifests from GitHub and creates the awx namespace, the custom resource definitions and the operator deployment:
kubectl apply -k .
Wait until the operator pod is running:
kubectl get pods -n awx
NAME READY STATUS RESTARTS AGE
awx-operator-controller-manager-6c58d8b4f7-kq2xz 2/2 Running 0 60s
Step 3 - Creating the AWX instance
The operator watches for resources of kind AWX and builds everything each one needs: the web and task deployments, a PostgreSQL database and the services. Describe your instance in a file:
nano awx.yaml
apiVersion: awx.ansible.com/v1beta1
kind: AWX
metadata:
name: awx
spec:
service_type: ClusterIP
ClusterIP keeps the web interface reachable only from inside the server. You will open it through an SSH tunnel in the next step, so the admin login is never exposed to the Internet over plain HTTP.
Add the file to the resources in kustomization.yaml:
resources:
- github.com/ansible/awx-operator/config/default?ref=2.19.1
- awx.yaml
Apply the configuration again:
kubectl apply -k .
The deployment takes several minutes, because the operator pulls the images, starts PostgreSQL and runs the database migrations. Follow its progress in the operator log:
kubectl logs -f deployment/awx-operator-controller-manager -c awx-manager -n awx
When the log shows a play recap with failed=0, press Ctrl+C and list the pods:
kubectl get pods -n awx
NAME READY STATUS RESTARTS AGE
awx-migration-24.6.1-7mqzf 0/1 Completed 0 4m
awx-operator-controller-manager-6c58d8b4f7-kq2xz 2/2 Running 0 9m
awx-postgres-15-0 1/1 Running 0 5m
awx-task-7b9d8f6c5d-l4xjp 4/4 Running 0 4m
awx-web-5f8c9b7d6-9wz2m 3/3 Running 0 4m
All pods must be Running, except the migration job, which ends as Completed.
Step 4 - Logging in to the web interface
The operator generates the password for the admin user and stores it in a Kubernetes secret named after your instance:
kubectl get secret awx-admin-password -n awx -o jsonpath='{.data.password}' | base64 --decode; echo
Copy the password. Then forward a local port on the server to the AWX web service:
kubectl port-forward service/awx-service -n awx 8080:80
Leave that command running. On your workstation, open an SSH tunnel to that port in another terminal:
ssh -L 8080:localhost:8080 your_user@your_server_ip
Browse to http://localhost:8080 on your workstation and log in as admin with the password from the secret. The AWX dashboard opens, showing no hosts or jobs yet.
TipFor permanent access by your team, expose AWX through an Ingress with a TLS certificate instead of the tunnel. The operator supports this through the
ingress_type,hostnameandingress_tls_secretfields of theAWXresource.
Step 5 - Adding a machine credential
AWX stores secrets as credentials and injects them into jobs, so playbooks never contain passwords or keys. To manage a server over SSH, create a Machine credential:
- Go to Resources > Credentials and click Add.
- Name it
Web servers SSHand choose the credential type Machine. - Enter the remote Username (for example
your_user) and paste the private key in SSH Private Key. - If the user needs a password for
sudo, set Privilege Escalation Method tosudoand fill in Privilege Escalation Password. - Click Save.
The key is encrypted in the AWX database and is never shown again in the interface.
Step 6 - Creating an inventory
An inventory lists the hosts AWX can target:
- Go to Resources > Inventories, click Add and choose Add inventory.
- Name it
Web servers, keep theDefaultorganization and click Save. - Open the Hosts tab, click Add, enter your managed server's IP address or hostname as the name, and save.
If the host's SSH port or address differs from its name, add it as a variable in the host's Variables field, for example ansible_host: your_server_ip.
Step 7 - Creating a project from Git
A project points AWX to a Git repository that contains playbooks. AWX clones it and updates it before each job if you choose so. For a first test, use the public sample repository published by the Ansible project:
- Go to Resources > Projects and click Add.
- Name it
Samples, choose Source Control TypeGit. - Set Source Control URL to
https://github.com/ansible/ansible-tower-samples. - Enable Update Revision on Launch and click Save.
AWX syncs the project immediately. The status icon next to the project turns green when the clone succeeds. For a private repository, create a Source Control credential with a deploy key or token and select it in the project.
Step 8 - Running a job template
A job template combines a project, a playbook, an inventory and credentials into something anyone with permission can launch:
- Go to Resources > Templates, click Add and choose Add job template.
- Name it
Hello world. - Select the inventory
Web servers, the projectSamplesand the playbookhello_world.yml. - Under Credentials, select
Web servers SSH. - Click Save, then Launch.
AWX opens the job output, which streams the Ansible run live:
PLAY [Hello World Sample] ******************************************************
TASK [Gathering Facts] *********************************************************
ok: [203.0.113.20]
TASK [Hello Message] ***********************************************************
ok: [203.0.113.20] => {
"msg": "Hello World!"
}
PLAY RECAP *********************************************************************
203.0.113.20 : ok=2 changed=0 unreachable=0 failed=0 skipped=0
A job status of Successful confirms that AWX reached the server with the stored credential. Every run stays in Views > Jobs with its full output, who launched it and when.
Step 9 - Giving access to other users
Avoid sharing the admin account. AWX permissions are granted on objects (templates, inventories, projects, credentials) to users or teams:
- Go to Access > Users and create a user for each person.
- Go to Access > Teams, create a team such as
Operators, and add the users to it. - Open the
Hello worldtemplate, go to its Access tab (or User and Team Access in newer versions) and grant the team the Execute role.
Members of the team can now launch that template and read its output, but cannot see the SSH key or change the playbook, inventory or credentials.
Troubleshooting
- Pods stay in
Pending: the server does not have enough CPU or memory. Check the reason withkubectl describe pod <pod_name> -n awxand resize the server. kubectl apply -k .fails to fetch the operator: Git is missing or the server cannot reach GitHub. Install Git and check outbound HTTPS.- The project sync fails: open the sync job under Views > Jobs to see the Git error; private repositories need a Source Control credential.
- Jobs fail with
UNREACHABLE: the managed server does not accept the key or blocks SSH from the AWX server. Test withssh -i key your_user@hostfrom the AWX server itself. - The operator log shows errors after an upgrade: operator releases must be applied in order. Read the release notes on GitHub before changing the tag in
kustomization.yaml.
Conclusion
You installed K3s and the AWX Operator on Ubuntu 24.04, deployed an AWX instance, and ran a playbook from a Git project with a stored credential, inventory and job template. Next, point a project to your own playbook repository, schedule recurring jobs from the template's Schedules tab, and back up the instance regularly with the operator's AWXBackup resource before upgrades.
