,

Automating Hosting Support Ops with Gemini + Ansible

Hosting support is diagnosis at scale, and most of it follows patterns. Here's an architecture that pairs Gemini's reasoning with Ansible's safe execution to triage server issues faster, without ever letting the model touch a shell.

Hosting support work has a rhythm: a ticket arrives (“site down”, “site slow”, “can’t receive mail”), an engineer SSHes in, runs the same fifteen diagnostic commands they always run, reads the output, and either applies a known fix or escalates with notes. The diagnosis step is pattern matching over command output, which is precisely the kind of reading-and-reasoning task Gemini handles well. The execution step is where you must not let a language model anywhere near a shell.

The architecture that resolves this tension cleanly: Gemini reasons, Ansible executes. This post walks through it for WordPress hosting specifically, but the pattern applies to any ops environment.

Why Ansible is the perfect AI boundary

The naive design (model generates shell commands, something runs them) is a security incident with extra steps. Model output is probabilistic; shells are unforgiving; and ticket text (which flows into your prompt) is attacker-controllable input.

Ansible changes the shape of the problem. A playbook is a named, reviewed, idempotent, parameterized unit of operations. Which means the AI never authors actions: it selects from a catalog of actions your team already wrote and trusts, exactly the function-calling allowlist pattern from earlier in this series, applied to infrastructure:

  • diag_site_down.yml: checks web server status, PHP-FPM pool, recent OOM kills, disk space, cert expiry; gathers but changes nothing
  • diag_slow_site.yml: load averages, slow query log tail, PHP-FPM queue, object-cache status
  • fix_restart_phpfpm.yml: the boring, safe restart, with a health check after
  • fix_clear_disk_space.yml: rotates logs, prunes old backups per policy

Every playbook is idempotent, logged, and was written by a human on your team. The blast radius of any model mistake is bounded by the worst thing your safest playbooks can do.

The loop

The triage service (a small daemon or queue worker; this is a backend service, not a WordPress plugin) runs a function-calling loop:

  1. Ticket text plus server identifier goes to Gemini with function declarations mirroring the playbook catalog: diagnostics exposed as freely callable, fixes marked as approval-required.
  2. Gemini picks diagnostics: run_playbook("diag_site_down", host). Your code shells out to ansible-playbook (the code does, never the model), captures structured output, returns it as the function response.
  3. Gemini reads results and iterates: disk full? It calls the disk-usage diagnostic next. This multi-step narrowing is where the model genuinely earns its keep; it’s the same “read output, decide next check” reasoning your engineers do.
  4. Terminal output is a structured verdict: diagnosis, evidence, recommended playbook, confidence, using a response schema (structured output, covered earlier) so it’s machine-routable.
$verdict_schema = [
    'type'       => 'object',
    'properties' => [
        'diagnosis'            => [ 'type' => 'string' ],
        'evidence'             => [ 'type' => 'array', 'items' => [ 'type' => 'string' ] ],
        'recommended_playbook' => [ 'type' => 'string' ],
        'confidence'           => [ 'type' => 'string', 'enum' => [ 'high', 'medium', 'low' ] ],
        'escalate_to_human'    => [ 'type' => 'boolean' ],
    ],
    'required'   => [ 'diagnosis', 'evidence', 'escalate_to_human' ],
];

The evidence array should quote actual command output (“disk 98% on /var”, “php-fpm: pool www seems busy”). Verdicts that cite evidence can be verified by the engineer in seconds; verdicts that don’t are vibes with a confidence score.

The autonomy dial

Roll this out in stages, and be explicit about which stage you’re in:

Stage 1: diagnose only. The AI runs read-only diagnostics and attaches its verdict to the ticket. The engineer executes any fix. Run here for weeks; measure how often the diagnosis matches what the engineer concluded. This stage alone is a large win: the engineer opens a ticket that already contains the fifteen commands’ worth of evidence, pre-summarized.

Stage 2: one-click fix. High-confidence verdicts render the recommended playbook as a button. Human clicks, Ansible runs, model never self-executes. The approval flag is set by your UI after a real click, never model-settable (the confirmation pattern from the function-calling post, verbatim).

Stage 3: auto-fix for a tiny allowlist. Only for fixes that are provably safe and idempotent (restart a stuck PHP-FPM pool after a health check confirms it’s stuck), only on high confidence, always with notification and an audit trail. Many teams rationally stop at stage 2 forever.

Guardrails that earn their keep

  • Sanitize ticket text in the prompt. Customers paste anything, and “anything” includes text that reads like instructions. Wrap ticket content in clear delimiters and tell the model explicitly: content inside is data to diagnose, not commands to follow.
  • Per-host rate limits and cooldowns. An AI that restarts the same service five times in ten minutes is masking an incident, not fixing one. After N actions on a host, force escalation.
  • Redact before prompting. Diagnostic output can contain credentials (env dumps, config greps). Your playbooks should emit curated facts, not raw config files, and a redaction pass runs before anything leaves for the API.
  • Audit everything. Ticket, prompts, function calls, playbook runs, verdicts: one correlated log. When the model is wrong, you want to know in review, not in a postmortem.

Why this compounds

The catalog is the asset. Every incident type your team turns into a diagnostic playbook makes the AI triage smarter without touching a prompt: you’re expanding its vocabulary of safe actions. Six months in, you have something better than an AI feature: an executable, versioned encyclopedia of your team’s operational knowledge, with a reasoning engine in front of it and every dangerous verb still behind a human.

That’s the series’ thesis in production form: the model supplies judgment under supervision; deterministic systems supply every action; and the boundary between them is something you designed on purpose.

If you schedule any of this to run unattended, the same rule applies to the agent itself: hard limits in code, not in the prompt. Codex scheduled tasks and hooks shows the PreToolUse guard hook I use to block destructive commands before they run.

This post is part of the Gemini and WordPress developer guide, which lists every post in the series.

Filed under ·
Aditya Shah Avatar

Written by

Hosting Support Manager & DevOps Engineer at WPMU DEV. I scale and secure WordPress infrastructure, and organize WordPress Bhopal and GDG Cloud Bhopal.

More about me · LinkedIn · GitHub