How to install docker using ansible on a Ubuntu Server
If you manage more than one server, installing Docker manually becomes a repetitive (and error-prone) checklist. This tutorial shows how to install docker using ansible on an Ubuntu Server by creating a reusable role that follows Docker’s official Ubuntu installation steps: configure the official APT repository, install the latest packages, and verify everything works.
We’ll start from zero: install Ansible on your local machine, set up a basic inventory, create a role, and run it against a remote Ubuntu host.
TL;DR (what you’ll build)
- An Ansible role named
dockerthat:- Installs prerequisites
- Adds Docker’s official GPG key (keyring)
- Adds Docker’s official APT repository (based on distro codename)
- Installs the latest
docker-ce,containerd.io, and plugins viaapt - Ensures the Docker service is enabled and running
- Optionally adds your user to the
dockergroup
- A playbook you can reuse across environments.
Prerequisites
- A local machine (Linux/macOS recommended) with:
- Python 3
- SSH client
- An Ubuntu Server (20.04/22.04/24.04) reachable via SSH
- A user on the server with
sudoprivileges
Note: This guide uses the official Docker APT repo approach (recommended) instead of Ubuntu’s default
docker.iopackage, which is often behind on versions.
Quick intro: what Ansible is (in practical terms)
Ansible is an automation tool that runs tasks over SSH to configure servers. You describe the desired state (packages installed, services running, files present), and Ansible makes it happen in an idempotent way, meaning you can run it multiple times and it won’t keep changing things unnecessarily.
For this tutorial, Ansible will:
- Connect to your Ubuntu host via SSH
- Configure Docker’s official repository and keyring
- Install Docker packages via
apt
Step 1: Install Ansible on your local machine
Option A: Install with pip (works almost everywhere)
python3 -m pip install --user ansible
# Verify
ansible --versionBashOption B: Install on Ubuntu/Debian via APT
sudo apt update
sudo apt install -y ansible
ansible --versionBashEither option is fine. Although, if you want more predictable versions across machines/CI, pip tends to be easier to standardize.
Step 2: Create a minimal Ansible project structure
Create a folder for your project:
mkdir -p ansible-docker-ubuntu && cd ansible-docker-ubuntu
mkdir -p roles group_vars
BashCreate an inventory file (inventory.ini):
cat > inventory.ini <<'EOF'
[docker_hosts]
ubuntu1 ansible_host=203.0.113.10 ansible_user=ubuntu
EOFBashReplace:
203.0.113.10with your server IPansible_userwith your SSH username (common values:ubuntu,ec2-user,root)
SSH access check
Before doing anything with Ansible, make sure SSH works:
If you need to use an SSH key explicitly, you can do it in Ansible too:
cat > inventory.ini <<'EOF'
[docker_hosts]
ubuntu1 ansible_host=203.0.113.10 ansible_user=ubuntu ansible_ssh_private_key_file=~/.ssh/id_rsa
EOFBashStep 3: Bootstrap Ansible config (recommended)
Create an ansible.cfg in the project root to avoid repeating flags:
cat > ansible.cfg <<'EOF'
[defaults]
inventory = inventory.ini
host_key_checking = False
interpreter_python = auto_silent
[privilege_escalation]
become = True
become_method = sudo
become_ask_pass = False
EOFINIGotcha: Disabling
host_key_checkingis convenient for tutorials and ephemeral hosts. In production, you may want it enabled to prevent MITM-style issues.
Step 4: Create the Docker installation role
Generate the role skeleton:
ansible-galaxy role init roles/dockerBashWe’ll implement the tasks in roles/docker/tasks/main.yml and keep variables in roles/docker/defaults/main.yml.
Role defaults (customizable variables)
Edit roles/docker/defaults/main.yml:
# roles/docker/defaults/main.yml
# Add a user to the docker group (so they can run docker without sudo)
docker_add_user_to_group: true
docker_user: "{{ ansible_user | default('ubuntu') }}"
# Docker packages from the official repository
docker_packages:
- docker-ce
- docker-ce-cli
- containerd.io
- docker-buildx-plugin
- docker-compose-plugin
YAMLMain tasks: follow Docker’s official repo steps
Now the important part: implement roles/docker/tasks/main.yml to match the official documentation flow.
---
# roles/docker/tasks/main.yml
- name: Ensure APT cache is updated
ansible.builtin.apt:
update_cache: true
cache_valid_time: 3600
- name: Install packages required to use Docker's APT repository
ansible.builtin.apt:
name:
- ca-certificates
- curl
- gnupg
state: present
- name: Ensure /etc/apt/keyrings exists
ansible.builtin.file:
path: /etc/apt/keyrings
state: directory
mode: "0755"
- name: Download Docker official GPG key
ansible.builtin.get_url:
url: https://download.docker.com/linux/ubuntu/gpg
dest: /etc/apt/keyrings/docker.asc
mode: "0644"
- name: Get dpkg architecture (amd64, arm64, ...)
ansible.builtin.command: dpkg --print-architecture
register: dpkg_arch
changed_when: false
- name: Add Docker official APT repository
ansible.builtin.apt_repository:
repo: >-
deb [arch={{ dpkg_arch.stdout }} signed-by=/etc/apt/keyrings/docker.asc]
https://download.docker.com/linux/ubuntu
{{ ansible_distribution_release }} stable
state: present
filename: docker
- name: Install Docker Engine from official repository
ansible.builtin.apt:
name: "{{ docker_packages }}"
state: latest
update_cache: true
- name: Ensure Docker service is enabled and started
ansible.builtin.service:
name: docker
state: started
enabled: true
- name: Add user to docker group (optional)
ansible.builtin.user:
name: "{{ docker_user }}"
groups: docker
append: true
when: docker_add_user_to_group | bool
- name: Verify docker works (docker version)
ansible.builtin.command: docker version
register: docker_version
changed_when: false
- name: Show docker version output
ansible.builtin.debug:
var: docker_version.stdout_lines
YAMLWhy this approach? It mirrors the official steps: install prerequisites, place the key in
/etc/apt/keyrings, configure the repo withsigned-by, then install packages with APT.
Common pitfall: After adding the user to the
dockergroup, the user must log out and back in (or you need to start a new SSH session) for group changes to apply.
Step 5: Create the playbook that uses the role
Create playbook.yml in the project root:
---
# playbook.yml
- name: Install Docker on Ubuntu hosts
hosts: docker_hosts
become: true
roles:
- docker
YAMLStep 6: Run the playbook
Run it:
ansible-playbook playbook.ymlBashIf your sudo requires a password, you can run:
ansible-playbook playbook.yml --ask-become-passBashStep 7: Validate on the server (real-world verification)
SSH into the host and run:
docker --version
sudo systemctl status docker --no-pager
# Optional: quick test container
sudo docker run --rm hello-worldBashIf you enabled the “add user to docker group” step, you can test without sudo after reconnecting:
Best practices (things that save you later)
Pin versions only if you must
This role installs state: latest, which is great for keeping systems updated, but it can surprise you if a newer Docker release changes behavior. If you need stricter control, pin versions (or manage updates with a controlled pipeline).
Don’t disable host key checking in production blindly
For real environments, keep SSH host key checking enabled and manage known_hosts properly. It’s a real security control.
Prefer SSH keys and least privilege
- Use SSH keys instead of passwords
- Use a non-root user with sudo
- Limit which hosts are targeted by inventory groups
Troubleshooting
“Permission denied” when running docker without sudo
- Make sure the user was added to the
dockergroup - Reconnect the SSH session (group changes require a new login)
- Check with:
idand confirmdockeris listed
APT repo added but packages don’t update
- Verify the repo file exists:
/etc/apt/sources.list.d/docker.list - Verify the keyring exists:
/etc/apt/keyrings/docker.asc - Run:
sudo apt updateand inspect errors
Architecture/codename mismatch
This role uses:
dpkg --print-architectureforarch={{ ansible_distribution_release }}for the Ubuntu codename (likejammy,focal)
If your host is not Ubuntu (or uses something unusual), the repo string needs adjustment.
Reference links
- Docker official docs (Ubuntu install): https://docs.docker.com/engine/install/ubuntu/
- Ansible docs: https://docs.ansible.com/
Conclusion
You now have a clean, reusable, and practical answer to how to install docker using ansible on Ubuntu Server. The key is using Docker’s official APT repository (not the distro package), and wrapping the steps in an idempotent role you can apply to any host group.
Next steps you can add without complicating the role too much:
- Install and configure UFW rules for published ports
- Configure Docker daemon options (
/etc/docker/daemon.json) - Add a separate role for deploying your containers (Compose, Swarm, or Kubernetes)
DevOps engineer with 10 years of experience in infrastructure, automation, and cloud computing.
João Silva has been working in infrastructure and development for over a decade, with experience in both startups and large companies. A specialist in Kubernetes, Docker, and AWS, he enjoys sharing knowledge in a practical and accessible way.
English 



