Ghost Hands – Automating The Stronghold With Ansible And Podman
Mission Update
Now we automate.
The pod.
The proxy.
The secrets.
One playbook to conjure the setup, one command to repeat the ritual.
Requirements
- Ansible (core +
community.containers) - Podman configured for rootless ops
- X509 certs or automation for Let’s Encrypt
- Directory structure with:
roles/semaphore/tasks/main.ymlfiles/nginx.conffiles/cert.pem, key.pem(or auto-gen task)
Playbook Strategy
- Create Podman pod
- Deploy MySQL container
- Deploy Semaphore UI container
- Deploy NginX container with volumes mounted
Secret Externalization
Store credentials in group_vars/containers.yml and encrypt with Ansible Vault.
Step 1: Create The Pod
- name: Create the pod
containers.podman.podman_pod:
name: p_semaphore
state: created
ports:
- "4430:443"
Step 2: Activate the MySQL Container
- name: Create the MySQL container
containers.podman.podman_container:
name: semaphore_mysql
pod: p_semaphore
state: started
rm: true
detach: true
image: docker.io/mysql:lts
volumes:
- semaphore_mysql:/var/lib/mysql
env:
MYSQL_RANDOM_ROOT_PASSWORD: 'yes'
MYSQL_DATABASE: semaphore
MYSQL_USER: semaphore
MYSQL_PASSWORD: "{{ semaphore_mysql_pw }}"
Step 3: Initiate the Semaphore container
- name: Create the Semaphore container
containers.podman.podman_container:
name: semaphore
pod: p_semaphore
state: started
rm: true
detach: true
image: docker.io/semaphoreui/semaphore:latest
env:
SEMAPHORE_DB_USER: semaphore
SEMAPHORE_DB_PASS: "{{ semaphore_mysql_pw }}"
SEMAPHORE_DB_HOST: 127.0.0.1
SEMAPHORE_DB_PORT: 3306
SEMAPHORE_DB_DIALECT: mysql
SEMAPHORE_DB: semaphore
SEMAPHORE_PLAYBOOK_PATH: /tmp/semaphore/
SEMAPHORE_ADMIN_PASSWORD: "{{ semaphore_admin_pw }}"
SEMAPHORE_ADMIN_NAME: admin
SEMAPHORE_ADMIN_EMAIL: admin@localhost
SEMAPHORE_ADMIN: admin
SEMAPHORE_ACCESS_KEY_ENCRYPTION: gs72mPntFATGJs9qK0pQ0rKtfidlexiMjYCH9gWKhTU=
SEMAPHORE_LDAP_ACTIVATED: 'no'
TZ: UTC
Step 4: The NginX Reverse Proxy
- name: Create the NginX container
containers.podman.podman_container:
name: semaphore_proxy
pod: p_semaphore
state: started
rm: true
detach: true
image: docker.io/library/nginx
volumes:
- "{{ role_path }}/files/nginx.conf:/etc/nginx/conf.d/default.conf:ro"
- "{{ role_path }}/files/cert.pem:/etc/nginx/cert.pem:ro"
- "{{ role_path }}/files/key.pem:/etc/nginx/key.pem:ro"
Step 5: Verify
Log in.
Verify the configuration.
Monitor the logs with podman pod logs p_semaphore.
Final Signal
The stronghold stands.
Provisioned in silence. Hardened by code.
But this is just the surface. A faint signal.
There is much to do for a strong signal.
Need the full Ansible role?
- Variables ready
- Templates in place
- Handlers sharpened
- Deploy once, repeat forever
Buy the hardened role + full guide – forged in the silence.
Whisper to DeadSwitch on Matrix: @deadswitch:matrix.org
Maybe the Ghost signals back.
DeadSwitch | The Silent Architect
In silence, I rise. In structure, I endure.
Discover more from Tom's IT Cafe
Subscribe to get the latest posts sent to your email.