How to Install Docker on AlmaLinux 10 (Step-by-Step)

Install Docker on AlmaLinux 10 with Docker’s RPM repository, Compose v2, firewalld-safe testing, non-root access, and fixes for common errors.
A polished 3D server rack with glowing container blocks and a subtle orange accent on a midnight-blue background.

Install Docker on AlmaLinux 10 with Docker Engine, Compose v2, and a non-root administration setup. In about ten minutes, you will run a verified container and a local web test without exposing a new service to the public internet.

Prerequisites

  • A 64-bit AlmaLinux 10 VPS with a current package index, at least 2 GB of RAM, and 10 GB of free disk space.
  • SSH access as root, or a normal Linux account with working sudo privileges.
  • Outbound HTTPS access to Docker’s package repository and Docker Hub.
  • No domain is needed for this installation or the local smoke test. Use a domain later if you put a public application behind a TLS reverse proxy.
  • A VPSLake Linux VPS if you need an AlmaLinux server with root access.

The commands use sudo for a normal SSH user. If you are logged in as root, remove sudo. AlmaLinux uses DNF and firewalld; do not substitute Ubuntu’s apt or ufw commands.

Step 1: Confirm AlmaLinux 10 and update the host

Checking the release first prevents you from adding a repository for a different Enterprise Linux version.

grep -E '^(PRETTY_NAME|VERSION_ID|ID_LIKE)=' /etc/os-release
uname -m
sudo dnf -y upgrade

The release should identify AlmaLinux 10 and the architecture should normally be x86_64:

PRETTY_NAME="AlmaLinux 10.x (Cerulean Lion)"
VERSION_ID="10.x"
ID_LIKE="rhel centos fedora"
x86_64

The exact minor release changes as AlmaLinux publishes updates. Resolve any DNF mirror, DNS, or signature error before installing Docker.

Step 2: Remove packages that conflict with Docker Engine

Distribution-provided Docker packages, Podman, and a separately installed runtime can conflict with Docker’s bundled containerd and networking components.

On a new VPS, remove the possible conflicting packages with DNF:

sudo dnf remove -y docker \
  docker-client \
  docker-client-latest \
  docker-common \
  docker-latest \
  docker-latest-logrotate \
  docker-logrotate \
  docker-engine \
  podman \
  runc

If DNF says a package is not installed, that is expected. Removing these packages does not automatically delete Docker data under /var/lib/docker/, but do not remove a package from a production host until you have checked which workloads depend on it.

Step 3: Add Docker’s signed RPM repository

The repository supplies Docker Engine, its CLI, containerd, Buildx, and the maintained Compose plugin as a compatible package set.

Install the repository-management tools and add Docker’s RHEL-compatible repository for AlmaLinux 10:

sudo dnf install -y dnf-plugins-core ca-certificates
sudo dnf config-manager --add-repo https://download.docker.com/linux/rhel/docker-ce.repo
sudo dnf makecache

Confirm that DNF can see an Engine candidate before installing anything:

dnf list --showduplicates docker-ce | tail -n 5

You should see one or more docker-ce entries from download.docker.com. Docker publishes new patch versions regularly, so the version and release date will differ from this example.

For the repository prerequisites and package names, see Docker’s RHEL installation documentation. AlmaLinux’s compatible Enterprise Linux package interfaces let DNF use this package path.

Step 4: Install Docker Engine and Compose v2

These packages install the daemon, CLI, runtime, Buildx builder, and the docker compose subcommand in one transaction.

sudo dnf install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo systemctl enable --now docker

Check the service and command-line tools immediately:

sudo systemctl is-active docker
sudo systemctl is-enabled docker
sudo docker version --format 'Client {{.Client.Version}} / Server {{.Server.Version}}'
sudo docker compose version

Expected output has an active, enabled service and matching client/server versions. Patch numbers will change:

active
enabled
Client 29.x.y / Server 29.x.y
Docker Compose version v2.x.y

Step 5: Run Docker’s installation test

The hello-world image proves that the CLI can reach the daemon, pull an image, create a container, and run it successfully.

sudo docker run --rm hello-world

Look for this confirmation near the end of the output:

Hello from Docker!
Your installation appears to be working correctly.

The container exits after printing the message, and --rm removes its stopped container record. The small image remains cached until you prune it.

Step 6: Allow a trusted account to run Docker

Docker’s Unix socket is root-owned by default. The docker group removes repeated sudo prompts, but membership is effectively administrative access to the host.

Run this block from the normal sudo-enabled account that should manage containers, not from a root shell:

sudo groupadd --force docker
sudo usermod -aG docker "$USER"

Log out of SSH completely and reconnect so the new group is loaded. Then check access without sudo:

id -nG
docker info --format 'Server {{.ServerVersion}}'

The group list should include docker, and the second command should print the Engine version. Until you reconnect, use newgrp docker or keep using sudo docker.

Step 7: Test a local web container

This test checks Docker networking while binding the host port to loopback, so a random internet client cannot reach the container.

