How to Install Docker in Ubuntu 22.04: A 2025 Quick Start Guide

Install Docker in Ubuntu
Install Docker in Ubuntu: A 2025 Quick Guide

Okay! You’ve been looking for the latest comprehensive tutorial to help you install Docker in Ubuntu in 2025, right? Worry no more, as you have found the right one. Deploying Docker on an Ubuntu 22.04 VM is easier than you think. This guide walks you through provisioning the VM, connecting via SSH, installing Docker Engine and Docker Compose, and launching your first container in clear step-by-step commands. By the end, you’ll have a secure, production-ready Docker setup on Azure.

Please note that for this step-by-step tutorial, we are going to be using an Azure Virtual Machine setup, but you’re free to use any cloud provider you like. All good? Let’s dive in.

1. Deploy Ubuntu 22.04 VM on Azure

To get started with Azure, you’re going to need an Azure account with credits. For my case, I am using a student account with an “Azure for Students Starter” subscription activated. But also, azure offers a free account with $200 worth of credits to use for the first month, after that, you will be required to upgrade your account to Pay-As-You-Go.

To get started, first head to Azure Portal and search for Azure Virtual Machine, then select it from the resulting menu. It should look like the screenshot below:

Install Docker in Ubuntu: Azure Virtual Machines Display Page
Azure Virtual Machines Display Page

The next step you want to take is to click the + Create button and select Virtual Machine. On the resulting page, type or select the following details to provision an Azure virtual machine.

  • Resource Group – Either select or create a New one.
  • Virtual machine name – Type a name for your virtual machine, e.g., MyVM1
  • Region – It is recommended you select a region closest to you to reduce latency, and also a region that supports the Ubuntu 22.04 virtual machine (some regions do not support Ubuntu VMs; choose wisely).
  • Availability zones – For this tutorial, I am going to choose a single zone, but you can choose up to three, depending on the type of workload you plan to use with the virtual machine.
  • Security type – select either the Standard plan or Trusted Launch Virtual Machines.
  • Image – Select Ubuntu Server 22.04 LTS – x64 Gen2.
  • When it comes to the size, select Standard_B2MS-2VCPUs, 8 GIB Memory.
  • For authentication type, select SSH public key, set your username, select Generate new key pair, and type your Key pair name.
  • For the ports, select port 22, which is used for Secure Shell (SSH), used to connect to your virtual machine remotely from your local machine.
  • Next, head to the Networking tab, create a new Virtual Network. Leave the Subnet and Public IP as default, and check the following Delete public IP and NIC when VM is deleted. Leave everything else as default and…
Install Docker in Ubuntu: Configuring VM Network Interface
Configuring VM Network Interface


Finally, click review + create to confirm your VM details

Now you should see your deployment initializing as seen below:

Install Docker in Ubuntu: Initializing Deployment
Initializing Deployment

2. SSH into Your Azure VM

Now that we have successfully initialized an Ubuntu Server 22.04 virtual machine, it’s time to SSH into it. SSH means accessing the remote server from our local machine without physically interacting. For this we have two ways; the first one is to SSH using a command-line interface or using a Graphical User Interface (GUI) application such as MobaXTerm, which we shall use for this tutorial.

2.1 Using the Command-line to SSH to Ubuntu VM

To SSH to your remote virtual machine using the command line purely, you need to place the SSH public key you downloaded previously in a location you know, and then open the command line to that location. Then run the following command:

ssh -i ~/path/to/myKey.pem <user>@<YOUR_UBUNTU_IP_ADDRESS>

The -i tells the SSH command which public key file to use by following the path, and then the <user> specifies the username that you set up earlier and then the <YOUR_UBUNTU_IP_ADDRESS> specifies the public IP address of your machine (this one you can find it on the resource page in Azure or your own cloud provider VMs page).

2.2 Using the MobaXTerm GUI to SSH to Ubuntu VM

Accessing the Ubuntu VM using MobaXTerm is very easy. You just need to download it here and install it, then launch the application to present an interface as follows:

Install Docker in Ubuntu: MobaXTerm Interface
MobaXTerm Interface

Now to connect to the VM from here, we do the following:

  • Click on New Session, then choose SSH.
  • Specify the Remote Host, i.e, the VM Public IP, and also the username.
  • Then click on advanced SSH settings and select the private key you downloaded.
  • Finally, click OK to connect to your VM
