DiyMediaServer
Featured image of post Master the Basics - How to Install Docker in Linux

Master the Basics - How to Install Docker in Linux

Securely Install Docker on Ubuntu 24.04: A Step-by-Step Guide with Security In Mind

What Is Docker and Why Should You Use It?

Docker is a containerization platform that lets you run applications inside isolated environments called containers. Each container packages an app with all its dependencies, so it stays lightweight, portable, and easy to manage.

Why Use Docker?

Simpler deployments. Instead of installing software directly on your server and fighting dependency conflicts, Docker bundles everything into a self-contained unit. It runs the same way on every system.

Lighter on resources. Docker containers share the host OS kernel, so they’re far cheaper on memory and CPU than a stack of full virtual machines. You can comfortably run dozens of containers on a single box.

Easier software management. Want Jellyfin, Sonarr, Radarr, or Home Assistant? You pull an image, run a container, and you’re done. No hand-compiling, no dependency hell.

Isolation by default. Containers don’t see each other. If one crashes or gets compromised, the rest of the system keeps running.

Updates and rollbacks are cheap. Pulling a newer image is one command. Rolling back to a known-good tag is one more.

Now that you know why Docker is worth running on your home server, let’s install it correctly with security in mind.

Intel NUC 12 Pro (NUC12WSHi5): Compact mini PC for lightweight servers, GPU Passthrough, Docker stacks, and VMs.

Intel NUC 12 Pro (NUC12WSHi5) Compact mini PC for lightweight servers, GPU Passthrough, Docker stacks, and VMs.

Contains affiliate links. I may earn a commission at no cost to you.

1. Update Your System and Install Dependencies

Before installing Docker, update your system and pull in the prerequisites. This gives you a clean, stable base.

Run the following:

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

These commands:

  • Refresh the package list (apt update)
  • Upgrade installed packages (apt upgrade -y)
  • Install the dependencies you’ll need (if curl and gnupg aren’t already on the box)

2. Add Docker’s Official GPG Key and Repository

Ubuntu ships a Docker package in its default repositories, but you shouldn’t use it. Here’s why:

  • Outdated versions. Ubuntu’s repo lags behind Docker’s latest stable releases, so you miss features and security fixes.
  • Slower updates. Critical bug fixes and security patches land in Docker’s official repo first. Ubuntu’s version gets them later, if at all.
  • Missing features. The Ubuntu package can lack support for newer Docker functionality.

So, install from Docker’s official repository. Run the following commands.

Cheat Sheet - 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 is a command that can copy files, set permissions, and create directories.
  • -m 0755 sets the directory permissions to 0755 (read and execute for everyone, write for the owner).
  • -d tells install to create a directory if it doesn’t already exist.
  • /etc/apt/keyrings is where the directory is created. This is where trusted GPG keys for package signing live.

Security Purpose:

  • Ensures only the owner (root) can modify the keyring directory.
  • Prevents unauthorized users from tampering with the 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. It’s better security hygiene.
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 is a tool for downloading files from the internet.
  • -f fails silently if the URL is wrong, so you don’t end up saving an error page.
  • -s runs in silent mode (hides progress output).
  • -S shows errors when they occur, which makes troubleshooting easier.
  • -L follows redirects in case the URL points somewhere else.
  • https://download.docker.com/linux/ubuntu/gpg is the URL of 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 the output of curl into 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.
    • That file is later used to verify Docker packages are signed and authentic before installing.

3. > /dev/null

  • > redirects output somewhere else.
  • /dev/null is the Linux “trash” file that throws away anything written to it.
sudo chmod a+r /etc/apt/keyrings/docker.asc

Breaking It Down:

  • sudo runs the command with superuser (root) privileges.
  • chmod changes file permissions.
  • a stands for “all users” (owner, group, and others).
  • +r adds read permission so the file can be read by everyone.
  • /etc/apt/keyrings/docker.asc is the GPG key file used to verify Docker packages when installing or updating via apt.

What this does:

Lets the system use the key. When apt installs or updates Docker, it checks package signatures against this GPG key. Without read access, apt will fail to verify Docker’s authenticity and throw errors at you.

Prevents unauthorized modifications. The file is still protected (only root can modify it), but every user can now read it. System processes and normal users can verify packages, but they can’t tamper with the key.