docker run -d --name almalinux-docker-test --publish 127.0.0.1:8080:80 nginx:alpine
docker ps --filter name=almalinux-docker-test --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'
curl --head http://127.0.0.1:8080

The container should be running and curl should receive an HTTP success response:

NAMES                  STATUS        PORTS
almalinux-docker-test  Up ...        127.0.0.1:8080->80/tcp
HTTP/1.1 200 OK

Remove the disposable test when you are finished:

docker stop almalinux-docker-test
docker rm almalinux-docker-test

Verify Docker on AlmaLinux 10

Run this final check to confirm service startup, daemon communication, Compose, and the container runtime:

systemctl is-active docker
systemctl is-enabled docker
docker version --format 'Client {{.Client.Version}} / Server {{.Server.Version}}'
docker compose version
docker info --format 'Containers {{.Containers}} | Images {{.Images}} | Storage {{.Driver}}'

Expected results include active, enabled, Docker client/server versions, a Compose v2 version, and a storage driver such as overlay2:

active
enabled
Client 29.x.y / Server 29.x.y
Docker Compose version v2.x.y
Containers 0 | Images 2 | Storage overlay2

Docker is ready for a Compose project or application image. For firewall behavior and published ports, read Docker’s packet-filtering and firewalls guide.

Troubleshooting

No match for argument: docker-ce

DNF has not loaded Docker’s repository, or the repository was added for a different Enterprise Linux release. Inspect the repo file and refresh metadata:

sudo dnf repolist --enabled | grep -i docker
sudo dnf makecache
dnf list --showduplicates docker-ce

The enabled list should contain Docker’s repository and the package list should show an el10 build. If the repo file is missing, run the dnf config-manager --add-repo command from Step 3 again.

package podman ... conflicts with ... during installation

Podman or a standalone runc package is still installed and owns files Docker expects to manage. On a fresh host, rerun the removal block from Step 2, then retry the Docker package installation; do not remove a runtime that a current production service still needs without a migration plan.

permission denied while trying to connect to the Docker daemon socket

Your SSH session was opened before the account joined the docker group, or you ran the group command from a different account. Reconnect, run id -nG, and retry. sudo docker info is a temporary workaround, while newgrp docker reloads group membership in the current shell.

curl: (7) Failed to connect to 127.0.0.1 port 8080

The test container stopped, the image is still downloading, or another process already owns port 8080. Check the container state and logs:

docker ps -a --filter name=almalinux-docker-test
docker logs almalinux-docker-test
docker port almalinux-docker-test

If another local service owns the port, repeat the test with --publish 127.0.0.1:18080:80 and curl http://127.0.0.1:18080. Because the example binds only to loopback, you do not need to open 8080 in firewalld.

Hardening

  • Keep Docker on its Unix socket. Never expose an unauthenticated Docker API on TCP port 2375; remote administration requires a deliberately configured TLS endpoint and narrow firewall rules.
  • Treat the docker group as root-equivalent access. Use Docker rootless mode when the workload needs a stronger privilege boundary.
  • Keep test and internal application ports on 127.0.0.1. If a web service must be public, publish only ports 80 and 443 and open the matching firewalld services:
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
  • Keep SELinux enabled. When a container bind-mounts a host directory, use a private :Z label, for example -v /srv/app:/app:Z, instead of weakening file permissions or disabling SELinux.

FAQ

Is Docker supported on AlmaLinux 10?

AlmaLinux 10 follows the Enterprise Linux 10 interfaces that Docker’s RHEL package instructions target. The repository method in this guide uses DNF and Docker’s el10 packages, while the exact package versions change as Docker publishes updates.

Should I use Podman instead of Docker on AlmaLinux?

Podman is a strong daemonless option and is commonly available in the AlmaLinux repositories. Choose Docker when your deployment, Compose files, tooling, or team workflow specifically expects the Docker Engine and CLI; do not run both engines casually with overlapping runtime packages.

Where does Docker store images and containers?

The default data root is /var/lib/docker, with containerd data under /var/lib/containerd. Keep that space on a filesystem with enough capacity, and use Docker’s own prune commands only after checking which images, stopped containers, and volumes are disposable.

How do I publish a container safely?

Bind internal services to 127.0.0.1 and put a TLS reverse proxy in front of them when they do not need direct public access. For a public service, publish only its required ports and align firewalld and Docker’s packet-filtering rules with the application design.

Samrat Ghosh
Written by

Samrat Ghosh

Founder & Infrastructure Engineer

Samrat Ghosh is the founder of VPSLake, where he builds and runs the remote desktop and VPS hosting infrastructure the company is built on. He writes hands-on guides about RDP, Windows Server, VPS management and secure remote access - the practical documentation he wishes had…

Previous Article

5 Best FireVPS Alternatives in 2026

Next Article

How to Install Docker on AlmaLinux 8 (Step-by-Step)

Write a Comment

Leave a Comment

Your email address will not be published. Required fields are marked *

Subscribe to our Newsletter

Subscribe to our email newsletter to get the latest posts delivered right to your email.
Pure inspiration, zero spam ✨