How to install docker

What Is Docker and Why Should You Use It?

Docker is a containerization platform that lets you run applications in isolated environments called containers. These containers package an application with all its dependencies, making them lightweight, portable, and easy to manage.

Why Use Docker?

Simplifies Application Deployment
Instead of installing software directly on your server (which can lead to dependency conflicts), Docker packages everything into self-contained units that run the same way on any system.

Saves System Resources
Unlike virtual machines (VMs), Docker containers share the host OS kernel, making them far more efficient with memory and CPU usage. You can run dozens of containers on one machine without the overhead of multiple full operating systems.

Easy Software Management
Need to install Jellyfin, Sonarr, Radarr, or Home Assistant? With Docker, it’s as easy as running a command to pull the application and all its dependencies—no manual configuration required.

Keeps Applications Isolated
Docker isolates applications from each other. If one container crashes or gets compromised, it won’t affect the rest of your system.

Effortless Updates and Rollbacks
Updating an app is as simple as pulling the latest container image. And if something goes wrong? Just roll back to the previous version with ease.


Now that you know why Docker is such a powerful tool for your home server, let’s install it correctly, with security in mind.

1. Update Your System and Install Dependencies

Before installing Docker, your system needs to be updated. Additionally, the necessary dependencies also need to be installed. These steps ensure a clean, stable installation. Run the following commands:

sudo apt update && sudo apt upgrade -y
sudo apt install -y ca-certificates curl gnupg

These commands:

  • Update your package list (apt update)
  • Upgrade installed packages (apt upgrade -y)
  • Install the essential dependencies (if curl and gnupg are not already installed)

2. Add Docker’s Official GPG Key and Repository

Ubuntu includes Docker in its default repositories, but you should not use it. Why?

  • Outdated versions: Ubuntu’s repository often lags behind Docker’s latest stable releases, meaning you could be missing important features and security fixes.
  • Slower updates: Critical bug fixes and security patches may take longer to arrive in Ubuntu’s repositories. Where Docker’s official repository adds these patches immediately.
  • Missing features: The Ubuntu version may lack support for new Docker functionalities.

To install the latest version, add Docker’s official repository run the following commands:


TL;DR - I Just Want to Cut & Paste Commands:

sudo install -m 0755 -d /etc/apt/keyrings

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo tee /etc/apt/keyrings/docker.asc > /dev/null

sudo chmod a+r /etc/apt/keyrings/docker.asc

echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

sudo apt update

The Long and Detailed Explanation of the Commands:

sudo install -m 0755 -d /etc/apt/keyrings

Breaking It Down:

  • sudo → Runs the command with superuser (root) privileges.
  • install → A command that can copy files, set permissions, and create directories.
  • -m 0755 → Sets the permissions of the directory to 0755 (read & execute for everyone, write for the owner).
  • -d → Tells install to create a directory (if it doesn’t exist).
  • /etc/apt/keyrings → The path where the directory is created. This is where trusted GPG keys for package signing are stored.

🔒 Security Purpose:

  • Ensures only the owner (root) can modify the keyring directory.
  • Prevents unauthorized users from tampering with trusted GPG keys used to verify software packages.
  • Ubuntu 24.04 and later recommend storing GPG keys in /etc/apt/keyrings/ instead of the older /etc/apt/trusted.gpg for better security.

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo tee /etc/apt/keyrings/docker.asc > /dev/null

Breaking The Three Parts of This Command Down:

1 curl -fsSL https://download.docker.com/linux/ubuntu/gpg

  • curl → A tool to download files from the internet.
  • -f → Fails silently if the URL is incorrect (avoids downloading error messages).
  • -s → Runs in silent mode (hides progress output).
  • -S → Shows errors (only if they occur, making troubleshooting easier).
  • -L → Follows redirects (in case the URL redirects to another location).
  • https://download.docker.com/linux/ubuntu/gpg → The URL to Docker’s official GPG key.

What this does:
Downloads Docker’s GPG key, which is used to verify the authenticity of Docker packages.

2️ | sudo tee /etc/apt/keyrings/docker.asc

  • |Pipes (redirects) the output of curl to the tee command.
  • sudo → Runs the command as root (needed to write to system directories).
  • tee /etc/apt/keyrings/docker.asc
    • tee writes the Docker GPG key into /etc/apt/keyrings/docker.asc.
    • This file will later be used to verify that Docker packages are signed and authentic before installing them.

3 > /dev/null

  • > redirects output somewhere else.
  • /dev/null is a special “trash” file in Linux that discards anything written to it.

sudo chmod a+r /etc/apt/keyrings/docker.asc

Breaking It Down:

  • sudo → Runs the command with superuser (root) privileges.
  • chmodChanges file permissions.
  • a → Stands for “all users” (owner, group, and others).
  • +rAdds read permission (so the file can be read by everyone).
  • /etc/apt/keyrings/docker.asc This is the GPG key file used to verify Docker packages when installing/updating via apt.

What this does:

1️ Allows the System to Use the Key

  • When apt installs or updates Docker, it checks package signatures using this GPG key.
  • Without read access, apt might fail to verify Docker’s authenticity, causing errors.

2 Prevents Unauthorized Modifications

  • The file remains protected (only root can modify it), but now all users can read it.
  • This ensures that system processes and normal users can verify packages but not modify the key.