Install Docker in Ubuntu: Setting up SSH Credentials
Setting up SSH Credentials

Once successfully connected, you should see the following logs:

Install Docker in Ubuntu: Successful Connection to Ubuntu VM
Successful Connection to Ubuntu VM

3. Prepare Ubuntu for Docker Installation

To prepare Ubuntu for Docker Installation, we need to run the following command on the MobaXterm command line, which updates your existing list of packages:

sudo apt update

4. Install Docker Engine

To install Docker, we are going to follow the list of instructions below:

  •  Install a few prerequisite packages that let apt use packages over HTTPS:
sudo apt install apt-transport-https ca-certificates curl software-properties-common
  • Then add the GPG key for the official Docker repository to your system:
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
  • Add the Docker repository to APT sources:
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
  • Update your existing list of packages again for the addition to be recognized:
sudo apt update
  • Run the following to make sure you are about to install from the Docker repo instead of the default Ubuntu repo:
apt-cache policy docker-ce

You should see the following output confirming we are on the right track:

Install Docker in Ubuntu: Output of apt-cache policy docker-ce
  • Finally, install Docker:
sudo apt install docker-ce

Docker should now be installed, the daemon started, and the process enabled to start on boot. Check that it’s running:

sudo systemctl status docker

The output should be similar to the following, showing that the service is active and running:

Install Docker in Ubuntu: Output of Docker is Running
Output of Docker is Running

5. Grant Non‑Root Access to Docker

5.1 Running Docker Without sudo

By default, Docker commands only work for the root user or anyone in the special docker group that gets created during installation. If you’re logged in as an ordinary user and try:

docker run hello-world

You’ll see something like:

docker: Cannot connect to the Docker daemon. Is the docker daemon running on this host?
See ‘docker run --help’.

5.1.1. Add Yourself to the docker Group

Instead of typing sudo every time, you can give your user account permission to talk to the Docker daemon:

sudo usermod -aG docker $USER
  • -aG docker tells the system “append this user to the docker group.”
  • $USER is your current username.

5.1.2. Activate the Change

For your new group membership to take effect, either:

  • Log out and then log back in, or
  • Run:
su - $USER

You’ll be asked to re-enter your user password. This step reloads your group settings in the current shell.

5.1.3. Verify Your Membership

Once you’ve re-connected, check which groups you belong to:

groups

You should see at least:

yourusername sudo docker

That “docker” entry means you can now run docker commands directly.

5.1.4. Adding Other Users

If you need to grant Docker access to someone else on the machine, replace $USER with their username:

sudo usermod -aG docker their-username

Note: From this point on, I’ll assume you’re running Docker commands as a member of the docker group. If you ever need to, you can still prefix with sudo.

5.2. Using the Docker Command

Using docker consists of passing it a chain of options and commands, followed by arguments. The syntax takes this form:

docker [option] [command] [arguments]
  • To view all available subcommands, type:
docker

As of Docker version 28.2.2, the complete list of available subcommands includes:

azureuser@MyUbuntu1:~$ docker
Usage:  docker [OPTIONS] COMMAND

A self-sufficient runtime for containers

Common Commands:
  run         Create and run a new container from an image
  exec        Execute a command in a running container
  ps          List containers
  build       Build an image from a Dockerfile
  bake        Build from a file
  pull        Download an image from a registry
  push        Upload an image to a registry
  images      List images
  login       Authenticate to a registry
  logout      Log out from a registry
  search      Search Docker Hub for images
  version     Show the Docker version information
  info        Display system-wide information

Management Commands:
  builder     Manage builds
  buildx*     Docker Buildx
  checkpoint  Manage checkpoints
  compose*    Docker Compose
  container   Manage containers
  context     Manage contexts
  image       Manage images
  manifest    Manage Docker image manifests and manifest lists
  network     Manage networks
  plugin      Manage plugins
  system      Manage Docker
  trust       Manage trust on Docker images
  volume      Manage volumes

Swarm Commands:
  config      Manage Swarm configs
  node        Manage Swarm nodes
  secret      Manage Swarm secrets
  service     Manage Swarm services
  stack       Manage Swarm stacks
  swarm       Manage Swarm

