{"id":1059,"date":"2026-11-11T13:00:00","date_gmt":"2026-11-11T13:00:00","guid":{"rendered":"https:\/\/vpslake.com\/blog\/?p=1059"},"modified":"2026-11-11T13:00:00","modified_gmt":"2026-11-11T13:00:00","slug":"install-docker-ubuntu-24-04","status":"publish","type":"post","link":"https:\/\/vpslake.com\/blog\/2026\/11\/11\/install-docker-ubuntu-24-04\/","title":{"rendered":"How to Install Docker on Ubuntu 24.04 (Step-by-Step)"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Install Docker on Ubuntu 24.04 from Docker&#8217;s official APT repository and finish with Compose v2, non-root CLI access, and a working container test. On a fresh VPS, the setup and verification take about ten minutes.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Prerequisites<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n\n<li>A 64-bit Ubuntu 24.04 LTS VPS with at least 2 GB of RAM and 10 GB of free disk space.<\/li>\n\n\n<li>SSH access as <code>root<\/code>, or a normal Linux account with working <code>sudo<\/code> privileges.<\/li>\n\n\n<li>Outbound HTTPS access to <code>download.docker.com<\/code> and Docker Hub so APT can retrieve packages and the test image.<\/li>\n\n\n<li>No domain is needed for installation or the local web test. You will need a domain later if you put a public application behind HTTPS.<\/li>\n\n\n<li>A <a href=\"https:\/\/vpslake.com\/buy-vps\">VPSLake Linux VPS<\/a> if you need a fresh Ubuntu server with root access.<\/li>\n\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">The commands below use <code>sudo<\/code> for a normal SSH account. If you are logged in as <code>root<\/code>, remove <code>sudo<\/code>. Ubuntu 24.04 uses APT and commonly uses UFW; the Docker repository method below installs Docker Engine rather than Ubuntu&#8217;s separately packaged <code>docker.io<\/code> build.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 1: Confirm Ubuntu 24.04 and update the VPS<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Checking the release and architecture first prevents you from adding a Noble repository to the wrong operating system.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>grep -E '^(PRETTY_NAME|VERSION_ID|VERSION_CODENAME)=' \/etc\/os-release\nuname -m\nsudo apt update\nsudo apt full-upgrade -y<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The release should identify Ubuntu 24.04 and the architecture should normally be <code>x86_64<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>PRETTY_NAME=\"Ubuntu 24.04.x LTS\"\nVERSION_ID=\"24.04\"\nVERSION_CODENAME=noble\nx86_64<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The minor release and number of upgraded packages will vary. Fix any DNS, mirror, or interrupted-package error before continuing.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 2: Remove packages that conflict with Docker Engine<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Ubuntu&#8217;s <code>docker.io<\/code> package, the older Compose package, and separately installed runtimes can conflict with Docker&#8217;s Engine package set.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">On a new VPS, remove possible conflicting packages:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo apt remove -y docker.io docker-compose docker-compose-v2 docker-doc docker-buildx podman-docker containerd runc<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">APT may say that some packages are not installed; that is expected. This command does not automatically erase images, containers, volumes, or networks stored under <code>\/var\/lib\/docker\/<\/code>, so inspect existing workloads before changing a host that already runs containers.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 3: Add Docker&#8217;s signed Noble repository<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The official repository supplies Docker Engine, its CLI, containerd, Buildx, and the maintained Compose plugin as a compatible package set.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Install the certificate tools, save Docker&#8217;s signing key in APT&#8217;s keyring directory, and create a deb822 source file for Ubuntu 24.04:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo apt install -y ca-certificates curl\nsudo install -m 0755 -d \/etc\/apt\/keyrings\nsudo curl -fsSL https:\/\/download.docker.com\/linux\/ubuntu\/gpg -o \/etc\/apt\/keyrings\/docker.asc\nsudo chmod a+r \/etc\/apt\/keyrings\/docker.asc\nsudo tee \/etc\/apt\/sources.list.d\/docker.sources &gt; \/dev\/null &lt;&lt;EOF\nTypes: deb\nURIs: https:\/\/download.docker.com\/linux\/ubuntu\nSuites: noble\nComponents: stable\nArchitectures: $(dpkg --print-architecture)\nSigned-By: \/etc\/apt\/keyrings\/docker.asc\nEOF\nsudo apt update<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Confirm that APT sees an Engine candidate from Docker&#8217;s repository before installing it:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>apt-cache policy docker-ce<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The candidate should be listed under <code>https:\/\/download.docker.com\/linux\/ubuntu<\/code> and use the <code>noble<\/code> suite. Docker&#8217;s <a href=\"https:\/\/docs.docker.com\/engine\/install\/ubuntu\/\" target=\"_blank\" rel=\"noopener\">Ubuntu installation documentation<\/a> documents this signed repository and package path.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 4: Install Docker Engine and Compose v2<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Installing the daemon and plugins together keeps the Docker client, container runtime, image builder, and Compose integration aligned.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin\nsudo systemctl enable --now docker<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Check the service and command-line tools immediately:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo systemctl is-active docker\nsudo systemctl is-enabled docker\nsudo docker version --format 'Client {{.Client.Version}} \/ Server {{.Server.Version}}'\nsudo docker compose version<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Expected output shows an active, enabled service and version strings. Docker publishes updates independently of Ubuntu&#8217;s point releases, so the numbers will change:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>active\nenabled\nClient 29.x.y \/ Server 29.x.y\nDocker Compose version v2.x.y<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Step 5: Run Docker&#8217;s installation test<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>hello-world<\/code> image checks the complete path from the CLI to the daemon, registry, image cache, container creation, and process startup.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo docker run --rm hello-world<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Near the end, look for this confirmation:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Hello from Docker!\nYour installation appears to be working correctly.<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The container exits after printing its message. The <code>--rm<\/code> flag removes its stopped container record, although the small image remains cached.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 6: Give one account non-root Docker access<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Docker&#8217;s Unix socket is root-owned by default. Adding one trusted account to the <code>docker<\/code> group avoids repeated <code>sudo<\/code>, but group membership grants root-equivalent control over the VPS.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Run this as the normal account that should manage containers, replacing the placeholder with that account&#8217;s login name:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo groupadd --force docker\nsudo usermod -aG docker YOUR_LINUX_USER<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Log out of SSH completely and reconnect as that user so the new group is loaded. Then verify access without <code>sudo<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>id -nG\ndocker info --format 'Server {{.ServerVersion}}'<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The group list should include <code>docker<\/code>, and the second command should print the Engine version. <code>newgrp docker<\/code> can load the group in the current shell, but reconnecting is less surprising when multiple SSH sessions are open.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Step 7: Test container networking on loopback<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A disposable NGINX container verifies port publishing while binding only to the VPS&#8217;s loopback address, so the test does not require a DNS record or a public firewall rule.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>docker run -d --name ubuntu2404-docker-check --publish 127.0.0.1:18083:80 nginx:alpine\ndocker ps --filter name=ubuntu2404-docker-check --format 'table {{.Names}}\\t{{.Status}}\\t{{.Ports}}'\ncurl --head --max-time 10 http:\/\/127.0.0.1:18083<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">You should see a running container and an HTTP success response:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>NAMES                   STATUS        PORTS\nubuntu2404-docker-check Up ...        127.0.0.1:18083-&gt;80\/tcp\nHTTP\/1.1 200 OK<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Remove the disposable test after checking it:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>docker stop ubuntu2404-docker-check\ndocker rm ubuntu2404-docker-check<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Verify Docker on Ubuntu 24.04<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Run this final check as the Docker administrator to confirm boot startup, daemon communication, Compose, and local storage:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>systemctl is-active docker\nsystemctl is-enabled docker\ndocker version --format 'Client {{.Client.Version}} \/ Server {{.Server.Version}}'\ndocker compose version\ndocker info --format 'Containers {{.Containers}} | Images {{.Images}} | Storage {{.Driver}}'<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Successful output includes <code>active<\/code>, <code>enabled<\/code>, client\/server versions, a Compose v2 version, and usually <code>overlay2<\/code> as the storage driver:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>active\nenabled\nClient 29.x.y \/ Server 29.x.y\nDocker Compose version v2.x.y\nContainers 0 | Images 2 | Storage overlay2<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">For the way Docker&#8217;s published ports interact with host filtering, read the official <a href=\"https:\/\/docs.docker.com\/engine\/network\/packet-filtering-firewalls\/\" target=\"_blank\" rel=\"noopener\">packet-filtering and firewall guidance<\/a>.<\/p>\n\n\n\n<aside class=\"vl-element vl-cta-banner\" aria-label=\"Run Docker on Ubuntu 24.04\">\n\t<div class=\"vl-cta-banner__content\">\n\t\t<p class=\"vl-cta-banner__eyebrow\">Ubuntu VPS<\/p>\n\t\t<h3 class=\"vl-cta-banner__title\">Run Docker on Ubuntu 24.04<\/h3>\n\t\t<p class=\"vl-cta-banner__text\">Get a root-access Ubuntu VPS ready for Docker apps, Compose projects, and development workloads.<\/p>\n\t<\/div>\n\t<a class=\"vl-cta-banner__button\" href=\"\/buy-vps\" aria-label=\"View Linux VPS plans\">View Linux VPS plans<\/a>\n<\/aside>\n\n\n\n<h2 class=\"wp-block-heading\">Troubleshooting<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\"><code>E: Package 'docker-ce' has no installation candidate<\/code><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">APT has not loaded Docker&#8217;s repository, or the source file points to a suite other than Noble. Check the release, source file, and package policy:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>grep -E '^(VERSION_ID|VERSION_CODENAME)=' \/etc\/os-release\ngrep -E '^(Types|URIs|Suites|Components|Architectures|Signed-By):' \/etc\/apt\/sources.list.d\/docker.sources\nsudo apt update\napt-cache policy docker-ce<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The source must show <code>Suites: noble<\/code>, and the policy output should show a candidate from <code>download.docker.com<\/code>. Recreate Step 3 if the file is missing or names <code>jammy<\/code> or another release.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><code>NO_PUBKEY<\/code> or an APT signature verification error<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">APT cannot read the signing key associated with the Docker source. Download the key again and ensure APT can read it:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>sudo curl -fsSL https:\/\/download.docker.com\/linux\/ubuntu\/gpg -o \/etc\/apt\/keyrings\/docker.asc\nsudo chmod a+r \/etc\/apt\/keyrings\/docker.asc\nsudo apt update<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Do not bypass signature checks or mark the repository as trusted; the signature protects the package metadata.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><code>permission denied while trying to connect to the Docker daemon socket<\/code><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The current SSH process started before the account joined the <code>docker<\/code> group, or <code>usermod<\/code> targeted a different user. Reconnect, run <code>id -nG<\/code>, and retry; <code>sudo docker info<\/code> is only a temporary diagnostic while you correct the group membership.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><code>curl: (7) Failed to connect to 127.0.0.1 port 18083<\/code><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The NGINX image may still be downloading, the container may have exited, or another process may already own port 18083. Inspect the container and its logs:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>docker ps -a --filter name=ubuntu2404-docker-check\ndocker logs ubuntu2404-docker-check\nsudo ss -ltnp | grep ':18083'<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">If the port is occupied, remove the failed test and repeat it with <code>--publish 127.0.0.1:28083:80<\/code>, then request <code>http:\/\/127.0.0.1:28083<\/code>. A loopback-only binding does not need a UFW rule.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Hardening<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n\n<li>Keep Docker&#8217;s API on its Unix socket. Never expose an unauthenticated Docker API on TCP port 2375; remote administration requires deliberate TLS configuration and narrow source-IP rules.<\/li>\n\n\n<li>Treat membership in the <code>docker<\/code> group as administrative access. Use rootless Docker when the workload needs a stronger privilege boundary.<\/li>\n\n\n<li>Bind internal applications to <code>127.0.0.1<\/code> until they sit behind a TLS reverse proxy. If an application must be public, open only the ports it needs in UFW and review Docker&#8217;s packet-filtering behavior because published ports can bypass ordinary UFW filtering. A <a href=\"https:\/\/vpslake.com\/ufw-firewall-generator\">VPSLake UFW firewall generator<\/a> can help draft a starting ruleset.<\/li>\n\n\n<li>Monitor <code>\/var\/lib\/docker<\/code> and container logs. Image layers and the default JSON logging driver can consume disk space even when few containers are running.<\/li>\n\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">FAQ<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Why use Docker&#8217;s repository instead of Ubuntu&#8217;s <code>docker.io<\/code> package?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Ubuntu&#8217;s package is maintained separately from Docker&#8217;s upstream Engine release cycle. Docker&#8217;s repository provides the current Engine package family together with <code>containerd.io<\/code>, Buildx, and the Compose plugin, which keeps those components aligned.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Does this install Docker Compose?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Yes. The <code>docker-compose-plugin<\/code> package installs Compose v2, used with <code>docker compose<\/code> and a space. The older standalone <code>docker-compose<\/code> command is not needed for new projects.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Do I need Docker Desktop on an Ubuntu VPS?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">No. Docker Desktop is aimed at desktop development environments, while Docker Engine is the server daemon used on a headless VPS. This guide installs Engine directly and manages it with systemd.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Where does Docker store its data on Ubuntu?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The default data directory is <code>\/var\/lib\/docker<\/code>, which contains image layers, containers, networks, and volumes. Account for that directory when sizing disk space, and use deliberate cleanup or log rotation rather than deleting it while containers are running.<\/p>\n\n\n\n<script type=\"application\/ld+json\">{\"@context\": \"https:\/\/schema.org\", \"@type\": \"FAQPage\", \"mainEntity\": [{\"@type\": \"Question\", \"name\": \"Why use Docker's repository instead of Ubuntu's `docker.io` package?\", \"acceptedAnswer\": {\"@type\": \"Answer\", \"text\": \"Ubuntu's package is maintained separately from Docker's upstream Engine release cycle. Docker's repository provides the current Engine package family together with `containerd.io`, Buildx, and the Compose plugin, which keeps those components aligned.\"}}, {\"@type\": \"Question\", \"name\": \"Does this install Docker Compose?\", \"acceptedAnswer\": {\"@type\": \"Answer\", \"text\": \"Yes. The `docker-compose-plugin` package installs Compose v2, used with `docker compose` and a space. The older standalone `docker-compose` command is not needed for new projects.\"}}, {\"@type\": \"Question\", \"name\": \"Do I need Docker Desktop on an Ubuntu VPS?\", \"acceptedAnswer\": {\"@type\": \"Answer\", \"text\": \"No. Docker Desktop is aimed at desktop development environments, while Docker Engine is the server daemon used on a headless VPS. This guide installs Engine directly and manages it with systemd.\"}}, {\"@type\": \"Question\", \"name\": \"Where does Docker store its data on Ubuntu?\", \"acceptedAnswer\": {\"@type\": \"Answer\", \"text\": \"The default data directory is `\/var\/lib\/docker`, which contains image layers, containers, networks, and volumes. Account for that directory when sizing disk space, and use deliberate cleanup or log rotation rather than deleting it while containers are running.\"}}]}<\/script>\n\n","protected":false},"excerpt":{"rendered":"Install Docker on Ubuntu 24.04 with the official APT repository, Compose v2, a verified container, and fixes for common VPS errors on a fresh VPS.","protected":false},"author":1,"featured_media":1060,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"csco_singular_sidebar":"","csco_page_header_type":"","csco_page_load_nextpost":"","footnotes":""},"categories":[5,9],"tags":[119,118,120,102],"class_list":["post-1059","post","type-post","status-publish","format-standard","has-post-thumbnail","category-guides","category-vps-hosting","tag-containers","tag-docker","tag-docker-compose","tag-ubuntu-24-04","cs-entry"],"_links":{"self":[{"href":"https:\/\/vpslake.com\/blog\/wp-json\/wp\/v2\/posts\/1059","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/vpslake.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/vpslake.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/vpslake.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/vpslake.com\/blog\/wp-json\/wp\/v2\/comments?post=1059"}],"version-history":[{"count":1,"href":"https:\/\/vpslake.com\/blog\/wp-json\/wp\/v2\/posts\/1059\/revisions"}],"predecessor-version":[{"id":3986,"href":"https:\/\/vpslake.com\/blog\/wp-json\/wp\/v2\/posts\/1059\/revisions\/3986"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/vpslake.com\/blog\/wp-json\/wp\/v2\/media\/1060"}],"wp:attachment":[{"href":"https:\/\/vpslake.com\/blog\/wp-json\/wp\/v2\/media?parent=1059"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/vpslake.com\/blog\/wp-json\/wp\/v2\/categories?post=1059"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/vpslake.com\/blog\/wp-json\/wp\/v2\/tags?post=1059"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}