3️ Follows Ubuntu’s New Security Guidelines

  • Older versions stored GPG keys in /etc/apt/trusted.gpg, which gave all keys full system-wide trust (less secure).
  • Newer Ubuntu releases use /etc/apt/keyrings/, where each key is isolated and explicitly trusted only for its repository.

echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Breaking The Three Parts of This Command Down:

1️ echo "deb [...] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

  • echo → Outputs the text inside quotes.
  • "deb [...] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
    This is a software repository entry in Debian/Ubuntu format.

What’s inside the deb [...] line?

  • deb → Tells apt this is a binary package repository (not source code).
  • [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc]
    • arch=$(dpkg --print-architecture) → Detects your system architecture (amd64, arm64, etc.), ensuring you install the correct version.
    • signed-by=/etc/apt/keyrings/docker.asc → Uses Docker’s GPG key (previously downloaded) to verify package authenticity.
  • https://download.docker.com/linux/ubuntu → The URL of Docker’s official repository.
  • $(lsb_release -cs) → Dynamically inserts your Ubuntu codename (e.g., noble for 24.04), ensuring compatibility.
  • stable → Installs the stable version of Docker (instead of edge/testing builds).

2️ | sudo tee /etc/apt/sources.list.d/docker.list

  • | → Pipes (echo output) to tee, which writes it to a file.
  • sudo → Runs with root privileges (since /etc/apt/sources.list.d/ requires admin access).
  • tee /etc/apt/sources.list.d/docker.list → Saves the repository entry into /etc/apt/sources.list.d/docker.list.

3️ > /dev/null

  • Discards the output from tee, keeping the terminal clean.

Update your apt repositories:

sudo apt update

3. Install Docker

To install Docker (The following command will also install the needed dependencies):

sudo apt install -y docker-ce

To ensure Docker starts when the system boots:

sudo systemctl enable --now docker

Once installed and enabled, verify that Docker is running:

sudo docker ps

If docker is running you should see the following after running docker ps

CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

With nothing showing under these headers.

🔒 Security Step: Prevent Unauthorized Docker Access

By default, Docker runs as root, which is a security risk. A safer approach is to create a dedicated user group:

sudo groupadd docker
sudo usermod -aG docker $USER
newgrp docker

After running these commands, you can run Docker without sudo:

docker run hello-world

4. Configure Docker for Better Security

A default Docker installation exposes certain risks. Let’s harden it.

Enable AppArmor

Ubuntu ships with AppArmor, a security module that restricts what Docker containers can access.

Check if it’s enabled:

sudo aa-status

If not, enable it with:

sudo systemctl enable --now apparmor

Disable Containers from Getting Root Privileges

By default, containers can run with elevated privileges. Restrict this with user namespaces:

TL;DR Cut & Paste These Commands:

sudo mkdir -p /etc/systemd/system/docker.service.d

echo -e "[Service]\nExecStart=\nExecStart=/usr/bin/dockerd --userns-remap=default" | sudo tee /etc/systemd/system/docker.service.d/override.conf

sudo systemctl daemon-reload

sudo systemctl restart docker

Breakdown of These Commands:

Create a Configuration Directory for Docker

sudo mkdir -p /etc/systemd/system/docker.service.d
  • sudo → Runs the command as root (required for modifying system settings).
  • mkdir -p → Creates a directory if it doesn’t already exist (-p ensures no error if the directory exists).
  • /etc/systemd/system/docker.service.d → This is where custom systemd overrides for Docker are stored.

Why?
This ensures we have a place to store a custom configuration for the Docker service without modifying the main Docker service file.


Create an Override File to Enable User Namespace Remapping

echo -e "[Service]\nExecStart=\nExecStart=/usr/bin/dockerd --userns-remap=default" | sudo tee /etc/systemd/system/docker.service.d/override.conf
  • echo -e "[Service]\nExecStart=\nExecStart=/usr/bin/dockerd --userns-remap=default"
    • Creates a custom systemd service override for Docker.
    • ExecStart= (empty) clears the previous ExecStart setting from the default Docker service.
    • ExecStart=/usr/bin/dockerd --userns-remap=default replaces it with a new one that enables user namespace remapping.
  • | sudo tee /etc/systemd/system/docker.service.d/override.conf
    • Pipes the output (|) to tee, which writes it into the override file at /etc/systemd/system/docker.service.d/override.conf.
    • sudo ensures root access for writing the file.

Why?

  • User namespace remapping (--userns-remap=default) makes Docker containers run as an unprivileged user instead of root.
  • This mitigates risks if a container is compromised—it won’t have full root access on the host.

Reload systemd to Apply the Changes

sudo systemctl daemon-reload
  • sudo → Runs as root.
  • systemctl daemon-reload → Reloads systemd so it recognizes the new Docker service override.

Why?
Without this, systemd won’t detect the new override.conf file.


Restart Docker to Apply the New Configuration

sudo systemctl restart docker
  • sudo → Runs as root.
  • systemctl restart docker → Restarts Docker so it runs with the new --userns-remap=default setting.

Why?

  • This applies the security changes without rebooting the system.
  • From now on, Docker containers will run as an unprivileged user instead of root.

Wrapping Up

Docker is a powerful tool for running apps on your Ubuntu 24.04 server, but an insecure setup can put your system at risk. By following this guide, you now have Docker installed correctly—with some security mitigations in place.

Want to take security even further? Consider ufw and/or fail2ban for added protection.

This sets us up for deploying Sonarr and Radarr services in the next posts.