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.