Commands:
  attach      Attach local standard input, output, and error streams to a running container
  commit      Create a new image from a container's changes
  cp          Copy files/folders between a container and the local filesystem
  create      Create a new container
  diff        Inspect changes to files or directories on a container's filesystem
  events      Get real time events from the server
  export      Export a container's filesystem as a tar archive
  history     Show the history of an image
  import      Import the contents from a tarball to create a filesystem image
  inspect     Return low-level information on Docker objects
  kill        Kill one or more running containers
  load        Load an image from a tar archive or STDIN
  logs        Fetch the logs of a container
  pause       Pause all processes within one or more containers
  port        List port mappings or a specific mapping for the container
  rename      Rename a container
  restart     Restart one or more containers
  rm          Remove one or more containers
  rmi         Remove one or more images
  save        Save one or more images to a tar archive (streamed to STDOUT by default)
  start       Start one or more stopped containers
  stats       Display a live stream of container(s) resource usage statistics
  stop        Stop one or more running containers
  tag         Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
  top         Display the running processes of a container
  unpause     Unpause all processes within one or more containers
  update      Update configuration of one or more containers
  wait        Block until one or more containers stop, then print their exit codes

Global Options:
      --config string      Location of client config files (default "/home/azureuser/.docker")
  -c, --context string     Name of the context to use to connect to the daemon (overrides DOCKER_HOST env
                           var and default context set with "docker context use")
  -D, --debug              Enable debug mode
  -H, --host list          Daemon socket to connect to
  -l, --log-level string   Set the logging level ("debug", "info", "warn", "error", "fatal") (default "info")
      --tls                Use TLS; implied by --tlsverify
      --tlscacert string   Trust certs signed only by this CA (default "/home/azureuser/.docker/ca.pem")
      --tlscert string     Path to TLS certificate file (default "/home/azureuser/.docker/cert.pem")
      --tlskey string      Path to TLS key file (default "/home/azureuser/.docker/key.pem")
      --tlsverify          Use TLS and verify the remote
  -v, --version            Print version information and quit

Run 'docker COMMAND --help' for more information on a command.

For more help on how to use Docker, head to https://docs.docker.com/go/guides/

5.2.1. Getting Help with Docker Commands

If you ever need a quick reminder of what a Docker subcommand can do, simply run:

docker <subcommand> --help

Docker will then display all the flags and options available for that particular command.

5.2.2. Checking Your Docker Setup

To peek under the hood and see details about your entire Docker installation—things like version info, running containers count, and storage drivers—just type:

docker info

6. Working with Docker Images

Docker containers are built from Docker images. By default, Docker pulls these images from Docker Hub, a Docker registry managed by Docker, the company behind the Docker project. Anyone can host their Docker images on Docker Hub, so most applications and Linux distributions you’ll need will have images hosted there.

To check whether you can access and download images from Docker Hub, run the following to pull the default hello-world container:

docker run hello-world

This command will check to see if the hello-world container is present locally; if it’s not, then it will go to Docker Hub and pull the image and run the respective container. The output below indicates that Docker is working correctly:

azureuser@MyUbuntu1:~$ sudo docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
e6590344b1a5: Pull complete
Digest: sha256:940c619fbd418f9b2b1b63e25d8861f9cc1b46e3fc8b018ccfe8b78f19b8cc4f
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

You can search for images available on Docker Hub by using the docker command with the search subcommand. For example, to search for the Nginx image, type:

docker search nginx

The script will crawl Docker Hub and return a listing of all images whose name matches the search string. In this case, the output will be similar to this:

