AWX (Ansible Tower)
Deployment rootless
1. Prepare the host
Prerequisites once as root
Install Podman (needs podman 4.3 or newer; Ubuntu 22.04 ships 3.4 and is too old, use 24.04)
apt update && apt install -y podman
Create user (if not existing)
useradd -m -s /bin/bash awx passwd awx
Enable linger (services keep running after logout and start after reboot)
loginctl enable-linger awx
Switch to deployment user
su - awx
Use su - with the dash — this creates a proper login shell as awx. Without the dash, root environment variables carry over and rootless Podman will not work correctly.
Fix environment for rootless systemd (new users only — skip if already set)
Required once so systemctl --user works in non-login sessions.
cat << 'EOF' >> ~/.bashrc # Fix for systemd user services (rootless Podman/systemctl) export XDG_RUNTIME_DIR=/run/user/$(id -u) export DBUS_SESSION_BUS_ADDRESS=unix:path=$XDG_RUNTIME_DIR/bus EOF source ~/.bashrc
2. Choose a format and deploy
The same pod in four forms. Pick one and follow only its steps.
Each tab says which podman it needs. Check yours with podman --version:
Debian 12 ships 4.3, Ubuntu 24.04 4.9, Debian 13 5.4, Fedora 5.8, Arch 6.x.
Kubernetes YAML for podman kube play, started by systemd through a Quadlet .kube unit (podman 4.4+; older podman like Debian 12 uses podman-kube@, see the version check below).
Kubernetes YAML
apiVersion: v1
kind: Pod
metadata:
name: awx
labels:
app: awx
spec:
restartPolicy: Always
containers:
- name: awx-web
image: quay.io/ansible/awx:latest
imagePullPolicy: Always
ports:
- containerPort: 8052
hostPort: 8052
env:
- name: DATABASE_USER
value: awx
- name: DATABASE_PASSWORD
value: Bb3GfGNhP_tp2j7MeCUDUw
- name: DATABASE_NAME
value: awx
- name: DATABASE_HOST
value: 127.0.0.1
- name: DATABASE_PORT
value: '5432'
- name: REDIS_HOST
value: 127.0.0.1
- name: REDIS_PORT
value: '6379'
- name: SECRET_KEY
value: sH-5EVaeQo7PL4TV7xoudA
- name: AWX_ADMIN_USER
value: admin
- name: AWX_ADMIN_PASSWORD
value: Bb3GfGNhP_tp2j7MeCUDUw
volumeMounts:
- name: vol-0
mountPath: /etc/tower
- name: vol-1
mountPath: /etc/nginx
- name: vol-2
mountPath: /var/lib/awx/projects
command:
- /bin/sh
args:
- -c
- until python3 -c "import socket;s=socket.create_connection(('${DATABASE_HOST:-127.0.0.1}',${DATABASE_PORT:-5432}),1);s.close()"
2>/dev/null; do echo 'Waiting for postgres...'; sleep 3; done && awx-manage
migrate && DJANGO_SUPERUSER_PASSWORD=${AWX_ADMIN_PASSWORD:-Bb3GfGNhP_tp2j7MeCUDUw}
awx-manage createsuperuser --noinput --username ${AWX_ADMIN_USER:-admin} --email
admin@localhost 2>/dev/null || true && exec /usr/bin/launch_awx_web.sh
- name: awx-task
image: quay.io/ansible/awx:latest
imagePullPolicy: Always
env:
- name: DATABASE_USER
value: awx
- name: DATABASE_PASSWORD
value: Bb3GfGNhP_tp2j7MeCUDUw
- name: DATABASE_NAME
value: awx
- name: DATABASE_HOST
value: 127.0.0.1
- name: DATABASE_PORT
value: '5432'
- name: REDIS_HOST
value: 127.0.0.1
- name: REDIS_PORT
value: '6379'
- name: SECRET_KEY
value: sH-5EVaeQo7PL4TV7xoudA
- name: AWX_ADMIN_USER
value: admin
- name: AWX_ADMIN_PASSWORD
value: Bb3GfGNhP_tp2j7MeCUDUw
volumeMounts:
- name: vol-0
mountPath: /etc/tower
- name: vol-2
mountPath: /var/lib/awx/projects
command:
- /usr/bin/launch_awx_task.sh
- name: postgres
image: docker.io/postgres:15
env:
- name: POSTGRES_USER
value: awx
- name: POSTGRES_PASSWORD
value: Bb3GfGNhP_tp2j7MeCUDUw
- name: POSTGRES_DB
value: awx
volumeMounts:
- name: vol-3
mountPath: /var/lib/postgresql/data
securityContext:
runAsUser: 999
runAsGroup: 999
- name: redis
image: docker.io/redis:7-alpine
volumeMounts:
- name: vol-4
mountPath: /data
args:
- redis-server
- --appendonly
- 'yes'
initContainers:
# Auto-generated init container — do not edit manually.
# settings.py: required by AWX to read DB/Redis credentials from environment variables above.
# nginx.conf: reverse proxy config for the AWX web UI (port 8052 -> uWSGI on 8050).
# uwsgi.ini: copied directly from the AWX image — updates automatically with new image versions.
- name: awx-init
image: quay.io/ansible/awx:latest
imagePullPolicy: Always
volumeMounts:
- name: vol-0
mountPath: /init-tower
- name: vol-1
mountPath: /init-nginx
command:
- sh
args:
- -c
- cp -r /etc/nginx/. /init-nginx/ && echo aW1wb3J0IG9zCgpEQVRBQkFTRVMgPSB7CiAgICAnZGVmYXVsdCc6IHsKICAgICAgICAnQVRPTUlDX1JFUVVFU1RTJzogVHJ1ZSwKICAgICAgICAnRU5HSU5FJzogJ2F3eC5tYWluLmRiLnByb2ZpbGVkX3BnJywKICAgICAgICAnTkFNRSc6IG9zLmVudmlyb24uZ2V0KCdEQVRBQkFTRV9OQU1FJywgJ2F3eCcpLAogICAgICAgICdVU0VSJzogb3MuZW52aXJvbi5nZXQoJ0RBVEFCQVNFX1VTRVInLCAnYXd4JyksCiAgICAgICAgJ1BBU1NXT1JEJzogb3MuZW52aXJvbi5nZXQoJ0RBVEFCQVNFX1BBU1NXT1JEJywgJ2NoYW5nZW1lJyksCiAgICAgICAgJ0hPU1QnOiBvcy5lbnZpcm9uLmdldCgnREFUQUJBU0VfSE9TVCcsICcxMjcuMC4wLjEnKSwKICAgICAgICAnUE9SVCc6IG9zLmVudmlyb24uZ2V0KCdEQVRBQkFTRV9QT1JUJywgJzU0MzInKSwKICAgIH0KfQpBTExPV0VEX0hPU1RTID0gWycqJ10KU0VDUkVUX0tFWSA9IG9zLmVudmlyb24uZ2V0KCdTRUNSRVRfS0VZJywgJ2NoYW5nZW1lJykKREpBTkdPX1JFRElTX0lHTk9SRV9FWENFUFRJT05TID0gVHJ1ZQoKX3JlZGlzX2hvc3QgPSBvcy5lbnZpcm9uLmdldCgnUkVESVNfSE9TVCcsICcxMjcuMC4wLjEnKQpfcmVkaXNfcG9ydCA9IG9zLmVudmlyb24uZ2V0KCdSRURJU19QT1JUJywgJzYzNzknKQpfcmVkaXNfdXJsID0gJ3JlZGlzOi8ve306e30nLmZvcm1hdChfcmVkaXNfaG9zdCwgX3JlZGlzX3BvcnQpCgpDQUNIRVMgPSB7CiAgICAnZGVmYXVsdCc6IHsKICAgICAgICAnQkFDS0VORCc6ICdhd3gubWFpbi5jYWNoZS5BV1hSZWRpc0NhY2hlJywKICAgICAgICAnTE9DQVRJT04nOiAne30vMScuZm9ybWF0KF9yZWRpc191cmwpLAogICAgfQp9CkNIQU5ORUxfTEFZRVJTID0gewogICAgJ2RlZmF1bHQnOiB7CiAgICAgICAgJ0JBQ0tFTkQnOiAnY2hhbm5lbHNfcmVkaXMuY29yZS5SZWRpc0NoYW5uZWxMYXllcicsCiAgICAgICAgJ0NPTkZJRyc6IHsKICAgICAgICAgICAgJ2hvc3RzJzogWyhfcmVkaXNfaG9zdCwgaW50KF9yZWRpc19wb3J0KSldLAogICAgICAgICAgICAnY2FwYWNpdHknOiAxMDAwMCwKICAgICAgICAgICAgJ2dyb3VwX2V4cGlyeSc6IDE1Nzc4NDc2MCwKICAgICAgICB9CiAgICB9Cn0KQlJPS0VSX1VSTCA9IF9yZWRpc191cmwK
| base64 -d > /init-tower/settings.py && cp /etc/tower/uwsgi.ini /init-tower/uwsgi.ini
&& echo d29ya2VyX3Byb2Nlc3NlcyBhdXRvOwplcnJvcl9sb2cgL2Rldi9zdGRlcnIgd2FybjsKcGlkIC90bXAvbmdpbngucGlkOwoKaW5jbHVkZSAvdXNyL3NoYXJlL25naW54L21vZHVsZXMvKi5jb25mOwoKZXZlbnRzIHsKICAgIHdvcmtlcl9jb25uZWN0aW9ucyAxMDI0Owp9CgpodHRwIHsKICAgIGNsaWVudF9ib2R5X3RlbXBfcGF0aCAvdG1wL25naW54LWNsaWVudC1ib2R5OwogICAgcHJveHlfdGVtcF9wYXRoIC90bXAvbmdpbngtcHJveHk7CiAgICBmYXN0Y2dpX3RlbXBfcGF0aCAvdG1wL25naW54LWZhc3RjZ2k7CiAgICB1d3NnaV90ZW1wX3BhdGggL3RtcC9uZ2lueC11d3NnaTsKICAgIHNjZ2lfdGVtcF9wYXRoIC90bXAvbmdpbngtc2NnaTsKICAgIGluY2x1ZGUgL2V0Yy9uZ2lueC9taW1lLnR5cGVzOwogICAgZGVmYXVsdF90eXBlIGFwcGxpY2F0aW9uL29jdGV0LXN0cmVhbTsKICAgIGFjY2Vzc19sb2cgL2Rldi9zdGRvdXQ7CiAgICBzZW5kZmlsZSBvbjsKICAgIGtlZXBhbGl2ZV90aW1lb3V0IDY1OwoKICAgIHNlcnZlciB7CiAgICAgICAgbGlzdGVuIDgwNTIgZGVmYXVsdF9zZXJ2ZXI7CiAgICAgICAgc2VydmVyX25hbWUgXzsKICAgICAgICBjbGllbnRfbWF4X2JvZHlfc2l6ZSAwOwoKICAgICAgICBsb2NhdGlvbiB+IF4vd2Vic29ja2V0IHsKICAgICAgICAgICAgcHJveHlfcGFzcyBodHRwOi8vMTI3LjAuMC4xOjgwNTE7CiAgICAgICAgICAgIHByb3h5X2h0dHBfdmVyc2lvbiAxLjE7CiAgICAgICAgICAgIHByb3h5X3NldF9oZWFkZXIgVXBncmFkZSAkaHR0cF91cGdyYWRlOwogICAgICAgICAgICBwcm94eV9zZXRfaGVhZGVyIENvbm5lY3Rpb24gIlVwZ3JhZGUiOwogICAgICAgICAgICBwcm94eV9jb25uZWN0X3RpbWVvdXQgNzVzOwogICAgICAgICAgICBwcm94eV9yZWFkX3RpbWVvdXQgMTIwczsKICAgICAgICB9CgogICAgICAgIGxvY2F0aW9uIC9zdGF0aWMvIHsKICAgICAgICAgICAgYWxpYXMgL3Zhci9saWIvYXd4L3B1YmxpYy9zdGF0aWMvOwogICAgICAgIH0KCiAgICAgICAgbG9jYXRpb24gLyB7CiAgICAgICAgICAgIHV3c2dpX3JlYWRfdGltZW91dCAxMjBzOwogICAgICAgICAgICB1d3NnaV9wYXNzIDEyNy4wLjAuMTo4MDUwOwogICAgICAgICAgICBpbmNsdWRlIC9ldGMvbmdpbngvdXdzZ2lfcGFyYW1zOwogICAgICAgICAgICBwcm94eV9zZXRfaGVhZGVyIFgtRm9yd2FyZGVkLUZvciAkcHJveHlfYWRkX3hfZm9yd2FyZGVkX2ZvcjsKICAgICAgICAgICAgdXdzZ2lfcGFyYW0gSFRUUF9YX0ZPUldBUkRFRF9GT1IgJHByb3h5X2FkZF94X2ZvcndhcmRlZF9mb3I7CiAgICAgICAgfQogICAgfQp9Cg==
| base64 -d > /init-nginx/nginx.conf
volumes:
- name: vol-0
persistentVolumeClaim:
claimName: awx-tower
- name: vol-1
persistentVolumeClaim:
claimName: awx-nginx
- name: vol-2
persistentVolumeClaim:
claimName: awx-projects
- name: vol-3
persistentVolumeClaim:
claimName: awx-db
- name: vol-4
persistentVolumeClaim:
claimName: awx-redis
Save the YAML file
mkdir -p ~/.config/containers/ nano ~/.config/containers/awx.yaml
Test the pod (without autostart)
podman kube play ~/.config/containers/awx.yaml # Check status: podman pod ps && podman ps # Stop: podman kube down ~/.config/containers/awx.yaml
Check your podman version
podman --version
4.4 or newer: continue with step 3 below.
Older, e.g. 4.3 on Debian 12? There is no Quadlet yet: use podman's own podman-kube@ service instead of steps 3–5
systemctl --user enable --now podman-kube@$(systemd-escape ~/.config/containers/awx.yaml).service # Status & logs: systemctl --user status podman-kube@$(systemd-escape ~/.config/containers/awx.yaml).service journalctl --user -u podman-kube@$(systemd-escape ~/.config/containers/awx.yaml).service -f
The day-to-day commands below have a block for this service.
Create Quadlet .kube file
[Unit] Description=awx pod After=network-online.target Wants=network-online.target [Kube] Yaml=%h/.config/containers/awx.yaml [Service] Restart=always [Install] WantedBy=default.target
%h is a systemd home-directory specifier — do not replace it with ~/.
Save to ~/.config/containers/systemd/:
mkdir -p ~/.config/containers/systemd/ nano ~/.config/containers/systemd/awx.kube
Start systemd service
systemctl --user daemon-reload systemctl --user start awx.service
Status & Logs
systemctl --user status awx.service journalctl --user -u awx.service -f podman pod ps podman ps
Enable automatic image updates optional
Requires AutoUpdate=registry in the .kube file. Podman then checks for new images and restarts the pod automatically:
systemctl --user enable --now podman.socket systemctl --user daemon-reload systemctl --user enable --now podman-auto-update.timer # Check status: systemctl --user status podman-auto-update.timer # Trigger manually: podman auto-update
Day-to-day logs, restart, update, remove (click to open)
Logs & shell into a container
podman logs -f awx-awx-web podman logs -f awx-awx-task podman logs -f awx-postgres podman logs -f awx-redis podman exec -it awx-awx-web /bin/sh
Restart
systemctl --user restart awx.service
Update an image by hand
Pull the new version, the restart recreates the containers from it:
podman pull <image>:<tag> systemctl --user restart awx.service
Stop & remove
Stop through systemd, otherwise Restart=always brings the pod back. To remove it for good, delete the unit files and reload:
systemctl --user stop awx.service rm ~/.config/containers/systemd/awx.kube systemctl --user daemon-reload
podman older than 4.4 (podman-kube@ from step 3)
systemctl --user restart podman-kube@$(systemd-escape ~/.config/containers/awx.yaml).service # Update an image: pull, then restart as above podman pull <image>:<tag> # Stop and remove from autostart: systemctl --user disable --now podman-kube@$(systemd-escape ~/.config/containers/awx.yaml).service
Delete the data — permanent, only after stop & remove
podman volume rm awx-tower podman volume rm awx-nginx podman volume rm awx-projects podman volume rm awx-db podman volume rm awx-redis
Native systemd units without the Kubernetes YAML: one .pod plus one .container per container.
Each container becomes its own systemd service (restart, logs and ordering per container).
Needs podman 5.0 or newer — Debian 12 ships 4.3, use the Kube YAML tab there.
Save the unit files
[Unit] Description=awx pod [Pod] PodName=awx PodmanArgs=--exit-policy=continue PublishPort=8052:8052
[Unit] Description=awx-awx-init container [Container] Image=quay.io/ansible/awx:latest Pod=awx.pod ContainerName=awx-awx-init Pull=always Volume=awx-tower:/init-tower:Z Volume=awx-nginx:/init-nginx:Z Entrypoint=sh Exec=-c "cp -r /etc/nginx/. /init-nginx/ && echo aW1wb3J0IG9zCgpEQVRBQkFTRVMgPSB7CiAgICAnZGVmYXVsdCc6IHsKICAgICAgICAnQVRPTUlDX1JFUVVFU1RTJzogVHJ1ZSwKICAgICAgICAnRU5HSU5FJzogJ2F3eC5tYWluLmRiLnByb2ZpbGVkX3BnJywKICAgICAgICAnTkFNRSc6IG9zLmVudmlyb24uZ2V0KCdEQVRBQkFTRV9OQU1FJywgJ2F3eCcpLAogICAgICAgICdVU0VSJzogb3MuZW52aXJvbi5nZXQoJ0RBVEFCQVNFX1VTRVInLCAnYXd4JyksCiAgICAgICAgJ1BBU1NXT1JEJzogb3MuZW52aXJvbi5nZXQoJ0RBVEFCQVNFX1BBU1NXT1JEJywgJ2NoYW5nZW1lJyksCiAgICAgICAgJ0hPU1QnOiBvcy5lbnZpcm9uLmdldCgnREFUQUJBU0VfSE9TVCcsICcxMjcuMC4wLjEnKSwKICAgICAgICAnUE9SVCc6IG9zLmVudmlyb24uZ2V0KCdEQVRBQkFTRV9QT1JUJywgJzU0MzInKSwKICAgIH0KfQpBTExPV0VEX0hPU1RTID0gWycqJ10KU0VDUkVUX0tFWSA9IG9zLmVudmlyb24uZ2V0KCdTRUNSRVRfS0VZJywgJ2NoYW5nZW1lJykKREpBTkdPX1JFRElTX0lHTk9SRV9FWENFUFRJT05TID0gVHJ1ZQoKX3JlZGlzX2hvc3QgPSBvcy5lbnZpcm9uLmdldCgnUkVESVNfSE9TVCcsICcxMjcuMC4wLjEnKQpfcmVkaXNfcG9ydCA9IG9zLmVudmlyb24uZ2V0KCdSRURJU19QT1JUJywgJzYzNzknKQpfcmVkaXNfdXJsID0gJ3JlZGlzOi8ve306e30nLmZvcm1hdChfcmVkaXNfaG9zdCwgX3JlZGlzX3BvcnQpCgpDQUNIRVMgPSB7CiAgICAnZGVmYXVsdCc6IHsKICAgICAgICAnQkFDS0VORCc6ICdhd3gubWFpbi5jYWNoZS5BV1hSZWRpc0NhY2hlJywKICAgICAgICAnTE9DQVRJT04nOiAne30vMScuZm9ybWF0KF9yZWRpc191cmwpLAogICAgfQp9CkNIQU5ORUxfTEFZRVJTID0gewogICAgJ2RlZmF1bHQnOiB7CiAgICAgICAgJ0JBQ0tFTkQnOiAnY2hhbm5lbHNfcmVkaXMuY29yZS5SZWRpc0NoYW5uZWxMYXllcicsCiAgICAgICAgJ0NPTkZJRyc6IHsKICAgICAgICAgICAgJ2hvc3RzJzogWyhfcmVkaXNfaG9zdCwgaW50KF9yZWRpc19wb3J0KSldLAogICAgICAgICAgICAnY2FwYWNpdHknOiAxMDAwMCwKICAgICAgICAgICAgJ2dyb3VwX2V4cGlyeSc6IDE1Nzc4NDc2MCwKICAgICAgICB9CiAgICB9Cn0KQlJPS0VSX1VSTCA9IF9yZWRpc191cmwK | base64 -d > /init-tower/settings.py && cp /etc/tower/uwsgi.ini /init-tower/uwsgi.ini && echo d29ya2VyX3Byb2Nlc3NlcyBhdXRvOwplcnJvcl9sb2cgL2Rldi9zdGRlcnIgd2FybjsKcGlkIC90bXAvbmdpbngucGlkOwoKaW5jbHVkZSAvdXNyL3NoYXJlL25naW54L21vZHVsZXMvKi5jb25mOwoKZXZlbnRzIHsKICAgIHdvcmtlcl9jb25uZWN0aW9ucyAxMDI0Owp9CgpodHRwIHsKICAgIGNsaWVudF9ib2R5X3RlbXBfcGF0aCAvdG1wL25naW54LWNsaWVudC1ib2R5OwogICAgcHJveHlfdGVtcF9wYXRoIC90bXAvbmdpbngtcHJveHk7CiAgICBmYXN0Y2dpX3RlbXBfcGF0aCAvdG1wL25naW54LWZhc3RjZ2k7CiAgICB1d3NnaV90ZW1wX3BhdGggL3RtcC9uZ2lueC11d3NnaTsKICAgIHNjZ2lfdGVtcF9wYXRoIC90bXAvbmdpbngtc2NnaTsKICAgIGluY2x1ZGUgL2V0Yy9uZ2lueC9taW1lLnR5cGVzOwogICAgZGVmYXVsdF90eXBlIGFwcGxpY2F0aW9uL29jdGV0LXN0cmVhbTsKICAgIGFjY2Vzc19sb2cgL2Rldi9zdGRvdXQ7CiAgICBzZW5kZmlsZSBvbjsKICAgIGtlZXBhbGl2ZV90aW1lb3V0IDY1OwoKICAgIHNlcnZlciB7CiAgICAgICAgbGlzdGVuIDgwNTIgZGVmYXVsdF9zZXJ2ZXI7CiAgICAgICAgc2VydmVyX25hbWUgXzsKICAgICAgICBjbGllbnRfbWF4X2JvZHlfc2l6ZSAwOwoKICAgICAgICBsb2NhdGlvbiB+IF4vd2Vic29ja2V0IHsKICAgICAgICAgICAgcHJveHlfcGFzcyBodHRwOi8vMTI3LjAuMC4xOjgwNTE7CiAgICAgICAgICAgIHByb3h5X2h0dHBfdmVyc2lvbiAxLjE7CiAgICAgICAgICAgIHByb3h5X3NldF9oZWFkZXIgVXBncmFkZSAkaHR0cF91cGdyYWRlOwogICAgICAgICAgICBwcm94eV9zZXRfaGVhZGVyIENvbm5lY3Rpb24gIlVwZ3JhZGUiOwogICAgICAgICAgICBwcm94eV9jb25uZWN0X3RpbWVvdXQgNzVzOwogICAgICAgICAgICBwcm94eV9yZWFkX3RpbWVvdXQgMTIwczsKICAgICAgICB9CgogICAgICAgIGxvY2F0aW9uIC9zdGF0aWMvIHsKICAgICAgICAgICAgYWxpYXMgL3Zhci9saWIvYXd4L3B1YmxpYy9zdGF0aWMvOwogICAgICAgIH0KCiAgICAgICAgbG9jYXRpb24gLyB7CiAgICAgICAgICAgIHV3c2dpX3JlYWRfdGltZW91dCAxMjBzOwogICAgICAgICAgICB1d3NnaV9wYXNzIDEyNy4wLjAuMTo4MDUwOwogICAgICAgICAgICBpbmNsdWRlIC9ldGMvbmdpbngvdXdzZ2lfcGFyYW1zOwogICAgICAgICAgICBwcm94eV9zZXRfaGVhZGVyIFgtRm9yd2FyZGVkLUZvciAkcHJveHlfYWRkX3hfZm9yd2FyZGVkX2ZvcjsKICAgICAgICAgICAgdXdzZ2lfcGFyYW0gSFRUUF9YX0ZPUldBUkRFRF9GT1IgJHByb3h5X2FkZF94X2ZvcndhcmRlZF9mb3I7CiAgICAgICAgfQogICAgfQp9Cg== | base64 -d > /init-nginx/nginx.conf" [Service] Type=oneshot RemainAfterExit=yes Restart=no [Install] WantedBy=default.target
[Unit]
Description=awx-awx-web container
Requires=awx-awx-init.service
After=awx-awx-init.service
[Container]
Image=quay.io/ansible/awx:latest
Pod=awx.pod
ContainerName=awx-awx-web
Pull=always
Environment=DATABASE_USER=awx
Environment=DATABASE_PASSWORD=Bb3GfGNhP_tp2j7MeCUDUw
Environment=DATABASE_NAME=awx
Environment=DATABASE_HOST=127.0.0.1
Environment=DATABASE_PORT=5432
Environment=REDIS_HOST=127.0.0.1
Environment=REDIS_PORT=6379
Environment=SECRET_KEY=sH-5EVaeQo7PL4TV7xoudA
Environment=AWX_ADMIN_USER=admin
Environment=AWX_ADMIN_PASSWORD=Bb3GfGNhP_tp2j7MeCUDUw
Volume=awx-tower:/etc/tower:Z
Volume=awx-nginx:/etc/nginx:Z
Volume=awx-projects:/var/lib/awx/projects:Z
Entrypoint=/bin/sh
Exec=-c "until python3 -c \"import socket;s=socket.create_connection(('$${DATABASE_HOST:-127.0.0.1}',$${DATABASE_PORT:-5432}),1);s.close()\" 2>/dev/null; do echo 'Waiting for postgres...'; sleep 3; done && awx-manage migrate && DJANGO_SUPERUSER_PASSWORD=$${AWX_ADMIN_PASSWORD:-Bb3GfGNhP_tp2j7MeCUDUw} awx-manage createsuperuser --noinput --username $${AWX_ADMIN_USER:-admin} --email admin@localhost 2>/dev/null || true && exec /usr/bin/launch_awx_web.sh"
[Service]
Restart=always
[Install]
WantedBy=default.target
[Unit] Description=awx-awx-task container Requires=awx-awx-init.service After=awx-awx-init.service [Container] Image=quay.io/ansible/awx:latest Pod=awx.pod ContainerName=awx-awx-task Pull=always Environment=DATABASE_USER=awx Environment=DATABASE_PASSWORD=Bb3GfGNhP_tp2j7MeCUDUw Environment=DATABASE_NAME=awx Environment=DATABASE_HOST=127.0.0.1 Environment=DATABASE_PORT=5432 Environment=REDIS_HOST=127.0.0.1 Environment=REDIS_PORT=6379 Environment=SECRET_KEY=sH-5EVaeQo7PL4TV7xoudA Environment=AWX_ADMIN_USER=admin Environment=AWX_ADMIN_PASSWORD=Bb3GfGNhP_tp2j7MeCUDUw Volume=awx-tower:/etc/tower:Z Volume=awx-projects:/var/lib/awx/projects:Z Entrypoint=/usr/bin/launch_awx_task.sh [Service] Restart=always [Install] WantedBy=default.target
[Unit] Description=awx-postgres container Requires=awx-awx-init.service After=awx-awx-init.service [Container] Image=docker.io/postgres:15 Pod=awx.pod ContainerName=awx-postgres Environment=POSTGRES_USER=awx Environment=POSTGRES_PASSWORD=Bb3GfGNhP_tp2j7MeCUDUw Environment=POSTGRES_DB=awx Volume=awx-db:/var/lib/postgresql/data:Z User=999 Group=999 [Service] Restart=always [Install] WantedBy=default.target
[Unit] Description=awx-redis container Requires=awx-awx-init.service After=awx-awx-init.service [Container] Image=docker.io/redis:7-alpine Pod=awx.pod ContainerName=awx-redis Volume=awx-redis:/data:Z Exec=redis-server --appendonly yes [Service] Restart=always [Install] WantedBy=default.target
Save all of them to ~/.config/containers/systemd/:
mkdir -p ~/.config/containers/systemd/ nano ~/.config/containers/systemd/awx.pod nano ~/.config/containers/systemd/awx-awx-init.container nano ~/.config/containers/systemd/awx-awx-web.container nano ~/.config/containers/systemd/awx-awx-task.container nano ~/.config/containers/systemd/awx-postgres.container nano ~/.config/containers/systemd/awx-redis.container
Start the pod
The pod service pulls in every container service. Autostart at boot comes from the [Install] section of the units, no enable needed.
systemctl --user daemon-reload systemctl --user start awx-pod.service
Status & Logs
systemctl --user status awx-pod.service journalctl --user -u awx-awx-init.service -f journalctl --user -u awx-awx-web.service -f journalctl --user -u awx-awx-task.service -f journalctl --user -u awx-postgres.service -f journalctl --user -u awx-redis.service -f podman pod ps && podman ps
Day-to-day logs, restart, update, remove (click to open)
Logs & shell into a container
podman logs -f awx-awx-web podman logs -f awx-awx-task podman logs -f awx-postgres podman logs -f awx-redis podman exec -it awx-awx-web /bin/sh
Restart
systemctl --user restart awx-pod.service
Update an image by hand
Pull the new version, the restart recreates the containers from it:
podman pull <image>:<tag> systemctl --user restart awx-pod.service
Stop & remove
Stop through systemd, otherwise Restart=always brings the pod back. To remove it for good, delete the unit files and reload:
systemctl --user stop awx-pod.service rm ~/.config/containers/systemd/awx.pod rm ~/.config/containers/systemd/awx-awx-init.container rm ~/.config/containers/systemd/awx-awx-web.container rm ~/.config/containers/systemd/awx-awx-task.container rm ~/.config/containers/systemd/awx-postgres.container rm ~/.config/containers/systemd/awx-redis.container systemctl --user daemon-reload
Delete the data — permanent, only after stop & remove
podman volume rm awx-tower podman volume rm awx-nginx podman volume rm awx-projects podman volume rm awx-db podman volume rm awx-redis
A docker-compose.yml for podman-compose. Handy if you already work with Compose; there are no per-container systemd services.
Install podman-compose as root
Run this as root, e.g. together with the prerequisites before su - awx.
apt install -y podman-compose
Save the compose file
services:
awx-init:
image: quay.io/ansible/awx:latest
pull_policy: always
restart: 'no'
entrypoint:
- sh
command:
- -c
- cp -r /etc/nginx/. /init-nginx/ && echo aW1wb3J0IG9zCgpEQVRBQkFTRVMgPSB7CiAgICAnZGVmYXVsdCc6IHsKICAgICAgICAnQVRPTUlDX1JFUVVFU1RTJzogVHJ1ZSwKICAgICAgICAnRU5HSU5FJzogJ2F3eC5tYWluLmRiLnByb2ZpbGVkX3BnJywKICAgICAgICAnTkFNRSc6IG9zLmVudmlyb24uZ2V0KCdEQVRBQkFTRV9OQU1FJywgJ2F3eCcpLAogICAgICAgICdVU0VSJzogb3MuZW52aXJvbi5nZXQoJ0RBVEFCQVNFX1VTRVInLCAnYXd4JyksCiAgICAgICAgJ1BBU1NXT1JEJzogb3MuZW52aXJvbi5nZXQoJ0RBVEFCQVNFX1BBU1NXT1JEJywgJ2NoYW5nZW1lJyksCiAgICAgICAgJ0hPU1QnOiBvcy5lbnZpcm9uLmdldCgnREFUQUJBU0VfSE9TVCcsICcxMjcuMC4wLjEnKSwKICAgICAgICAnUE9SVCc6IG9zLmVudmlyb24uZ2V0KCdEQVRBQkFTRV9QT1JUJywgJzU0MzInKSwKICAgIH0KfQpBTExPV0VEX0hPU1RTID0gWycqJ10KU0VDUkVUX0tFWSA9IG9zLmVudmlyb24uZ2V0KCdTRUNSRVRfS0VZJywgJ2NoYW5nZW1lJykKREpBTkdPX1JFRElTX0lHTk9SRV9FWENFUFRJT05TID0gVHJ1ZQoKX3JlZGlzX2hvc3QgPSBvcy5lbnZpcm9uLmdldCgnUkVESVNfSE9TVCcsICcxMjcuMC4wLjEnKQpfcmVkaXNfcG9ydCA9IG9zLmVudmlyb24uZ2V0KCdSRURJU19QT1JUJywgJzYzNzknKQpfcmVkaXNfdXJsID0gJ3JlZGlzOi8ve306e30nLmZvcm1hdChfcmVkaXNfaG9zdCwgX3JlZGlzX3BvcnQpCgpDQUNIRVMgPSB7CiAgICAnZGVmYXVsdCc6IHsKICAgICAgICAnQkFDS0VORCc6ICdhd3gubWFpbi5jYWNoZS5BV1hSZWRpc0NhY2hlJywKICAgICAgICAnTE9DQVRJT04nOiAne30vMScuZm9ybWF0KF9yZWRpc191cmwpLAogICAgfQp9CkNIQU5ORUxfTEFZRVJTID0gewogICAgJ2RlZmF1bHQnOiB7CiAgICAgICAgJ0JBQ0tFTkQnOiAnY2hhbm5lbHNfcmVkaXMuY29yZS5SZWRpc0NoYW5uZWxMYXllcicsCiAgICAgICAgJ0NPTkZJRyc6IHsKICAgICAgICAgICAgJ2hvc3RzJzogWyhfcmVkaXNfaG9zdCwgaW50KF9yZWRpc19wb3J0KSldLAogICAgICAgICAgICAnY2FwYWNpdHknOiAxMDAwMCwKICAgICAgICAgICAgJ2dyb3VwX2V4cGlyeSc6IDE1Nzc4NDc2MCwKICAgICAgICB9CiAgICB9Cn0KQlJPS0VSX1VSTCA9IF9yZWRpc191cmwK
| base64 -d > /init-tower/settings.py && cp /etc/tower/uwsgi.ini /init-tower/uwsgi.ini
&& echo d29ya2VyX3Byb2Nlc3NlcyBhdXRvOwplcnJvcl9sb2cgL2Rldi9zdGRlcnIgd2FybjsKcGlkIC90bXAvbmdpbngucGlkOwoKaW5jbHVkZSAvdXNyL3NoYXJlL25naW54L21vZHVsZXMvKi5jb25mOwoKZXZlbnRzIHsKICAgIHdvcmtlcl9jb25uZWN0aW9ucyAxMDI0Owp9CgpodHRwIHsKICAgIGNsaWVudF9ib2R5X3RlbXBfcGF0aCAvdG1wL25naW54LWNsaWVudC1ib2R5OwogICAgcHJveHlfdGVtcF9wYXRoIC90bXAvbmdpbngtcHJveHk7CiAgICBmYXN0Y2dpX3RlbXBfcGF0aCAvdG1wL25naW54LWZhc3RjZ2k7CiAgICB1d3NnaV90ZW1wX3BhdGggL3RtcC9uZ2lueC11d3NnaTsKICAgIHNjZ2lfdGVtcF9wYXRoIC90bXAvbmdpbngtc2NnaTsKICAgIGluY2x1ZGUgL2V0Yy9uZ2lueC9taW1lLnR5cGVzOwogICAgZGVmYXVsdF90eXBlIGFwcGxpY2F0aW9uL29jdGV0LXN0cmVhbTsKICAgIGFjY2Vzc19sb2cgL2Rldi9zdGRvdXQ7CiAgICBzZW5kZmlsZSBvbjsKICAgIGtlZXBhbGl2ZV90aW1lb3V0IDY1OwoKICAgIHNlcnZlciB7CiAgICAgICAgbGlzdGVuIDgwNTIgZGVmYXVsdF9zZXJ2ZXI7CiAgICAgICAgc2VydmVyX25hbWUgXzsKICAgICAgICBjbGllbnRfbWF4X2JvZHlfc2l6ZSAwOwoKICAgICAgICBsb2NhdGlvbiB+IF4vd2Vic29ja2V0IHsKICAgICAgICAgICAgcHJveHlfcGFzcyBodHRwOi8vMTI3LjAuMC4xOjgwNTE7CiAgICAgICAgICAgIHByb3h5X2h0dHBfdmVyc2lvbiAxLjE7CiAgICAgICAgICAgIHByb3h5X3NldF9oZWFkZXIgVXBncmFkZSAkaHR0cF91cGdyYWRlOwogICAgICAgICAgICBwcm94eV9zZXRfaGVhZGVyIENvbm5lY3Rpb24gIlVwZ3JhZGUiOwogICAgICAgICAgICBwcm94eV9jb25uZWN0X3RpbWVvdXQgNzVzOwogICAgICAgICAgICBwcm94eV9yZWFkX3RpbWVvdXQgMTIwczsKICAgICAgICB9CgogICAgICAgIGxvY2F0aW9uIC9zdGF0aWMvIHsKICAgICAgICAgICAgYWxpYXMgL3Zhci9saWIvYXd4L3B1YmxpYy9zdGF0aWMvOwogICAgICAgIH0KCiAgICAgICAgbG9jYXRpb24gLyB7CiAgICAgICAgICAgIHV3c2dpX3JlYWRfdGltZW91dCAxMjBzOwogICAgICAgICAgICB1d3NnaV9wYXNzIDEyNy4wLjAuMTo4MDUwOwogICAgICAgICAgICBpbmNsdWRlIC9ldGMvbmdpbngvdXdzZ2lfcGFyYW1zOwogICAgICAgICAgICBwcm94eV9zZXRfaGVhZGVyIFgtRm9yd2FyZGVkLUZvciAkcHJveHlfYWRkX3hfZm9yd2FyZGVkX2ZvcjsKICAgICAgICAgICAgdXdzZ2lfcGFyYW0gSFRUUF9YX0ZPUldBUkRFRF9GT1IgJHByb3h5X2FkZF94X2ZvcndhcmRlZF9mb3I7CiAgICAgICAgfQogICAgfQp9Cg==
| base64 -d > /init-nginx/nginx.conf
volumes:
- awx-tower:/init-tower:Z
- awx-nginx:/init-nginx:Z
awx-web:
image: quay.io/ansible/awx:latest
pull_policy: always
restart: always
environment:
- DATABASE_USER=awx
- DATABASE_PASSWORD=Bb3GfGNhP_tp2j7MeCUDUw
- DATABASE_NAME=awx
- DATABASE_HOST=127.0.0.1
- DATABASE_PORT=5432
- REDIS_HOST=127.0.0.1
- REDIS_PORT=6379
- SECRET_KEY=sH-5EVaeQo7PL4TV7xoudA
- AWX_ADMIN_USER=admin
- AWX_ADMIN_PASSWORD=Bb3GfGNhP_tp2j7MeCUDUw
entrypoint:
- /bin/sh
command:
- -c
- until python3 -c "import socket;s=socket.create_connection(('$${DATABASE_HOST:-127.0.0.1}',$${DATABASE_PORT:-5432}),1);s.close()"
2>/dev/null; do echo 'Waiting for postgres...'; sleep 3; done && awx-manage
migrate && DJANGO_SUPERUSER_PASSWORD=$${AWX_ADMIN_PASSWORD:-Bb3GfGNhP_tp2j7MeCUDUw}
awx-manage createsuperuser --noinput --username $${AWX_ADMIN_USER:-admin} --email
admin@localhost 2>/dev/null || true && exec /usr/bin/launch_awx_web.sh
depends_on:
awx-init:
condition: service_completed_successfully
postgres:
condition: service_started
redis:
condition: service_started
volumes:
- awx-tower:/etc/tower:Z
- awx-nginx:/etc/nginx:Z
- awx-projects:/var/lib/awx/projects:Z
network_mode: service:postgres
awx-task:
image: quay.io/ansible/awx:latest
pull_policy: always
restart: always
environment:
- DATABASE_USER=awx
- DATABASE_PASSWORD=Bb3GfGNhP_tp2j7MeCUDUw
- DATABASE_NAME=awx
- DATABASE_HOST=127.0.0.1
- DATABASE_PORT=5432
- REDIS_HOST=127.0.0.1
- REDIS_PORT=6379
- SECRET_KEY=sH-5EVaeQo7PL4TV7xoudA
- AWX_ADMIN_USER=admin
- AWX_ADMIN_PASSWORD=Bb3GfGNhP_tp2j7MeCUDUw
entrypoint:
- /usr/bin/launch_awx_task.sh
depends_on:
awx-init:
condition: service_completed_successfully
postgres:
condition: service_started
redis:
condition: service_started
volumes:
- awx-tower:/etc/tower:Z
- awx-projects:/var/lib/awx/projects:Z
network_mode: service:postgres
postgres:
image: docker.io/postgres:15
restart: always
environment:
- POSTGRES_USER=awx
- POSTGRES_PASSWORD=Bb3GfGNhP_tp2j7MeCUDUw
- POSTGRES_DB=awx
user: 999:999
depends_on:
awx-init:
condition: service_completed_successfully
volumes:
- awx-db:/var/lib/postgresql/data:Z
ports:
- 8052:8052
redis:
image: docker.io/redis:7-alpine
restart: always
command:
- redis-server
- --appendonly
- 'yes'
depends_on:
awx-init:
condition: service_completed_successfully
postgres:
condition: service_started
volumes:
- awx-redis:/data:Z
network_mode: service:postgres
volumes:
awx-tower: null
awx-nginx: null
awx-projects: null
awx-db: null
awx-redis: null
mkdir -p ~/awx nano ~/awx/docker-compose.yml
Start, status & logs
cd ~/awx podman-compose up -d podman-compose ps podman-compose logs -f # Stop: podman-compose down
Start after reboot
podman-restart.service starts every container with restart: always at boot:
systemctl --user enable podman-restart.service
Update images
cd ~/awx podman-compose pull podman-compose up -d
Day-to-day logs, restart, update, remove (click to open)
Logs & shell into a container
podman logs -f awx_awx-web_1 podman logs -f awx_awx-task_1 podman logs -f awx_postgres_1 podman logs -f awx_redis_1 podman exec -it awx_awx-web_1 /bin/sh
Restart
cd ~/awx podman-compose restart
Stop & remove
cd ~/awx podman-compose down
Delete the data — permanent, only after stop & remove
podman volume rm awx_awx-tower podman volume rm awx_awx-nginx podman volume rm awx_awx-projects podman volume rm awx_awx-db podman volume rm awx_awx-redis
Plain podman pod create / podman create commands. Good for a quick test or to see what happens under the hood.
Save the script
#!/bin/bash
set -e
# ── Create named volumes ───────────────────────────────────────────
# Named volumes are created automatically — no UID/GID permission adjustment needed.
podman volume exists awx-tower || podman volume create awx-tower
podman volume exists awx-nginx || podman volume create awx-nginx
podman volume exists awx-projects || podman volume create awx-projects
podman volume exists awx-db || podman volume create awx-db
podman volume exists awx-redis || podman volume create awx-redis
# ── Create pod ─────────────────────────────────────────────────────
podman pod create \
--name awx \
-p 8052:8052
# ── Init container: awx-awx-init ────────────────────────────────────────
podman create \
--pod awx \
--name awx-awx-init \
--init-ctr=once \
--pull always \
-v awx-tower:/init-tower:Z \
-v awx-nginx:/init-nginx:Z \
--entrypoint sh \
quay.io/ansible/awx:latest \
-c 'cp -r /etc/nginx/. /init-nginx/ && echo aW1wb3J0IG9zCgpEQVRBQkFTRVMgPSB7CiAgICAnZGVmYXVsdCc6IHsKICAgICAgICAnQVRPTUlDX1JFUVVFU1RTJzogVHJ1ZSwKICAgICAgICAnRU5HSU5FJzogJ2F3eC5tYWluLmRiLnByb2ZpbGVkX3BnJywKICAgICAgICAnTkFNRSc6IG9zLmVudmlyb24uZ2V0KCdEQVRBQkFTRV9OQU1FJywgJ2F3eCcpLAogICAgICAgICdVU0VSJzogb3MuZW52aXJvbi5nZXQoJ0RBVEFCQVNFX1VTRVInLCAnYXd4JyksCiAgICAgICAgJ1BBU1NXT1JEJzogb3MuZW52aXJvbi5nZXQoJ0RBVEFCQVNFX1BBU1NXT1JEJywgJ2NoYW5nZW1lJyksCiAgICAgICAgJ0hPU1QnOiBvcy5lbnZpcm9uLmdldCgnREFUQUJBU0VfSE9TVCcsICcxMjcuMC4wLjEnKSwKICAgICAgICAnUE9SVCc6IG9zLmVudmlyb24uZ2V0KCdEQVRBQkFTRV9QT1JUJywgJzU0MzInKSwKICAgIH0KfQpBTExPV0VEX0hPU1RTID0gWycqJ10KU0VDUkVUX0tFWSA9IG9zLmVudmlyb24uZ2V0KCdTRUNSRVRfS0VZJywgJ2NoYW5nZW1lJykKREpBTkdPX1JFRElTX0lHTk9SRV9FWENFUFRJT05TID0gVHJ1ZQoKX3JlZGlzX2hvc3QgPSBvcy5lbnZpcm9uLmdldCgnUkVESVNfSE9TVCcsICcxMjcuMC4wLjEnKQpfcmVkaXNfcG9ydCA9IG9zLmVudmlyb24uZ2V0KCdSRURJU19QT1JUJywgJzYzNzknKQpfcmVkaXNfdXJsID0gJ3JlZGlzOi8ve306e30nLmZvcm1hdChfcmVkaXNfaG9zdCwgX3JlZGlzX3BvcnQpCgpDQUNIRVMgPSB7CiAgICAnZGVmYXVsdCc6IHsKICAgICAgICAnQkFDS0VORCc6ICdhd3gubWFpbi5jYWNoZS5BV1hSZWRpc0NhY2hlJywKICAgICAgICAnTE9DQVRJT04nOiAne30vMScuZm9ybWF0KF9yZWRpc191cmwpLAogICAgfQp9CkNIQU5ORUxfTEFZRVJTID0gewogICAgJ2RlZmF1bHQnOiB7CiAgICAgICAgJ0JBQ0tFTkQnOiAnY2hhbm5lbHNfcmVkaXMuY29yZS5SZWRpc0NoYW5uZWxMYXllcicsCiAgICAgICAgJ0NPTkZJRyc6IHsKICAgICAgICAgICAgJ2hvc3RzJzogWyhfcmVkaXNfaG9zdCwgaW50KF9yZWRpc19wb3J0KSldLAogICAgICAgICAgICAnY2FwYWNpdHknOiAxMDAwMCwKICAgICAgICAgICAgJ2dyb3VwX2V4cGlyeSc6IDE1Nzc4NDc2MCwKICAgICAgICB9CiAgICB9Cn0KQlJPS0VSX1VSTCA9IF9yZWRpc191cmwK | base64 -d > /init-tower/settings.py && cp /etc/tower/uwsgi.ini /init-tower/uwsgi.ini && echo d29ya2VyX3Byb2Nlc3NlcyBhdXRvOwplcnJvcl9sb2cgL2Rldi9zdGRlcnIgd2FybjsKcGlkIC90bXAvbmdpbngucGlkOwoKaW5jbHVkZSAvdXNyL3NoYXJlL25naW54L21vZHVsZXMvKi5jb25mOwoKZXZlbnRzIHsKICAgIHdvcmtlcl9jb25uZWN0aW9ucyAxMDI0Owp9CgpodHRwIHsKICAgIGNsaWVudF9ib2R5X3RlbXBfcGF0aCAvdG1wL25naW54LWNsaWVudC1ib2R5OwogICAgcHJveHlfdGVtcF9wYXRoIC90bXAvbmdpbngtcHJveHk7CiAgICBmYXN0Y2dpX3RlbXBfcGF0aCAvdG1wL25naW54LWZhc3RjZ2k7CiAgICB1d3NnaV90ZW1wX3BhdGggL3RtcC9uZ2lueC11d3NnaTsKICAgIHNjZ2lfdGVtcF9wYXRoIC90bXAvbmdpbngtc2NnaTsKICAgIGluY2x1ZGUgL2V0Yy9uZ2lueC9taW1lLnR5cGVzOwogICAgZGVmYXVsdF90eXBlIGFwcGxpY2F0aW9uL29jdGV0LXN0cmVhbTsKICAgIGFjY2Vzc19sb2cgL2Rldi9zdGRvdXQ7CiAgICBzZW5kZmlsZSBvbjsKICAgIGtlZXBhbGl2ZV90aW1lb3V0IDY1OwoKICAgIHNlcnZlciB7CiAgICAgICAgbGlzdGVuIDgwNTIgZGVmYXVsdF9zZXJ2ZXI7CiAgICAgICAgc2VydmVyX25hbWUgXzsKICAgICAgICBjbGllbnRfbWF4X2JvZHlfc2l6ZSAwOwoKICAgICAgICBsb2NhdGlvbiB+IF4vd2Vic29ja2V0IHsKICAgICAgICAgICAgcHJveHlfcGFzcyBodHRwOi8vMTI3LjAuMC4xOjgwNTE7CiAgICAgICAgICAgIHByb3h5X2h0dHBfdmVyc2lvbiAxLjE7CiAgICAgICAgICAgIHByb3h5X3NldF9oZWFkZXIgVXBncmFkZSAkaHR0cF91cGdyYWRlOwogICAgICAgICAgICBwcm94eV9zZXRfaGVhZGVyIENvbm5lY3Rpb24gIlVwZ3JhZGUiOwogICAgICAgICAgICBwcm94eV9jb25uZWN0X3RpbWVvdXQgNzVzOwogICAgICAgICAgICBwcm94eV9yZWFkX3RpbWVvdXQgMTIwczsKICAgICAgICB9CgogICAgICAgIGxvY2F0aW9uIC9zdGF0aWMvIHsKICAgICAgICAgICAgYWxpYXMgL3Zhci9saWIvYXd4L3B1YmxpYy9zdGF0aWMvOwogICAgICAgIH0KCiAgICAgICAgbG9jYXRpb24gLyB7CiAgICAgICAgICAgIHV3c2dpX3JlYWRfdGltZW91dCAxMjBzOwogICAgICAgICAgICB1d3NnaV9wYXNzIDEyNy4wLjAuMTo4MDUwOwogICAgICAgICAgICBpbmNsdWRlIC9ldGMvbmdpbngvdXdzZ2lfcGFyYW1zOwogICAgICAgICAgICBwcm94eV9zZXRfaGVhZGVyIFgtRm9yd2FyZGVkLUZvciAkcHJveHlfYWRkX3hfZm9yd2FyZGVkX2ZvcjsKICAgICAgICAgICAgdXdzZ2lfcGFyYW0gSFRUUF9YX0ZPUldBUkRFRF9GT1IgJHByb3h5X2FkZF94X2ZvcndhcmRlZF9mb3I7CiAgICAgICAgfQogICAgfQp9Cg== | base64 -d > /init-nginx/nginx.conf'
# ── Container: awx-awx-web ─────────────────────────────────────────────
podman create \
--pod awx \
--name awx-awx-web \
--restart always \
--pull always \
-e DATABASE_USER='awx' \
-e DATABASE_PASSWORD='Bb3GfGNhP_tp2j7MeCUDUw' \
-e DATABASE_NAME='awx' \
-e DATABASE_HOST='127.0.0.1' \
-e DATABASE_PORT='5432' \
-e REDIS_HOST='127.0.0.1' \
-e REDIS_PORT='6379' \
-e SECRET_KEY='sH-5EVaeQo7PL4TV7xoudA' \
-e AWX_ADMIN_USER='admin' \
-e AWX_ADMIN_PASSWORD='Bb3GfGNhP_tp2j7MeCUDUw' \
-v awx-tower:/etc/tower:Z \
-v awx-nginx:/etc/nginx:Z \
-v awx-projects:/var/lib/awx/projects:Z \
--entrypoint /bin/sh \
quay.io/ansible/awx:latest \
-c 'until python3 -c "import socket;s=socket.create_connection(('"'"'${DATABASE_HOST:-127.0.0.1}'"'"',${DATABASE_PORT:-5432}),1);s.close()" 2>/dev/null; do echo '"'"'Waiting for postgres...'"'"'; sleep 3; done && awx-manage migrate && DJANGO_SUPERUSER_PASSWORD=${AWX_ADMIN_PASSWORD:-Bb3GfGNhP_tp2j7MeCUDUw} awx-manage createsuperuser --noinput --username ${AWX_ADMIN_USER:-admin} --email admin@localhost 2>/dev/null || true && exec /usr/bin/launch_awx_web.sh'
# ── Container: awx-awx-task ─────────────────────────────────────────────
podman create \
--pod awx \
--name awx-awx-task \
--restart always \
--pull always \
-e DATABASE_USER='awx' \
-e DATABASE_PASSWORD='Bb3GfGNhP_tp2j7MeCUDUw' \
-e DATABASE_NAME='awx' \
-e DATABASE_HOST='127.0.0.1' \
-e DATABASE_PORT='5432' \
-e REDIS_HOST='127.0.0.1' \
-e REDIS_PORT='6379' \
-e SECRET_KEY='sH-5EVaeQo7PL4TV7xoudA' \
-e AWX_ADMIN_USER='admin' \
-e AWX_ADMIN_PASSWORD='Bb3GfGNhP_tp2j7MeCUDUw' \
-v awx-tower:/etc/tower:Z \
-v awx-projects:/var/lib/awx/projects:Z \
--entrypoint /usr/bin/launch_awx_task.sh \
quay.io/ansible/awx:latest
# ── Container: awx-postgres ─────────────────────────────────────────────
podman create \
--pod awx \
--name awx-postgres \
--restart always \
-e POSTGRES_USER='awx' \
-e POSTGRES_PASSWORD='Bb3GfGNhP_tp2j7MeCUDUw' \
-e POSTGRES_DB='awx' \
-v awx-db:/var/lib/postgresql/data:Z \
--user 999:999 \
docker.io/postgres:15
# ── Container: awx-redis ─────────────────────────────────────────────
podman create \
--pod awx \
--name awx-redis \
--restart always \
-v awx-redis:/data:Z \
docker.io/redis:7-alpine \
redis-server --appendonly yes
# ── Start pod ──────────────────────────────────────────────────────
podman pod start awx
# ── Stop & clean up ───────────────────────────────────────────────
# podman pod stop awx
# podman pod rm awx
nano awx.sh
Run it, status & logs
bash awx.sh podman pod ps && podman ps podman logs -f <container-name>
Start after reboot
podman-restart.service starts every container with --restart always at boot:
systemctl --user enable podman-restart.service
Remove or rebuild
The script creates the pod once. To apply changes or new images, remove the pod and run the script again (named volumes stay):
podman pod rm -f awx bash awx.sh
Day-to-day logs, restart, update, remove (click to open)
Logs & shell into a container
podman logs -f awx-awx-web podman logs -f awx-awx-task podman logs -f awx-postgres podman logs -f awx-redis podman exec -it awx-awx-web /bin/sh
Restart
podman pod stop awx podman pod start awx
Stop & remove
podman pod rm -f awx
Delete the data — permanent, only after stop & remove
podman volume rm awx-tower podman volume rm awx-nginx podman volume rm awx-projects podman volume rm awx-db podman volume rm awx-redis
Ports < 1024 (e.g. 80, 443)
Rootless cannot open privileged ports. Solution:
sysctl net.ipv4.ip_unprivileged_port_start=80
Make persistent in /etc/sysctl.d/99-podman.conf.
Containers communicate via localhost
All containers in the pod share the same network namespace. Always use localhost, not container names.
# Correct (e.g. app → db): localhost:5432 # Wrong (doesn't work in a pod): db-container:5432
List open ports
Which ports are the running containers publishing? See the PORTS column:
podman ps
Custom DNS for the pod
Set a custom DNS server (e.g. local Pi-hole) in the generator under DNS server. Every format picks it up.
Set volume ownership
Fix permission errors by adjusting UID/GID in the user namespace:
podman unshare chown 1000:1000 /path/to/volume
SELinux volume labels
On SELinux systems (RHEL, Fedora) set the volume suffix:
/host/path:/container/path:Z # private /host/path:/container/path:z # shared
List all volumes
podman volume ls podman volume inspect <volume-name>
Volume backup
Back up data from a named volume:
podman run --rm \ -v <volume-name>:/data:ro \ -v $(pwd):/backup \ busybox tar czf /backup/backup.tar.gz /data
Cleanup
Remove unused images, containers and volumes:
podman system prune -f # containers + images podman image prune -f # untagged images only podman volume prune -f # unused volumes
Check for outdated images
List local images; auto-update only covers units with AutoUpdate= (Kube and Quadlet tabs):
podman images podman auto-update --dry-run
All containers, including stopped ones
podman pod ps podman ps -a
Resource usage
podman stats --no-stream