Follows Ubuntu’s newer security guidelines. Older versions stored GPG keys in /etc/apt/trusted.gpg, which gave every key full system-wide trust. That’s loose. Newer Ubuntu releases put each key under /etc/apt/keyrings/, where it’s isolated and trusted only for its own 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 prints the text inside the quotes.
  • "deb [...] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" 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.) so you install the right build.
    • signed-by=/etc/apt/keyrings/docker.asc uses Docker’s GPG key (the one you downloaded a minute ago) to verify package authenticity.
  • https://download.docker.com/linux/ubuntu is the URL of Docker’s official repository.
  • $(lsb_release -cs) inserts your Ubuntu codename (e.g., noble for 24.04) so you get the right release.
  • stable pulls the stable Docker channel instead of edge or testing builds.

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

  • | pipes the echo output into tee, which writes it to a file.
  • sudo runs the command 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

  • Throws away the output from tee so your terminal stays clean.

Update your apt repositories:

sudo apt update

3. Install Docker

Now install Docker. The following command also pulls in the dependencies:

sudo apt install -y docker-ce

Make sure Docker starts at boot:

sudo systemctl enable --now docker

Once installed and enabled, verify Docker is running:

sudo docker ps

If Docker is running, you should see this after running docker ps:

CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

With nothing showing under those headers.

Security Step: Prevent Unauthorized Docker Access

By default, Docker runs as root. That’s a problem. Anyone in the docker group gets effective root on the host, so add a dedicated group and put your user in it deliberately:

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 stock Docker install carries real risk. Let’s harden it.

Enable AppArmor

Ubuntu ships with AppArmor, a security module that restricts what Docker containers can do on the host.

Check whether it’s enabled:

sudo aa-status

If it isn’t, turn it on:

sudo systemctl enable --now apparmor

Stop Containers from Getting Root Privileges

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

Cheat Sheet - 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 keeps it from erroring out if the directory’s already there).
  • /etc/systemd/system/docker.service.d is where custom systemd overrides for Docker live.

Why? This gives you a place to drop a custom configuration for the Docker service without editing the main 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":
    • Builds a custom systemd service override for Docker.
    • ExecStart= (empty) clears the previous ExecStart from the default Docker service.
    • ExecStart=/usr/bin/dockerd --userns-remap=default replaces it with one that enables user namespace remapping.
  • | sudo tee /etc/systemd/system/docker.service.d/override.conf:
    • Pipes the output (|) into tee, which writes it into the override file at /etc/systemd/system/docker.service.d/override.conf.
    • sudo gives tee the root access it needs.

Why?

  • User namespace remapping (--userns-remap=default) makes Docker containers run as an unprivileged user on the host instead of root.
  • If a container is compromised, it doesn’t get full root on the host.

Reload systemd to apply the changes:

sudo systemctl daemon-reload
  • sudo runs as root.
  • systemctl daemon-reload reloads systemd so it picks up the new Docker service override.

Why? Without it, systemd never notices 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?

  • Applies the security change without rebooting.
  • From now on, Docker containers run as an unprivileged user instead of root.

Wrapping Up

Docker is a powerful tool for running apps on your Ubuntu 24.04 server. An insecure setup will bite you. Follow this guide and you’ve got Docker installed correctly, with sensible security mitigations in place.

Want to push security further? Look at ufw for the firewall layer and fail2ban for blocking brute-force attempts on exposed services.

Next up: deploying Sonarr and Radarr on top of this Docker install.

ASRock Intel ARC A380 Challenger: The Arc A380 isn't for gamingβ€”it’s for obliterating video streams. With support for H.264, HEVC, and full AV1 hardware enco…

ASRock Intel ARC A380 Challenger The Arc A380 isn’t for gamingβ€”it’s for obliterating video streams. With support for H.264, HEVC, and full AV1 hardware encode/decode, it crushes 20+ 1080p streams or 6–8 HDR tone-mapped 4Ks without breaking a sweat. Drop it in your media server, give Jellyfin direct VA-API access, and watch your CPU finally cool off for a bit.

Contains affiliate links. I may earn a commission at no cost to you.

Was this useful?

Last updated on May 20, 2026 06:56 MDT