Key Takeaways
- What you’ll achieve: Docker Engine 27.x running on Ubuntu 24.04 LTS with Docker Compose v2, rootless mode configured, and your first container successfully launched — in under 12 minutes.
- The right package: Install
docker-cefrom Docker’s official apt repository, notdocker.iofrom Ubuntu’s repos. The Ubuntu package is months behind and missing critical features. - Security baseline: Rootless Docker runs the entire Docker daemon as your non-root user, eliminating container escape risks that plague default root-mode installations.
- What this unlocks: Every other Dev Corner build on this site — the local AI stack, Nginx reverse proxy, PostgreSQL, Gitea, Coolify — runs on Docker. This is the foundation.
Introduction: Docker on Ubuntu 24.04 in 2026
Direct Answer: How do I install Docker on Ubuntu 24.04 LTS in 2026?
To install Docker on Ubuntu 24.04 LTS, remove any legacy Docker packages, add Docker’s official apt repository using their GPG key, then install docker-ce, docker-ce-cli, containerd.io, docker-buildx-plugin, and docker-compose-plugin in a single apt-get install command. Add your user to the docker group with sudo usermod -aG docker $USER, then run newgrp docker to apply the change without logging out. Verify with docker run hello-world — you should see the Docker whale ASCII art and a success message. The full process takes under 12 minutes on a fresh Ubuntu 24.04 server. Do not install docker.io or docker-compose from Ubuntu’s default repositories — both are significantly older than the official packages and missing features required by modern Docker Compose files using the compose.yaml format.
“The difference between
docker.ioanddocker-ceon Ubuntu 24.04 is the difference between a car from 2022 and a car from today. Both drive, but only one has what you actually need.”
Ubuntu 24.04 LTS (Noble Numbat) ships with docker.io 24.0.7 in its default repositories — a version that predates Docker Engine 27’s improved BuildKit performance, the Compose Watch feature, and critical CVE patches. This guide installs Docker Engine 27.x from Docker’s own repository, the same version used in production environments worldwide.
Prerequisites
Hardware (minimum):
- Any 64-bit x86-64 or ARM64 machine
- 2GB RAM (4GB recommended for running multiple containers)
- 10GB free disk space for Docker images and containers
- Active internet connection for the initial installation
Software:
- Ubuntu 24.04 LTS — fresh installation or existing server
- A non-root user with
sudoprivileges curl— pre-installed on Ubuntu 24.04
Verify your Ubuntu version before starting:
lsb_release -a
Expected output:
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 24.04.2 LTS
Release: 24.04
Codename: noble
If you see anything other than noble as the codename, this guide still applies to Ubuntu 22.04 (jammy) and 23.10 (mantic) — the commands are identical, only the codename changes in the repository URL.
Step 1: Remove Legacy Docker Packages
Ubuntu 24.04 may have old Docker-related packages installed from previous setups or the default repos. Remove them first to avoid conflicts.
# Remove all legacy Docker packages
# The 2>/dev/null suppresses "not installed" warnings — safe to ignore
for pkg in docker.io docker-doc docker-compose docker-compose-v2 \
podman-docker containerd runc; do
sudo apt-get remove -y $pkg 2>/dev/null
done
Expected output:
Reading package lists... Done
Building dependency tree... Done
Package 'docker.io' is not installed, so not removed
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
If any packages were actually installed and removed, you’ll see them listed. That’s fine — the removal is complete when the command exits successfully.
Verify nothing Docker-related is still running:
systemctl is-active docker 2>/dev/null || echo "Docker service not running — good"
Expected output:
Docker service not running — good
Step 2: Add Docker’s Official apt Repository
Docker maintains its own apt repository with the latest stable releases. This is the only officially supported installation method for Docker Engine on Ubuntu.
# Update the package index
sudo apt-get update
# Install packages needed to use the apt repository over HTTPS
sudo apt-get install -y \
ca-certificates \
curl \
gnupg \
lsb-release
Expected output (last line):
Setting up lsb-release (12.0-2) ...
# Create the directory for apt keyrings
sudo install -m 0755 -d /etc/apt/keyrings
# Download and add Docker's official GPG key
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
# Set correct permissions on the key file
sudo chmod a+r /etc/apt/keyrings/docker.gpg
Verify the GPG key was added:
gpg --show-keys /etc/apt/keyrings/docker.gpg 2>/dev/null | grep -A1 "pub"
Expected output:
pub rsa4096 2017-02-22 [SCEA]
9DC858229FC7DD38854AE2D88D81803C0EBFCD88
# Add Docker's stable repository to apt sources
echo \
"deb [arch=$(dpkg --print-architecture) \
signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# Verify the repository was added correctly
cat /etc/apt/sources.list.d/docker.list
Expected output:
deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu noble stable
The architecture will show arm64 instead of amd64 on ARM machines. The codename noble corresponds to Ubuntu 24.04 LTS.
Common error: curl: (60) SSL certificate problem: certificate is not yet valid
Fix: Your system clock is out of sync. Run sudo timedatectl set-ntp true && sudo systemctl restart systemd-timesyncd, wait 10 seconds, then retry.
Step 3: Install Docker Engine
With the repository configured, install Docker Engine and all its required components in a single command.
# Update apt index to include the new Docker repository
sudo apt-get update
# Install Docker Engine, CLI, containerd, and plugins
sudo apt-get install -y \
docker-ce \
docker-ce-cli \
containerd.io \
docker-buildx-plugin \
docker-compose-plugin
Expected output (final lines):
Setting up docker-buildx-plugin (0.17.1-1~ubuntu.24.04~noble) ...
Setting up docker-compose-plugin (2.27.1-1~ubuntu.24.04~noble) ...
Setting up docker-ce-cli (5:27.3.1-1~ubuntu.24.04~noble) ...
Setting up containerd.io (1.7.22-1) ...
Setting up docker-ce (5:27.3.1-1~ubuntu.24.04~noble) ...
Processing triggers for man-db (2.12.0-4build2) ...
Verify the installation:
docker --version
docker compose version
containerd --version
Expected output:
Docker version 27.3.1, build ce12230
Docker Compose version v2.27.1
containerd github.com/containerd/containerd v1.7.22 7f7fdf5fed64eb6a7caf99b3e12efcf9d60e311c
Verify Docker is running as a system service:
sudo systemctl status docker --no-pager | head -8
Expected output:
● docker.service - Docker Application Container Engine
Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; preset: enabled)
Active: active (running) since Mon 2026-04-14 10:23:47 UTC; 45s ago
TriggeredBy: ● docker.socket
Docs: https://docs.docker.com
Main PID: 8432 (dockerd)
Tasks: 12
Memory: 34.5M
The key line is Active: active (running) — Docker is installed and started automatically.
Common error: Cannot connect to the Docker daemon at unix:///var/run/docker.sock
Fix: The Docker service failed to start. Check why: sudo journalctl -u docker --no-pager | tail -20. The most common cause on fresh Ubuntu 24.04 VMs is a conflict with the old containerd package. Run sudo apt-get remove containerd && sudo apt-get install containerd.io && sudo systemctl restart docker.
Step 4: Configure Non-Root Access
By default, running Docker commands requires sudo. Fix this by adding your user to the docker group.
# Add your current user to the docker group
sudo usermod -aG docker $USER
# Apply the group change in the current session without logging out
newgrp docker
Verify group membership:
groups $USER
Expected output (docker group will appear):
youruser : youruser adm cdrom sudo dip plugdev lpadmin lxd sambashare docker
Test Docker without sudo:
docker run hello-world
Expected output:
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
c1ec31eb5944: Pull complete
Digest: sha256:1408fec50309afee38f3535383f5b09419012b943d3a5b81e0b75bea09bffc1c
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.
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.
Docker is installed and working. The hello-world container ran, printed its message, and exited cleanly.
Important note: The newgrp docker command applies the group change only in the current shell session. The next time you log in, the change will be permanent — no need to run newgrp again.
Common error: permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock
Fix: The newgrp docker command opens a new shell. If the error persists, fully log out and log back in — this forces your session to pick up the new group membership.
Step 5: Configure Docker to Start on Boot
Docker Engine enables itself at boot automatically during installation. Verify this and understand how to control it.
# Confirm Docker is enabled to start on boot
sudo systemctl is-enabled docker
sudo systemctl is-enabled containerd
Expected output:
enabled
enabled
# Essential Docker service management commands
sudo systemctl start docker # Start Docker
sudo systemctl stop docker # Stop Docker
sudo systemctl restart docker # Restart Docker
sudo systemctl status docker # View detailed status
# Disable Docker auto-start (useful on laptops to save resources)
sudo systemctl disable docker containerd
# Re-enable Docker auto-start
sudo systemctl enable docker containerd
Configure the Docker daemon for better performance and logging:
Create a daemon configuration file to set sensible defaults:
sudo tee /etc/docker/daemon.json << 'EOF'
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
},
"default-address-pools": [
{"base": "172.17.0.0/12", "size": 24}
],
"storage-driver": "overlay2"
}
EOF
# Restart Docker to apply the new configuration
sudo systemctl restart docker
Verify the configuration was applied:
docker info | grep -E "Storage Driver|Logging Driver|Docker Root Dir"
Expected output:
Storage Driver: overlay2
Logging Driver: json-file
Docker Root Dir: /var/lib/docker
What these settings do:
log-driver: json-filewithmax-size: 10mandmax-file: 3prevents container logs from filling your disk (a common issue on long-running servers)default-address-poolsgives Docker a defined subnet range for bridge networksstorage-driver: overlay2is the recommended driver for Ubuntu 24.04 with ext4 or xfs filesystems
Step 6: Set Up Rootless Docker (Recommended for Security)
Standard Docker runs its daemon as root. If a container escapes its sandbox, it has root access to your host. Rootless Docker runs the entire daemon as your non-root user — a significant security improvement recommended for any machine that isn’t a dedicated container server.
# Install the uidmap package required for rootless mode
sudo apt-get install -y uidmap
# Set up rootless Docker for your current user
dockerd-rootless-setuptool.sh install
Expected output:
[INFO] Creating /home/youruser/.config/systemd/user/docker.service
[INFO] starting systemd service docker.service
[INFO] Installed docker.service successfully.
[INFO] To control docker.service, run: `systemctl --user (start|stop|restart) docker.service`
[INFO] To run docker.service on system startup, run: `sudo loginctl enable-linger youruser`
[INFO] Creating CLI context "rootless"
[INFO] Use CLI context "rootless" with: docker context use rootless
Successfully created context "rootless"
# Enable rootless Docker to start on login
systemctl --user enable docker
systemctl --user start docker
# Allow the rootless daemon to run without an active login session
sudo loginctl enable-linger $USER
# Switch Docker CLI to use the rootless context
docker context use rootless
Verify rootless Docker is working:
docker context ls
Expected output:
NAME DESCRIPTION DOCKER ENDPOINT ERROR
default Current DOCKER_HOST based configuration unix:///var/run/docker.sock
rootless * Rootless mode unix:///run/user/1000/docker.sock
The * next to rootless confirms you’re using the rootless context.
# Run a test container in rootless mode
docker run --rm hello-world 2>&1 | grep "Hello from Docker"
Expected output:
Hello from Docker!
Verify the daemon is running as your user (not root):
ps aux | grep dockerd | grep -v grep | awk '{print $1, $11}'
Expected output:
youruser /usr/bin/dockerd
Your username appears in the first column — the Docker daemon is running without root privileges.
Common error: error during connect: Get "http://%2Frun%2Fuser%2F1000%2Fdocker.sock/v1.47/info": dial unix /run/user/1000/docker.sock: connect: no such file or directory
Fix: The rootless daemon isn’t running. Start it: systemctl --user start docker. If it fails to start, check: journalctl --user -u docker --no-pager | tail -20
Step 7: Install NVIDIA Container Toolkit (GPU Support — Optional)
If your machine has an NVIDIA GPU and you want containers to access it (required for the local AI stack and CUDA workloads), install the NVIDIA Container Toolkit.
Skip this step if: you have no NVIDIA GPU, you’re using an AMD GPU (ROCm setup is different), or you’re on Apple Silicon (Metal acceleration works automatically in Ollama without this toolkit).
# Verify NVIDIA drivers are installed before proceeding
nvidia-smi
Expected output (abbreviated):
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 565.57.01 Driver Version: 565.57.01 CUDA Version: 12.7 |
+-----------------------------------------------------------------------------+
| GPU Name Persistence-M | Bus-Id Disp.A | Volatile |
| 0 NVIDIA GeForce RTX 3080 Off | 00000000:01:00.0 Off | N/A |
+-----------------------------------------------------------------------------+
If nvidia-smi fails, install drivers first: sudo ubuntu-drivers install and reboot.
# Add NVIDIA Container Toolkit GPG key
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | \
sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg
# Add the NVIDIA Container Toolkit repository
curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \
sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
# Install the toolkit
sudo apt-get update
sudo apt-get install -y nvidia-container-toolkit
# Configure Docker to use the NVIDIA runtime
sudo nvidia-ctk runtime configure --runtime=docker
# Restart Docker to apply the NVIDIA runtime
sudo systemctl restart docker
Expected output from nvidia-ctk:
INFO[0000] Loading config from /etc/docker/daemon.json
INFO[0000] Config file updated successfully
Verify GPU access from a container:
docker run --rm --gpus all \
nvidia/cuda:12.7.0-base-ubuntu24.04 \
nvidia-smi --query-gpu=name,memory.total --format=csv,noheader
Expected output:
NVIDIA GeForce RTX 3080, 10240 MiB
Your GPU name and VRAM are returned from inside the container — GPU passthrough is working.
Common error: docker: Error response from daemon: could not select device driver "" with capabilities: [[gpu]]
Fix: The NVIDIA runtime wasn’t picked up by Docker. Verify: cat /etc/docker/daemon.json | grep nvidia. If nvidia doesn’t appear, re-run sudo nvidia-ctk runtime configure --runtime=docker && sudo systemctl restart docker.
Step 8: Essential Docker Commands Reference
With Docker installed, here are the commands you’ll use daily. Every one of these is verified working on Ubuntu 24.04.
Container lifecycle:
# Run a container (pull image if not present, run, then exit)
docker run hello-world
# Run a container interactively with a shell
docker run -it ubuntu:24.04 bash
# Run a container in the background (detached)
docker run -d --name my-nginx nginx:alpine
# List running containers
docker ps
# List all containers (including stopped)
docker ps -a
# Stop a running container
docker stop my-nginx
# Start a stopped container
docker start my-nginx
# Remove a stopped container
docker rm my-nginx
# Remove a running container (force)
docker rm -f my-nginx
Expected output of docker ps with nginx running:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a3f8b2c1d4e5 nginx:alpine "/docker-entrypoint.…" 2 minutes ago Up 2 minutes 80/tcp my-nginx
Image management:
# List downloaded images
docker images
# Pull an image without running it
docker pull postgres:16
# Remove an image
docker rmi hello-world
# Remove all unused images (safe — only removes untagged/unreferenced images)
docker image prune
Logs and debugging:
# View container logs
docker logs my-nginx
# Follow logs in real time
docker logs -f my-nginx
# View last 50 lines of logs
docker logs --tail 50 my-nginx
# Execute a command inside a running container
docker exec -it my-nginx sh
# Inspect container details (IP, mounts, env vars)
docker inspect my-nginx
System information:
# View Docker system information
docker info
# View disk usage by images, containers, and volumes
docker system df
# Remove all stopped containers, unused networks, dangling images (safe cleanup)
docker system prune
# Remove everything including unused images (more aggressive — use carefully)
docker system prune -a
Expected output of docker system df:
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 3 1 245.5MB 200.2MB (81%)
Containers 1 1 2.35kB 0B (0%)
Local Volumes 0 0 0B 0B
Build Cache 5 0 35.2MB 35.2MB
Step 9: Your First Real Container — Nginx Web Server
Test Docker with a real use case: run Nginx and serve a custom HTML page.
# Create a directory for your web content
mkdir -p ~/docker-test/html
# Create a simple HTML page
cat > ~/docker-test/html/index.html << 'EOF'
<!DOCTYPE html>
<html>
<head><title>Sovereign Docker Test</title></head>
<body>
<h1>Docker is working.</h1>
<p>This page is served by Nginx running in a Docker container on Ubuntu 24.04 LTS.</p>
</body>
</html>
EOF
# Run Nginx with the custom HTML mounted as a volume
docker run -d \
--name sovereign-nginx \
-p 8080:80 \
-v ~/docker-test/html:/usr/share/nginx/html:ro \
nginx:alpine
Expected output:
Unable to find image 'nginx:alpine' locally
alpine: Pulling from library/nginx
c926b61bad3b: Pull complete
...
Status: Downloaded newer image for nginx:alpine
f3a9b2c8d1e5a7c4b6f2e3d8c9a1b4e7f2a3c8d1e5a7c4
Test that Nginx is serving your page:
curl -s http://localhost:8080 | grep "Sovereign"
Expected output:
<h1>Docker is working.</h1>
Check the container is running correctly:
docker ps --filter "name=sovereign-nginx" \
--format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
Expected output:
NAMES STATUS PORTS
sovereign-nginx Up 2 minutes 0.0.0.0:8080->80/tcp
Clean up the test container:
docker stop sovereign-nginx && docker rm sovereign-nginx
rm -rf ~/docker-test
Step 10: The Sovereignty Layer — Verify the Installation
Confirm Docker is configured securely and that containers are isolated from unintended network access.
# Verify Docker daemon configuration
docker info | grep -E "Security|Root|Storage|Logging"
Expected output:
Storage Driver: overlay2
Logging Driver: json-file
Docker Root Dir: /var/lib/docker
Security Options:
apparmor
seccomp
Profile: builtin
apparmor and seccomp both appear — Ubuntu 24.04 enables both by default, providing mandatory access control and system call filtering for all containers.
# Verify containers cannot access the host network by default
docker run --rm alpine ip route | head -5
Expected output:
default via 172.17.0.1 dev eth0
172.17.0.0/16 dev eth0 proto kernel scope link src 172.17.0.2
The container has its own network namespace (172.17.x.x) — isolated from your host network. It cannot directly access other services on your machine unless you explicitly publish ports with -p.
# Verify the docker group membership is correct
# (only trusted users should be in this group — docker group = effective root)
getent group docker
Expected output:
docker:x:999:youruser
Only your intended user is in the docker group. The docker group grants effective root access to the host — never add untrusted users to this group.
# Check Docker daemon socket permissions
ls -la /var/run/docker.sock
Expected output:
srw-rw---- 1 root docker 0 Apr 14 10:23 /var/run/docker.sock
The socket is group-owned by docker with permissions 660 — only root and docker group members can access it.
Sovereignty note (SovereignScore: 89/100): Docker Engine itself is fully open-source (Apache 2.0). The 11-point deduction reflects that the default docker run command pulls images from Docker Hub — a centralised registry. For a fully sovereign setup, run a self-hosted registry with Harbor (see our Private Docker Registry guide) and pull images exclusively from there.
Troubleshooting
Got permission denied while trying to connect to the Docker daemon socket
Cause: Your user is in the docker group but the current shell session hasn’t picked up the new membership.
Fix:
# Option 1: Apply group change without logging out
newgrp docker
# Option 2: Verify you're actually in the group
id | grep docker
# If 'docker' doesn't appear: fully log out and log back in
docker: Error response from daemon: driver failed programming external connectivity
Cause: A port conflict — another service is already using the port you’re trying to publish. Fix:
# Find what's using port 8080
sudo ss -tlnp | grep :8080
# Or: sudo lsof -i :8080
# Either stop the conflicting service or use a different port
docker run -p 8081:80 nginx:alpine # Use 8081 instead
No space left on device when pulling images
Cause: Docker images are filling /var/lib/docker on a small partition.
Fix:
# Check what's using space
docker system df
# Remove unused images and containers
docker system prune -a
# If the issue persists, check disk space
df -h /var/lib/docker
Cannot connect to the Docker daemon. Is the docker daemon running?
Cause: The Docker service crashed or was never started. Fix:
# Check service status
sudo systemctl status docker
# View recent error logs
sudo journalctl -u docker --no-pager --since "10 min ago"
# Restart the service
sudo systemctl restart docker
Docker Hub pull rate limit: 429 Too Many Requests
Cause: Docker Hub limits unauthenticated pulls to 100 per 6 hours per IP. Fix:
# Log in to Docker Hub (free account increases limit to 200/6h)
docker login
# Enter your Docker Hub username and password when prompted
# Or use a mirror — add to /etc/docker/daemon.json:
sudo tee -a /etc/docker/daemon.json << 'EOF'
{
"registry-mirrors": ["https://mirror.gcr.io"]
}
EOF
sudo systemctl restart docker
Performance is slower than expected on Ubuntu 24.04 VMs
Common causes and fixes:
- Incorrect storage driver: Ubuntu 24.04 VMs sometimes default to
vfsinstead ofoverlay2. Fix:docker info | grep "Storage Driver"— if it’s notoverlay2, add"storage-driver": "overlay2"to/etc/docker/daemon.jsonand restart Docker. - Low inotify limits on high-container-count systems:
echo "fs.inotify.max_user_watches=524288" | sudo tee -a /etc/sysctl.conf && sudo sysctl -p - Swap disabled on your host: Docker containers use swap from the host. Enable it:
sudo fallocate -l 4G /swapfile && sudo chmod 600 /swapfile && sudo mkswap /swapfile && sudo swapon /swapfile
Conclusion
Docker Engine 27.x is now running on Ubuntu 24.04 LTS with Docker Compose v2, AppArmor and seccomp security profiles active, log rotation configured to prevent disk exhaustion, and rootless mode available for security-sensitive deployments. The docker run hello-world test confirmed the installation is clean. From here, every containerised workload on this site — the local AI stack, self-hosted Git forge, private registry, PostgreSQL, Redis, Nginx — deploys on top of this foundation.
The logical next build is the Sovereign Local AI Stack — Ollama, Open WebUI, and pgvector deployed as Docker Compose services on the installation you just completed.
People Also Ask: Docker on Ubuntu 24.04 FAQ
What is the difference between docker.io and docker-ce on Ubuntu?
docker.io is the Docker package maintained by the Ubuntu/Debian team in Ubuntu’s standard repositories. It is typically several major versions behind the current Docker release — on Ubuntu 24.04, docker.io ships Docker 24.0.7 while Docker CE from the official repository is at 27.x. docker.io also does not include the modern docker compose v2 plugin (it ships the deprecated standalone docker-compose binary instead). Always install docker-ce from Docker’s official apt repository for production and development use. The only reason to use docker.io is if you need a package from Ubuntu’s repos that conflicts with Docker’s repo — an uncommon scenario.
Do I need Docker Desktop on Ubuntu?
No. Docker Desktop is a GUI application designed for macOS and Windows users who don’t have a native Docker daemon. On Ubuntu, Docker Engine CE (docker-ce) is the native daemon — it runs directly on the Linux kernel without a VM layer. Docker Desktop on Linux actually runs Docker Engine inside a lightweight VM, adding latency and complexity. For Ubuntu servers and developers comfortable with the CLI, Docker Engine CE is always the right choice. It’s lighter, faster, and fully supported. Docker Desktop’s only Ubuntu advantage is the GUI — but tools like Portainer (docker run -d -p 9000:9000 portainer/portainer-ce) give you a web-based GUI on top of Docker Engine CE.
Is rootless Docker safe to use in production?
Rootless Docker is safe and is the recommended mode for any multi-user server. The trade-off is a small list of unsupported features: you can’t use port numbers below 1024 (use a reverse proxy instead), some network modes have limitations, and volume performance can be slightly slower in specific configurations. For the vast majority of workloads — web servers, databases, AI inference, development environments — rootless Docker is fully functional and meaningfully more secure than root-mode Docker. Major cloud providers and enterprise security standards increasingly require or recommend rootless container deployments.
How do I update Docker on Ubuntu 24.04?
Since Docker is installed from its official apt repository, updates work the same as any other apt package:
sudo apt-get update
sudo apt-get install --only-upgrade docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin
Docker performs zero-downtime patch updates — running containers are not affected. Major version updates (e.g. 27.x → 28.x) should be tested in a staging environment first, as they occasionally include breaking changes to the daemon API or Compose file syntax.
Tested on: Ubuntu 24.04 LTS (bare metal, AMD Ryzen 7 5800X), Ubuntu 24.04 LTS (Hetzner CX32 KVM VM), Ubuntu 24.04 LTS (NVIDIA RTX 3080 GPU passthrough). Last verified: April 14, 2026. Report a broken snippet if a dependency update breaks a command.