azureuser@MyUbuntu1:~$ sudo docker search nginx
NAME                                     DESCRIPTION                                     STARS     OFFICIAL
nginx                                    Official build of Nginx.                        20856     [OK]
nginx/nginx-ingress                      NGINX and  NGINX Plus Ingress Controllers fo109
nginx/nginx-prometheus-exporter          NGINX Prometheus Exporter for NGINX and NGIN50
nginx/unit                               This repository is retired, use the Docker o65
nginx/nginx-ingress-operator             NGINX Ingress Operator for NGINX and NGINX P2
nginx/nginx-quic-qns                     NGINX QUIC interop                              1
nginx/nginxaas-loadbalancer-kubernetes                                                   1
nginx/unit-preview                       Unit preview features                           0
bitnami/nginx                            Bitnami container image for NGINX               199
ubuntu/nginx                             Nginx, a high-performance reverse proxy & we129
bitnamicharts/nginx                      Bitnami Helm chart for NGINX Open Source        0
kasmweb/nginx                            An Nginx image based off nginx:alpine and in8
rancher/nginx                                                                            2
linuxserver/nginx                        An Nginx container, brought to you by LinuxS231
dtagdevsec/nginx                         T-Pot Nginx                                     0
vmware/nginx                                                                             2
paketobuildpacks/nginx                                                                   0
gluufederation/nginx                      A customized NGINX image containing a consu1
chainguard/nginx                         Build, ship and run secure software with Cha4
intel/nginx                                                                              0
antrea/nginx                             Nginx server used for Antrea e2e testing        0
droidwiki/nginx                                                                          0
circleci/nginx                           This image is for internal use                  2
corpusops/nginx                          https://github.com/corpusops/docker-images/     1
docksal/nginx                            Nginx service image for Docksal                 0

In the OFFICIAL column, OK indicates an image built and supported by the company behind the project. Once you’ve identified the image that you would like to use, you can download it to your computer using the pull subcommand.

docker pull nginx

To see the images that have been downloaded to your computer, type:

docker images

The output will look similar to the following:

azureuser@MyUbuntu1:~$ sudo docker images
REPOSITORY    TAG       IMAGE ID       CREATED        SIZE
nginx         latest    1e5f3c5b981a   2 months ago   192MB
hello-world   latest    74cc54e27dc4   4 months ago   10.1kB

Now, let us switch gears a bit and see how to install and run a simple HTML application using Docker Compose.

7. Install Docker Compose

Docker makes it easy to package and run applications in containers—lightweight, resource-efficient alternatives to virtual machines. Yet when your app relies on multiple services (for example, a web server, database, and cache), coordinating all those containers by hand can get messy.

That’s where Docker Compose comes in. With Docker Compose, you describe your entire multi-container setup—services, networks, volumes—in a simple YAML file. Then a single command brings the whole environment up or tears it down, ensuring everything starts, links, and shuts down together exactly as defined.

In this section, we’ll walk through installing Docker Compose on an Ubuntu 22.04 server and show you how to launch your first multi-service stack.

To make sure you obtain the most updated stable version of Docker Compose, you’ll download this software from its official Github repository.

First, confirm the latest version available in their releases page. At the time of this writing, the most current stable version is 2.37.1.

Use the following command to download:

mkdir -p ~/.docker/cli-plugins/
curl -SL https://github.com/docker/compose/releases/download/v2.37.1/docker-compose-linux-x86_64 -o ~/.docker/cli-plugins/docker-compose

Next, set the correct permissions so that the docker compose command is executable:

chmod +x ~/.docker/cli-plugins/docker-compose

To verify that the installation was successful, you can run:

docker compose version

You’ll see output similar to the following:


azureuser@MyUbuntu1:~$ docker compose version
Docker Compose version v2.37.1

Docker Compose is now successfully installed on your system. In the next section, you’ll see how to set up a docker-compose.yml file and get a containerized environment up and running with this tool.

7.1. Creating a docker-compose.YAML File

To demonstrate how to set up a docker-compose.yml file and work with Docker Compose, you’ll create a web server environment using the official Nginx image from Docker Hub, the public Docker registry. This containerized environment will serve a single static HTML file.

Start off by creating a new directory in your home folder, and then moving into it:

mkdir ~/dcompose-demo
cd ~/dcompose-demo

In this directory, we are going to set up an application folder to serve as the document root for your Nginx environment:

mkdir myapp

Using your preferred text editor, create a new index.html file within the myapp folder:

nano myapp/index.html

Insert the following HTML snippet inside

/*~/compose-demo/myapp/index.html*/

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Docker Compose Small Demo</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/kognise/water.css@latest/dist/dark.min.css">
</head>
<body>

    <h1>This is a Docker Compose Demo Page.</h1>
    <p>This content is being served by an Nginx container.</p>

</body>
</html>

Save and close the file when you’re done. If you are using nano, you can do that by typing CTRL+X, then Y and ENTER to confirm.

Define your docker-compose.yml file:

nano docker-compose.yml

Create (or open) a file named docker-compose.yml in your project directory and add:

version: '3.7'
services:
  web:
    image: nginx:alpine
    ports:
      - "8000:80"
    volumes:
      - ./myapp:/usr/share/nginx/html

