{"id":51331123,"url":"https://github.com/allamiro/ansible-controller","last_synced_at":"2026-07-01T23:03:42.847Z","repository":{"id":307556179,"uuid":"1029922868","full_name":"allamiro/ansible-controller","owner":"allamiro","description":"Ansible Controller :: Ubuntu-based Docker image for running Ansible playbooks with support for SSH, sudo, and external inventory mounts.","archived":false,"fork":false,"pushed_at":"2026-06-09T03:21:10.000Z","size":66,"stargazers_count":0,"open_issues_count":4,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-09T03:21:13.354Z","etag":null,"topics":["ansible","ansible-controller","automation","configuration-management","decops","docker","ssh-enabled","ubuntu"],"latest_commit_sha":null,"homepage":"","language":"Dockerfile","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/allamiro.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-07-31T19:45:35.000Z","updated_at":"2026-06-09T03:21:03.000Z","dependencies_parsed_at":"2025-07-31T23:16:44.462Z","dependency_job_id":"1ccc590e-f903-458e-97e0-8ecb5a13944e","html_url":"https://github.com/allamiro/ansible-controller","commit_stats":null,"previous_names":["allamiro/ansible-controller"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/allamiro/ansible-controller","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/allamiro%2Fansible-controller","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/allamiro%2Fansible-controller/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/allamiro%2Fansible-controller/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/allamiro%2Fansible-controller/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/allamiro","download_url":"https://codeload.github.com/allamiro/ansible-controller/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/allamiro%2Fansible-controller/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35025987,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-01T02:00:05.325Z","response_time":130,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ansible","ansible-controller","automation","configuration-management","decops","docker","ssh-enabled","ubuntu"],"created_at":"2026-07-01T23:03:41.401Z","updated_at":"2026-07-01T23:03:42.840Z","avatar_url":"https://github.com/allamiro.png","language":"Dockerfile","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![CI](https://github.com/allamiro/ansible-controller/actions/workflows/docker-image.yml/badge.svg?branch=main)](https://github.com/allamiro/ansible-controller/actions/workflows/docker-image.yml)\n[![Build \u0026 Publish](https://github.com/allamiro/ansible-controller/actions/workflows/docker-publish.yml/badge.svg?branch=main)](https://github.com/allamiro/ansible-controller/actions/workflows/docker-publish.yml)\n[![Last commit](https://img.shields.io/github/last-commit/allamiro/ansible-controller)](https://github.com/allamiro/ansible-controller)\n\n\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"assets/ansible-controller.png\" alt=\"Ansible Controller\" width=\"350\"/\u003e\n  \u003ch1\u003eAnsible Controller\u003c/h1\u003e\n  \u003cp\u003e\u003cstrong\u003eRun Ansible playbooks from any machine — no local Ansible installation required.\u003c/strong\u003e\u003c/p\u003e\n\n  [![Docker Pulls](https://img.shields.io/docker/pulls/allamiro1/ansible-controller)](https://hub.docker.com/r/allamiro1/ansible-controller)\n  [![Image Size](https://img.shields.io/docker/image-size/allamiro1/ansible-controller/latest)](https://hub.docker.com/r/allamiro1/ansible-controller)\n  [![License](https://img.shields.io/github/license/allamiro/ansible-controller)](LICENSE)\n  [![Latest Tag](https://img.shields.io/github/v/tag/allamiro/ansible-controller?label=version)](https://github.com/allamiro/ansible-controller/releases)\n\u003c/div\u003e\n\n---\n\nUbuntu 24.04-based Docker image that packages Ansible, OpenSSH, and everything needed to manage remote infrastructure. Write your playbooks on the host, mount them into the container, and run — no need to install Ansible locally.\n\n## Features\n\n- **Zero local dependencies** — only Docker required on the host\n- **SSH built-in** — connect into the controller or out to managed hosts\n- **Mount-based workflow** — playbooks, inventory, and SSH keys live on the host; no rebuild needed to change them\n- **Multi-platform** — ships `linux/amd64` and `linux/arm64` (Apple Silicon, AWS Graviton)\n- **Auto-versioned** — every push to `main` is automatically tagged via conventional commits\n- **Published to two registries** — Docker Hub and GitHub Container Registry (GHCR)\n- **Security hardened** — non-root `ansible` user, `PermitRootLogin no`, pip-upgraded CVE packages\n\n---\n\n## Table of Contents\n\n- [Prerequisites](#prerequisites)\n- [How it works](#how-it-works)\n- [Quick start](#quick-start)\n- [Pull the image](#pull-the-image)\n- [Makefile targets](#makefile-targets)\n- [Running playbooks](#running-playbooks)\n- [Ad-hoc commands](#ad-hoc-commands)\n- [Build from source](#build-from-source)\n- [Run with Docker (manual)](#run-with-docker-manual)\n- [Dynamic inventory](#dynamic-inventory)\n- [SSH keys for managed hosts](#ssh-keys-for-managed-hosts)\n- [SSH agent forwarding](#ssh-agent-forwarding-optional)\n- [Logs](#logs)\n- [Versioning and releases](#versioning-and-releases)\n- [Contributing](#contributing)\n- [License](#license)\n- [Notes](#notes)\n\n---\n\n## Prerequisites\n\n| Requirement | Minimum version | Notes |\n|-------------|----------------|-------|\n| Docker Engine | 20.10+ | [Install guide](https://docs.docker.com/engine/install/) |\n| Docker Compose | V2 (`docker compose`) | Included with Docker Desktop |\n\nNo other tools required. Ansible runs entirely inside the container.\n\n---\n\n## How it works\n\nYou write and store your playbooks on your host machine. The container provides Ansible and SSH. You mount your playbook directory into the container and tell Ansible where to find it.\n\n```\nHost machine                        Container\n──────────────────────────────      ────────────────────────────────\n~/my-project/\n  playbooks/        ──mount──→      /configs/\n    site.yml                          playbooks/site.yml\n    roles/                            roles/\n  inventory/        ──mount──→        inventory/hosts.ini\n  ssh/              ──mount──→      /home/ansible/.ssh/\n    id_ed25519                        id_ed25519  (used to reach remote hosts)\n```\n\nThe `docker-compose.yml` included in the repo already has all four mounts configured. If you add playbooks outside the `playbooks/` directory, add an extra volume entry for that path.\n\n---\n\n## Quick start\n\n### 1 — Clone the repo\n\n```bash\ngit clone https://github.com/allamiro/ansible-controller.git\ncd ansible-controller\n```\n\nThe repo already includes the full directory structure, `docker-compose.yml`, `ansible.cfg`, and example playbooks in `playbooks/`. Nothing to create manually.\n\n### 2 — Add your servers to the inventory\n\n```bash\n# Edit configs/inventory/hosts.ini and list your servers\ncat \u003e configs/inventory/hosts.ini \u003c\u003c 'EOF'\n[all]\n192.168.1.10\n192.168.1.11\n192.168.1.12\n\n[webservers]\n192.168.1.10\n192.168.1.11\n\n[databases]\n192.168.1.12\nEOF\n```\n\n### 3 — Generate an SSH key and copy it to your servers\n\n```bash\n# Generate a key pair into ssh/\nssh-keygen -t ed25519 -C \"ansible-controller\" -f ssh/id_ed25519 -N \"\"\nchmod 600 ssh/id_ed25519\n\n# Copy the public key to every unique host in the inventory\nfor host in $(grep -v '^\\[' configs/inventory/hosts.ini \\\n             | grep -v '^#' \\\n             | grep -v '^$' \\\n             | sort -u); do\n  ssh-copy-id -i ssh/id_ed25519.pub user@$host\ndone\n```\n\n### 4 — Start the container\n\n```bash\ndocker compose up -d\n```\n\n### 5 — Test connectivity\n\n```bash\n# Run the included ping playbook against all servers\ndocker exec -it ansible-controller \\\n  ansible-playbook /configs/playbooks/ping.yml\n```\n\nAll hosts should return `pong`. If they do, Ansible can reach your servers.\n\n### 6 — Add your own playbooks and run them\n\nDrop your playbooks into the `playbooks/` directory on the host:\n\n```bash\n# Example: create a simple playbook\ncat \u003e playbooks/deploy.yml \u003c\u003c 'EOF'\n---\n- name: Deploy application\n  hosts: webservers\n  tasks:\n    - name: Ensure nginx is installed\n      ansible.builtin.apt:\n        name: nginx\n        state: present\n      become: true\nEOF\n\n# Run it\ndocker exec -it ansible-controller \\\n  ansible-playbook /configs/playbooks/deploy.yml\n```\n\n### 7 — Open a shell inside the container (optional)\n\n```bash\nmake shell\n# or\ndocker exec -it ansible-controller bash\n```\n\n---\n\n## Pull the image\n\n**Docker Hub**\n```bash\ndocker pull allamiro1/ansible-controller:latest\n```\n\n**GitHub Container Registry (GHCR)**\n```bash\ndocker pull ghcr.io/allamiro/ansible-controller:latest\n```\n\n### Image tags\n\n| Tag | Description |\n|-----|-------------|\n| `latest` | Most recent successful build from `main` |\n| `sha-XXXXXXX` | Immutable pointer to a specific commit — use for pinned/reproducible deployments |\n| `v1.2.3` | Semantic version — published when a `v*` git tag is pushed |\n| `main` | Tracks the `main` branch |\n\n---\n\n## Makefile targets\n\n| Target | Description |\n|--------|-------------|\n| `make build` | Build the Docker image locally |\n| `make up` | Start the container in the background |\n| `make down` | Stop and remove the container |\n| `make shell` | Open an interactive bash shell inside the container |\n| `make run PLAYBOOK=site.yml` | Run an Ansible playbook |\n| `make logs` | Tail container logs |\n\n---\n\n## Running playbooks\n\n```bash\n# Basic run against the default inventory in ansible.cfg\ndocker exec -it ansible-controller \\\n  ansible-playbook /configs/playbooks/site.yml\n\n# Specify a user to connect as on the remote hosts\ndocker exec -it ansible-controller \\\n  ansible-playbook /configs/playbooks/site.yml -u deploy\n\n# Specify a different inventory file\ndocker exec -it ansible-controller \\\n  ansible-playbook /configs/playbooks/site.yml \\\n  -i /configs/inventory/hosts.ini\n\n# Run against a single host\ndocker exec -it ansible-controller \\\n  ansible-playbook /configs/playbooks/site.yml \\\n  -i \"192.168.1.10,\" -u deploy\n\n# Limit to a specific group or host from inventory\ndocker exec -it ansible-controller \\\n  ansible-playbook /configs/playbooks/site.yml --limit webservers\n\n# Pass extra variables\ndocker exec -it ansible-controller \\\n  ansible-playbook /configs/playbooks/site.yml \\\n  -e \"env=production version=1.2.3\"\n\n# Run only tasks with specific tags\ndocker exec -it ansible-controller \\\n  ansible-playbook /configs/playbooks/site.yml --tags \"install,configure\"\n\n# Dry run — show what would change without applying it\ndocker exec -it ansible-controller \\\n  ansible-playbook /configs/playbooks/site.yml --check --diff\n\n# Increase verbosity for troubleshooting\ndocker exec -it ansible-controller \\\n  ansible-playbook /configs/playbooks/site.yml -vv\n```\n\n### With roles\n\nRoles must be reachable from inside the container. If your project layout is:\n\n```\nplaybooks/\n  site.yml\n  roles/\n    webserver/\n    database/\n```\n\nThey are already available at `/configs/playbooks/roles/` inside the container. Reference them normally in your playbook:\n\n```yaml\n- hosts: webservers\n  roles:\n    - webserver\n    - database\n```\n\nIf roles live in a separate directory, mount them and set `roles_path` in `configs/ansible.cfg`:\n\n```ini\n[defaults]\nroles_path = /configs/roles:/configs/playbooks/roles\n```\n\n---\n\n## Ad-hoc commands\n\n```bash\n# Ping all hosts to verify connectivity\ndocker exec -it ansible-controller ansible all -m ping\n\n# Ping a specific group\ndocker exec -it ansible-controller ansible webservers -m ping\n\n# Run a shell command on all hosts\ndocker exec -it ansible-controller ansible all -m shell -a \"uptime\"\n\n# Check disk space\ndocker exec -it ansible-controller ansible all -m shell -a \"df -h\"\n\n# Gather all facts from a host\ndocker exec -it ansible-controller ansible server1 -m setup\n\n# Gather a specific fact\ndocker exec -it ansible-controller ansible all -m setup \\\n  -a \"filter=ansible_os_family\"\n\n# Copy a file to all hosts\ndocker exec -it ansible-controller ansible all -m copy \\\n  -a \"src=/configs/file.txt dest=/tmp/file.txt\"\n\n# Install a package (requires become)\ndocker exec -it ansible-controller ansible all -m apt \\\n  -a \"name=nginx state=present\" --become\n\n# Restart a service\ndocker exec -it ansible-controller ansible all -m service \\\n  -a \"name=nginx state=restarted\" --become\n\n# Reboot all hosts and wait for them to come back\ndocker exec -it ansible-controller ansible all -m reboot --become\n```\n\n---\n\n## Build from source\n\n```bash\ngit clone https://github.com/allamiro/ansible-controller.git\ncd ansible-controller\ndocker build -t ansible-controller:local -f docker/Dockerfile .\n```\n\n---\n\n## Run with Docker (manual)\n\n```bash\n# Prepare ssh/ directory first (see Quick start step 1)\n\ndocker run -d --name ansible-controller \\\n  -p 2222:22 \\\n  -v \"$PWD/configs\":/configs:rw \\\n  -v \"$PWD/playbooks\":/configs/playbooks:ro \\\n  -v \"$PWD/logs\":/var/log/ansible:rw \\\n  -v \"$PWD/ssh\":/home/ansible/.ssh:ro \\\n  ansible-controller:latest\n```\n\n\u003e **Note:** Mount the entire `ssh/` directory (not a single file). Set `chmod 700 ssh` and `chmod 600 ssh/authorized_keys` on the host before starting.\n\n---\n\n## Dynamic inventory\n\nA dynamic inventory script is included at `configs/inventory/inventory.py`. It reads hosts from `configs/inventory/hosts.json` when present and falls back gracefully when the file is absent.\n\n**hosts.json example:**\n```json\n{\n  \"all\": {\n    \"hosts\": [\"192.168.1.10\", \"192.168.1.11\"],\n    \"vars\": { \"ansible_user\": \"ansible\" }\n  },\n  \"webservers\": {\n    \"hosts\": [\"192.168.1.10\"],\n    \"vars\": {}\n  }\n}\n```\n\n**Use it:**\n```bash\ndocker exec -it ansible-controller \\\n  ansible-playbook -i /configs/inventory/inventory.py /configs/playbooks/site.yml\n```\n\n---\n\n## SSH keys for managed hosts\n\nTo allow the controller to connect passwordlessly to your managed servers, generate a key pair on the host and let the container pick it up via the volume mount.\n\n```bash\n# Generate the key pair into the ssh/ directory\nssh-keygen -t ed25519 -C \"ansible-controller\" -f ssh/id_ed25519 -N \"\"\nchmod 600 ssh/id_ed25519\n```\n\nCopy the public key to every server you want Ansible to manage:\n\n```bash\nssh-copy-id -i ssh/id_ed25519.pub user@server1\nssh-copy-id -i ssh/id_ed25519.pub user@server2\n```\n\nTell Ansible to use the key by adding this to `configs/ansible.cfg`:\n\n```ini\n[defaults]\nprivate_key_file = /home/ansible/.ssh/id_ed25519\n```\n\nThe private key is available inside the container at `/home/ansible/.ssh/id_ed25519` via the volume mount. Restart the container after adding the key if it was already running.\n\n---\n\n## SSH agent forwarding (optional)\n\nTo use your host SSH keys inside the container without copying them to disk, uncomment the volume and environment entries in `docker-compose.yml`:\n\n```yaml\nvolumes:\n  - ${SSH_AUTH_SOCK}:/run/host-services/ssh-auth.sock\nenvironment:\n  - SSH_AUTH_SOCK=/run/host-services/ssh-auth.sock\n```\n\nMake sure your key is loaded on the host first:\n\n```bash\nssh-add ~/.ssh/id_ed25519\n```\n\n---\n\n## Logs\n\nAnsible logs are written to `/var/log/ansible/ansible.log` inside the container and persisted to `./logs/ansible.log` on the host via the volume mount.\n\n```bash\n# Tail logs from the host\ntail -f logs/ansible.log\n\n# Or from inside the container\ndocker exec -it ansible-controller tail -f /var/log/ansible/ansible.log\n```\n\n---\n\n## Versioning and releases\n\nEvery push to `main` is automatically tagged based on [conventional commit](https://www.conventionalcommits.org/) prefixes:\n\n| Commit prefix | Version bump | Example |\n|---------------|--------------|---------|\n| `fix:` / `perf:` / `refactor:` | patch | `v1.0.0` → `v1.0.1` |\n| `feat:` | minor | `v1.0.0` → `v1.1.0` |\n| `feat!:` / `BREAKING CHANGE` | major | `v1.0.0` → `v2.0.0` |\n\nThe new git tag triggers the publish workflow which:\n- Builds and pushes `v1.2.3`, `v1.2`, `v1`, `latest` tags to both Docker Hub and GHCR\n- Creates a GitHub Release with auto-generated changelog\n\n---\n\n## Contributing\n\nContributions are welcome. Please open an issue before submitting a pull request so the change can be discussed first.\n\n1. Fork the repository\n2. Create a feature branch: `git checkout -b feat/my-feature`\n3. Commit using [conventional commits](https://www.conventionalcommits.org/): `feat:`, `fix:`, `docs:` etc.\n4. Push and open a pull request against `main`\n\nBug reports, feature requests, and documentation improvements are all appreciated.\n\n---\n\n## License\n\nThis project is licensed under the [Apache License 2.0](LICENSE).\n\n---\n\n## Notes\n\n- **Base image:** Ubuntu 24.04 LTS (Noble Numbat) — standard security support until April 2029, extended to 2034 with Ubuntu Pro.\n- If `configs/ansible.cfg` exists on the host it is used automatically; otherwise the image default applies.\n- The `ansible` user (uid 1000) is the only user inside the container. `PermitRootLogin no` is enforced.\n- SSH host keys are generated at image build time (`ssh-keygen -A`).\n- A `HEALTHCHECK` verifies sshd is listening on port 22. Check container health with `docker ps`.\n\n---\n\n\u003cdiv align=\"center\"\u003e\n  \u003csub\u003eBuilt with care · \u003ca href=\"https://hub.docker.com/r/allamiro1/ansible-controller\"\u003eDocker Hub\u003c/a\u003e · \u003ca href=\"https://ghcr.io/allamiro/ansible-controller\"\u003eGHCR\u003c/a\u003e\u003c/sub\u003e\n\u003c/div\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fallamiro%2Fansible-controller","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fallamiro%2Fansible-controller","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fallamiro%2Fansible-controller/lists"}