How to Install Docker in Ubuntu 22.04: A 2025 Quick Start 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.
- How to Install Docker in Ubuntu 22.04: A 2025 Quick Start Guide
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:

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…

Finally, click review + create to confirm your VM details
Now you should see your deployment initializing as seen below:

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:

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

Once successfully connected, you should see the following logs:

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:

- 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:

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 fo… 109
nginx/nginx-prometheus-exporter NGINX Prometheus Exporter for NGINX and NGIN… 50
nginx/unit This repository is retired, use the Docker o… 65
nginx/nginx-ingress-operator NGINX Ingress Operator for NGINX and NGINX P… 2
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 & we… 129
bitnamicharts/nginx Bitnami Helm chart for NGINX Open Source 0
kasmweb/nginx An Nginx image based off nginx:alpine and in… 8
rancher/nginx 2
linuxserver/nginx An Nginx container, brought to you by LinuxS… 231
dtagdevsec/nginx T-Pot Nginx 0
vmware/nginx 2
paketobuildpacks/nginx 0
gluufederation/nginx A customized NGINX image containing a consu… 1
chainguard/nginx Build, ship and run secure software with Cha… 4
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:
- version: Specifies the Compose file format version.
- services: Lists the containers you want to run. In our case, we have a single service called web.
- image: Tells Docker Compose to use the
nginx:alpine
image. - ports: Maps port 8000 on your host (where you run Compose) to port 80 inside the container, where Nginx listens.
- 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

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!