Here’s what each section does:

  1. version: Specifies the Compose file format version.
  2. services: Lists the containers you want to run. In our case, we have a single service called web.
  3. image: Tells Docker Compose to use the nginx:alpine image.
  4. ports: Maps port 8000 on your host (where you run Compose) to port 80 inside the container, where Nginx listens.
  5. volumes: Mounts your local ./app folder into /usr/share/nginx/html inside the container, replacing Nginx’s default web root with your demo files.

Save and close the file. You now have a simple “hello world” web server setup ready to launch.

7.2. Launch Your Multi-Container App

With docker-compose.yml in place, bring everything up with:

docker compose up -d
  • The Docker Compose checks your machine for the nginx:alpine image.
  • If it’s missing, Compose pulls it from Docker Hub.
  • Then it creates a Docker network, starts the web container, and runs it in the background.

You’ll see an output like:

azureuser@MyUbuntu1:~/dcompose-demo$ sudo docker compose up -d
WARN[0000] /home/azureuser/dcompose-demo/docker-compose.yml: the attribute `version` is obsolete, it will be ignored, please remove it to avoid potential confusion
[+] Running 9/9
web Pulled                                                                                              3.2s
f18232174bc9 Pull complete                                                                            0.3s
   ✔ 61ca4f733c80 Pull complete                                                                            1.0s
b464cfdf2a63 Pull complete                                                                            1.1s
d7e507024086 Pull complete                                                                            1.2s
   ✔ 81bd8ed7ec67 Pull complete                                                                            1.3s
   ✔ 197eb75867ef Pull complete                                                                            1.4s
   ✔ 34a64644b756 Pull complete                                                                            1.5s
   ✔ 39c2ddfd6010 Pull complete                                                                            2.7s
[+] Running 2/2
Network dcompose-demo_default  Created                                                                  0.1s
Container dcompose-demo-web-1  Started                                                                  0.5s

Tip: If you see a permission error on the Docker socket, make sure you added your user to the docker group (see Step 5.1).

7.3. Verify and Test

Check that your container is running:

docker compose ps

Sample Output:


azureuser@MyUbuntu1:~/dcompose-demo$ sudo docker compose ps
WARN[0000] /home/azureuser/dcompose-demo/docker-compose.yml: the attribute `version` is obsolete, it will be ignored, please remove it to avoid potential confusion
NAME                  IMAGE          COMMAND                  SERVICE   CREATED         STATUS         PORTS
dcompose-demo-web-1   nginx:alpine   "/docker-entrypoint.…"   web       4 minutes ago   Up 4 minutes   0.0.0.0:8000->80/tcp, [::]:8000->80/tcp

Now open a browser to:

  • Local: http://localhost:8000
  • Remote server: http://YOUR_UBUNTU_SERVER_IP:8000

You should see your demo page served by Nginx. Any changes you make in the ./myapp folder (for example, editing index.html) will instantly show up—thanks to the shared volume.

If you are using Azure and cannot be able to access the page on port 8000, the issue is probably that the port has not yet been enabled in the Network Security Groups under inbound rules.

What you need to do is; navigate to your Resource Group > then select the Network Security Group resource > head to settings and select Inbound Security Rules and add port 8000.
Now upon refreshing, you should see the following html page on your browser

Install Docker in Ubuntu: A preview of rendered HTML file
A preview of rendered HTML file

8. Clean Up & Best Practices

If you were using Azure Resources like myself and would wish to clean up your Virtual Machine to prevent unallocated costs from accumulating, it is always advisable to delete the whole Resource Group to ensure a 100% cleanup.

Tip:
Always double-check your Cost Management dashboard in Azure to track quotas and avoid surprises.

9. Conclusion

Docker has become an indispensable tool for modern software development, making it simple to build, deploy, and scale applications in portable containers. In this quick start guide, you learned how to install Docker in Ubuntu 22.04 on an Azure VM, configure it securely, use Docker Compose for multi-container setups, and deploy a sample containerized app.

By following best practices and cleaning up your Azure resources when you’re done, you’ll make the most of your free student credits while keeping your cloud environment tidy and cost-effective.

Happy containerizing — and don’t forget to experiment further with Docker’s vast ecosystem to power up your development workflow!

Share via: