Skip to content

Quick Start

Installation

Install Collection

ansible-galaxy collection install jackaltx.solti_ensemble

Verify Installation

ansible-galaxy collection list | grep solti_ensemble

Quick Start Scenarios

Scenario 1: Harden SSH on New Server

Goal: Secure SSH daemon on a fresh server

# playbooks/harden-ssh.yml
---
- name: Harden SSH
  hosts: new_servers
  become: true
  roles:
    - jackaltx.solti_ensemble.sshd_harden

Run:

ansible-playbook -i inventory.yml playbooks/harden-ssh.yml

What Happens: - Restricts SSH algorithms to secure options - Configures timeouts - Generates secure keys - Filters weak DH moduli - Restarts SSH service

Scenario 2: Deploy MariaDB

Goal: Install database server for application

# playbooks/deploy-database.yml
---
- name: Deploy MariaDB
  hosts: db_servers
  become: true
  vars_files:
    - vars/vault.yml
  roles:
    - role: jackaltx.solti_ensemble.mariadb
      vars:
        mariadb_mysql_root_password: "{{ vault_mariadb_root }}"
        mariadb_security: true
        mariadb_bind_address: "127.0.0.1"

Run:

# Create encrypted vault file first
ansible-vault create vars/vault.yml
# Add: vault_mariadb_root: "your_secure_password"

ansible-playbook -i inventory.yml --ask-vault-pass playbooks/deploy-database.yml

What Happens: - Installs MariaDB server - Removes anonymous users and test database - Sets root password - Configures secure defaults - Starts service

Scenario 3: Connect Remote Host via VPN

Goal: Set up secure monitoring connectivity

# playbooks/setup-monitoring-vpn.yml
---
- name: Configure WireGuard Client
  hosts: remote_hosts
  become: true
  vars_files:
    - vars/vault.yml
  roles:
    - role: jackaltx.solti_ensemble.wireguard
      vars:
        wireguard_endpoint: "monitor-hub.example.com:51820"
        wireguard_server_public_key: "{{ vault_wg_server_pubkey }}"
        wireguard_client_address: "10.10.0.20/24"
        wireguard_allowed_ips: "10.10.0.0/24"
        wireguard_persistent_keepalive: 25

Run:

ansible-playbook -i inventory.yml --ask-vault-pass playbooks/setup-monitoring-vpn.yml

What Happens: - Installs WireGuard client - Generates client keys - Configures VPN connection - Starts wg-quick service - Establishes encrypted tunnel

Scenario 4: Full Stack Deployment

Goal: Deploy complete infrastructure stack

# playbooks/full-stack.yml
---
- name: Deploy Infrastructure Stack
  hosts: app_servers
  become: true
  vars_files:
    - vars/vault.yml
  roles:
    # Layer 1: Foundation
    - role: jackaltx.solti_ensemble.sshd_harden
    - role: jackaltx.solti_ensemble.fail2ban_config

    # Layer 2: Infrastructure
    - role: jackaltx.solti_ensemble.mariadb
      vars:
        mariadb_mysql_root_password: "{{ vault_mariadb_root }}"
        mariadb_security: true

    - role: jackaltx.solti_ensemble.nfs_client
      vars:
        nfs_shares:
          - server: "nas.example.com"
            remote_path: "/export/app_data"
            local_path: "/mnt/nfs/app_data"

    # Layer 3: Application
    - role: jackaltx.solti_ensemble.gitea
      vars:
        gitea_db_type: mysql
        gitea_db_host: "localhost"
        gitea_db_password: "{{ vault_gitea_db_pass }}"

Run:

ansible-playbook -i inventory.yml --ask-vault-pass playbooks/full-stack.yml

What Happens: - Hardens SSH - Configures fail2ban - Installs MariaDB - Mounts NFS storage - Deploys Gitea with database

Common Patterns

Pattern 1: Secure Defaults

Always enable security features:

roles:
  - role: jackaltx.solti_ensemble.mariadb
    vars:
      mariadb_security: true              # Remove test users/db
      mariadb_bind_address: "127.0.0.1"   # Localhost only

Pattern 2: Vault for Secrets

Never hardcode passwords:

# vars/vault.yml (encrypted with ansible-vault)
vault_mariadb_root: "secure_random_password_123"
vault_gitea_db_pass: "another_secure_password_456"
vault_wg_server_pubkey: "base64_encoded_public_key"

# playbook.yml
vars_files:
  - vars/vault.yml

Pattern 3: Layered Deployment

Deploy in order of dependencies:

# Layer 1: Foundation
- jackaltx.solti_ensemble.sshd_harden
- jackaltx.solti_ensemble.podman

# Layer 2: Infrastructure (requires Layer 1)
- jackaltx.solti_ensemble.mariadb

# Layer 3: Applications (requires Layer 2)
- jackaltx.solti_ensemble.gitea

Pattern 4: Idempotent Operations

Roles are safe to re-run:

# First run: installs MariaDB
ansible-playbook deploy.yml

# Second run: checks state, makes no changes if already configured
ansible-playbook deploy.yml

# Output: "ok" instead of "changed"

Pattern 5: Tag-Based Execution

Run specific parts:

roles:
  - role: jackaltx.solti_ensemble.mariadb
    tags: ['database', 'infrastructure']

  - role: jackaltx.solti_ensemble.gitea
    tags: ['application', 'git']

Run only database:

ansible-playbook deploy.yml --tags database

Inventory Setup

Basic Inventory

# inventory.yml
all:
  hosts:
    server1.example.com:
      ansible_user: lavender
      ansible_become_password: "{{ vault_sudo_pass }}"

  children:
    db_servers:
      hosts:
        server1.example.com:

    app_servers:
      hosts:
        server2.example.com:

Group Variables

# group_vars/db_servers.yml
mariadb_bind_address: "0.0.0.0"
mariadb_backup_enabled: true

# group_vars/app_servers.yml
gitea_domain: "git.example.com"
gitea_db_host: "server1.example.com"

Verification

Check Services

# SSH hardening applied
ssh user@server "sudo sshd -T | grep -E '(Ciphers|MACs|KexAlgorithms)'"

# MariaDB running
ssh user@server "sudo systemctl status mariadb"

# WireGuard connected
ssh user@server "sudo wg show"

# NFS mounted
ssh user@server "df -h | grep nfs"

Test Functionality

# Database connection
ssh user@server "mysql -u root -p -e 'SELECT VERSION();'"

# WireGuard connectivity
ssh user@server "ping -c 3 10.10.0.11"

# NFS write test
ssh user@server "sudo touch /mnt/nfs/test && sudo rm /mnt/nfs/test"

Troubleshooting

Playbook Fails: Connection Refused

Symptom:

UNREACHABLE! => {"changed": false, "msg": "Failed to connect to the host via ssh"}

Solution:

  1. Check SSH key added to target host
  2. Verify ansible_user has sudo access
  3. Test manual SSH connection
ssh -v user@server

Playbook Fails: Permission Denied

Symptom:

FAILED! => {"changed": false, "msg": "Missing sudo password"}

Solution:

Add --ask-become-pass or set in inventory:

ansible_become_password: "{{ vault_sudo_pass }}"

Service Won't Start

Symptom:

FAILED! => {"changed": false, "msg": "Unable to start service mariadb"}

Solution:

Check service logs on target:

ssh user@server "sudo journalctl -u mariadb -n 100"

Role Not Found

Symptom:

ERROR! the role 'jackaltx.solti_ensemble.mariadb' was not found

Solution:

# Reinstall collection
ansible-galaxy collection install jackaltx.solti_ensemble --force

# Verify installation
ansible-galaxy collection list

Next Steps

For Simple Deployments

  1. Review individual role documentation
  2. Create playbooks for specific services
  3. Test in development environment

For Production Deployments

  1. Read "Architecture Overview"
  2. Plan service layers
  3. Set up Ansible Vault
  4. Review "Security Best Practices"
  5. Implement monitoring integration

For Testing and Validation

  1. Review "Testing Framework"
  2. Set up molecule testing
  3. Validate with verification tasks

Reference

Collection Documentation: - GitHub: http://github.com/jackaltx/solti_ensemble_collection - Documentation: http://docs.jackaltx.com

Role-Specific Docs: - MariaDB Role - WireGuard Role - SSHD Hardening Role - NFS Client Role - Gitea Role - And more...

SOLTI Ecosystem: - solti-monitoring: Observability stack - solti-containers: Testing infrastructure - solti-conductor: Proxmox orchestration